@cc-monitoring/proxy-core 0.1.4 → 0.1.5

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 (318) hide show
  1. package/README.md +11 -35
  2. package/dist/cli/commands/doc.d.ts +4 -0
  3. package/dist/cli/commands/doc.js +31 -0
  4. package/dist/cli/index.js +7 -0
  5. package/dist/config/index.js +2 -1
  6. package/dist/config/schema.d.ts +48 -0
  7. package/dist/config/schema.js +11 -1
  8. package/dist/parsers/docx-loader.d.ts +5 -0
  9. package/dist/parsers/docx-loader.js +15 -0
  10. package/dist/parsers/index.d.ts +3 -0
  11. package/dist/parsers/index.js +10 -0
  12. package/dist/parsers/md-loader.d.ts +5 -0
  13. package/dist/parsers/md-loader.js +13 -0
  14. package/dist/parsers/registry.d.ts +8 -0
  15. package/dist/parsers/registry.js +32 -0
  16. package/dist/parsers/types.d.ts +4 -0
  17. package/dist/parsers/types.js +1 -0
  18. package/dist/parsers/xlsx-loader.d.ts +5 -0
  19. package/dist/parsers/xlsx-loader.js +34 -0
  20. package/dist/server/__tests__/providers-route.test.js +4 -3
  21. package/dist/server/__tests__/proxy.test.js +11 -1
  22. package/dist/server/chat-route.d.ts +3 -0
  23. package/dist/server/chat-route.js +401 -0
  24. package/dist/server/claude-settings-route.d.ts +2 -0
  25. package/dist/server/claude-settings-route.js +76 -0
  26. package/dist/server/data-push.d.ts +3 -1
  27. package/dist/server/data-push.js +10 -3
  28. package/dist/server/docs-route.d.ts +2 -0
  29. package/dist/server/docs-route.js +63 -0
  30. package/dist/server/index.js +4 -0
  31. package/dist/server/mcp-route.d.ts +2 -0
  32. package/dist/server/mcp-route.js +161 -0
  33. package/dist/server/proxy.d.ts +4 -1
  34. package/dist/server/proxy.js +289 -128
  35. package/dist/server/ui-route.js +123 -46
  36. package/dist/tools/mcp-bridge.d.ts +13 -0
  37. package/dist/tools/mcp-bridge.js +36 -0
  38. package/dist/tools/registry.js +10 -4
  39. package/dist/ui/assets/{1c-CgVqmGt6.js → 1c-KmWe8RWs.js} +1 -1
  40. package/dist/ui/assets/{abnf-JPM4b6fj.js → abnf-BKQ6qIuo.js} +1 -1
  41. package/dist/ui/assets/{abnfDiagram-VRR7QNED-DJkd8PHl.js → abnfDiagram-VRR7QNED-CkRuDPu1.js} +1 -1
  42. package/dist/ui/assets/{accesslog-CLIMhXWi.js → accesslog-DD9H5Ktc.js} +1 -1
  43. package/dist/ui/assets/{actionscript-DqniQGld.js → actionscript-CAjf2Qtd.js} +1 -1
  44. package/dist/ui/assets/{ada-2BFfY7fF.js → ada-BXkXW16O.js} +1 -1
  45. package/dist/ui/assets/{angelscript-C47qRqcs.js → angelscript-BxT7o0Up.js} +1 -1
  46. package/dist/ui/assets/{apache-DP-LC5-h.js → apache-C5z_tmVm.js} +1 -1
  47. package/dist/ui/assets/{applescript-BB0gk3HQ.js → applescript-DdIxl8rr.js} +1 -1
  48. package/dist/ui/assets/{arc-D8wRCC4D.js → arc-hSdFaqKn.js} +1 -1
  49. package/dist/ui/assets/{arcade-1R6g1VPm.js → arcade-D5m0roat.js} +1 -1
  50. package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-CbHhHV9v.js → architectureDiagram-ZJ3FMSHR-DOSHSqzf.js} +1 -1
  51. package/dist/ui/assets/{arduino-B8YryK0R.js → arduino-FDap8kq-.js} +1 -1
  52. package/dist/ui/assets/{armasm-CYdj7mzR.js → armasm-Kzp-Jr1v.js} +1 -1
  53. package/dist/ui/assets/{asciidoc-bZ11zz6i.js → asciidoc-DbGMW3EE.js} +1 -1
  54. package/dist/ui/assets/{aspectj-D5WPU-RQ.js → aspectj-CVYMmBCO.js} +1 -1
  55. package/dist/ui/assets/{autohotkey-70tZvCLL.js → autohotkey-9PmBGTPd.js} +1 -1
  56. package/dist/ui/assets/{autoit-CX2GaaHP.js → autoit-B4F86jgh.js} +1 -1
  57. package/dist/ui/assets/{avrasm-C154El0d.js → avrasm-CSzv2eHX.js} +1 -1
  58. package/dist/ui/assets/{awk-DdXKOeux.js → awk-CjsvYvZE.js} +1 -1
  59. package/dist/ui/assets/{axapta-CwLwkXST.js → axapta-BVgMoNRY.js} +1 -1
  60. package/dist/ui/assets/{bash-Uu61S1nB.js → bash-IeBjW3pt.js} +1 -1
  61. package/dist/ui/assets/{basic-CeiAWoiF.js → basic-BTFJfmV1.js} +1 -1
  62. package/dist/ui/assets/{blockDiagram-677ZJIJ3-DcvhphUd.js → blockDiagram-677ZJIJ3-DLw3Bbhf.js} +1 -1
  63. package/dist/ui/assets/{bnf-B5KF61QW.js → bnf-rCkeRYk0.js} +1 -1
  64. package/dist/ui/assets/{brainfuck-CP0Y7_VW.js → brainfuck-DBHuB3uZ.js} +1 -1
  65. package/dist/ui/assets/{coq-D-WTlq_d.js → c-C95V0zHL.js} +1 -1
  66. package/dist/ui/assets/{c-like-DXr53gS6.js → c-like-CK1xGeX_.js} +1 -1
  67. package/dist/ui/assets/{c4Diagram-LMCZKHZV-Cn017lmJ.js → c4Diagram-LMCZKHZV-cqY51yJw.js} +1 -1
  68. package/dist/ui/assets/{cal-7ld1j-Wh.js → cal-BxGPpEZK.js} +1 -1
  69. package/dist/ui/assets/{capnproto-DrddNBCZ.js → capnproto-Bo2fgXF9.js} +1 -1
  70. package/dist/ui/assets/{ceylon-XPuE6IIL.js → ceylon-C4Bb4pNB.js} +1 -1
  71. package/dist/ui/assets/channel-D9Y4iN1l.js +1 -0
  72. package/dist/ui/assets/{chunk-2Q5K7J3B-BoX3IESS.js → chunk-2Q5K7J3B-CGTiTBmo.js} +1 -1
  73. package/dist/ui/assets/{chunk-32BRIVSS-C300ACzq.js → chunk-32BRIVSS-DWagYBp9.js} +1 -1
  74. package/dist/ui/assets/{chunk-5VM5RSS4-MtSkFsde.js → chunk-5VM5RSS4-BzSBMKJX.js} +1 -1
  75. package/dist/ui/assets/{chunk-EX3LRPZG-CEeHrGNV.js → chunk-EX3LRPZG-4-aKwCgZ.js} +1 -1
  76. package/dist/ui/assets/{chunk-JWPE2WC7-DTRgpK0R.js → chunk-JWPE2WC7-CPC_cBN0.js} +1 -1
  77. package/dist/ui/assets/{chunk-MOJQB5TN-DiOl0HJx.js → chunk-MOJQB5TN-DrDE4H9w.js} +1 -1
  78. package/dist/ui/assets/{chunk-RYQCIY6F-CVC3opqY.js → chunk-RYQCIY6F-DkdXe_kU.js} +1 -1
  79. package/dist/ui/assets/{chunk-V7JOEXUC-yQYlqQCC.js → chunk-V7JOEXUC-Da6EWcQt.js} +1 -1
  80. package/dist/ui/assets/{chunk-VR4S4FIN-iAA8ZgkK.js → chunk-VR4S4FIN-nP6dstD5.js} +1 -1
  81. package/dist/ui/assets/{chunk-XXDRQBXY-B303eieF.js → chunk-XXDRQBXY-Bi_rRAPA.js} +1 -1
  82. package/dist/ui/assets/classDiagram-OUVF2IWQ-C4UVH6RI.js +1 -0
  83. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-C4UVH6RI.js +1 -0
  84. package/dist/ui/assets/{clean-MfHaW_uS.js → clean-cc1m9AxK.js} +1 -1
  85. package/dist/ui/assets/{clojure-9L8TfiWA.js → clojure-DX5V8QA8.js} +1 -1
  86. package/dist/ui/assets/{clojure-repl-CjsH9sxr.js → clojure-repl-FzjnVNWQ.js} +1 -1
  87. package/dist/ui/assets/{cmake-D0D1Q30G.js → cmake-COZZyrKs.js} +1 -1
  88. package/dist/ui/assets/{coffeescript-BI4jWZnB.js → coffeescript-DBsnOmC4.js} +1 -1
  89. package/dist/ui/assets/{c-BgqCrSpv.js → coq-TwFFolHa.js} +1 -1
  90. package/dist/ui/assets/{cos-DHax5LIJ.js → cos-Dm5g-IQT.js} +1 -1
  91. package/dist/ui/assets/{cose-bilkent-JH36ORCC-BzrKmTAZ.js → cose-bilkent-JH36ORCC-B3-weOQF.js} +1 -1
  92. package/dist/ui/assets/{cpp-M4aMPUas.js → cpp-_RZxQjg7.js} +1 -1
  93. package/dist/ui/assets/{crmsh-DAAczfR0.js → crmsh-DGPJ11Gt.js} +1 -1
  94. package/dist/ui/assets/{crystal-7g2CpWm4.js → crystal-BOMSPGge.js} +1 -1
  95. package/dist/ui/assets/{csharp-DW5GdKKf.js → csharp-DZXiHH72.js} +1 -1
  96. package/dist/ui/assets/{csp-Bq74fG7-.js → csp-DDSIMUoU.js} +1 -1
  97. package/dist/ui/assets/{css-DHyeLXff.js → css-Bjye-ZWr.js} +1 -1
  98. package/dist/ui/assets/{cynefin-VYW2F7L2-DwV1t9iV.js → cynefin-VYW2F7L2-Cj5c4L3y.js} +1 -1
  99. package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-kBCFRYPz.js → cynefinDiagram-TSTJHNR4-BYsfTeNX.js} +1 -1
  100. package/dist/ui/assets/{d-yey2lm3v.js → d-22pfurOx.js} +1 -1
  101. package/dist/ui/assets/{dagre-VKFMJZFB-CErVJ1s0.js → dagre-VKFMJZFB-DiEob-by.js} +1 -1
  102. package/dist/ui/assets/{dart-BadDxflP.js → dart-Doiu8cDW.js} +1 -1
  103. package/dist/ui/assets/{delphi-CqzVqtDp.js → delphi-CQ7epp84.js} +1 -1
  104. package/dist/ui/assets/{diagram-FQU43EPY-C7zAW2DU.js → diagram-FQU43EPY-BOPbQcL4.js} +1 -1
  105. package/dist/ui/assets/{diagram-G47NLZAW-CbUb6BZI.js → diagram-G47NLZAW-C1UWDJTx.js} +1 -1
  106. package/dist/ui/assets/{diagram-NH7WQ7WH-C5mgi3dn.js → diagram-NH7WQ7WH-CYsBqW3J.js} +1 -1
  107. package/dist/ui/assets/{diagram-OA4YK3LP-Cok2YNfS.js → diagram-OA4YK3LP-Dnag0x_3.js} +1 -1
  108. package/dist/ui/assets/{diagram-WEI45ONY-BODuP2EB.js → diagram-WEI45ONY-Bo4CsDoj.js} +1 -1
  109. package/dist/ui/assets/{diff-EVigJ-h2.js → diff-Cs6VQQZt.js} +1 -1
  110. package/dist/ui/assets/{django-BH2EEal6.js → django-Bo3okOrw.js} +1 -1
  111. package/dist/ui/assets/{dns-BSc8VTm8.js → dns-BpG60eIX.js} +1 -1
  112. package/dist/ui/assets/{dockerfile-Br_pZjru.js → dockerfile-BWyH8SlV.js} +1 -1
  113. package/dist/ui/assets/{dos-Bx3ludet.js → dos-DWlNbaB9.js} +1 -1
  114. package/dist/ui/assets/{dsconfig-DSI-ePne.js → dsconfig-D_8y8YrJ.js} +1 -1
  115. package/dist/ui/assets/{dts-ClCuE1Xq.js → dts-Cz4SyMYR.js} +1 -1
  116. package/dist/ui/assets/{dust-CC9Z8iuW.js → dust-Cu4qLkeH.js} +1 -1
  117. package/dist/ui/assets/{ebnf-DI0w_fbi.js → ebnf-CTVHui3r.js} +1 -1
  118. package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-CgsnO8Qm.js → ebnfDiagram-CCIWWBDH-epcXQLEj.js} +1 -1
  119. package/dist/ui/assets/{elixir-hdzZik8p.js → elixir-MAlwXhfU.js} +1 -1
  120. package/dist/ui/assets/{elm-DJAgqt5I.js → elm-Bdmwbvef.js} +1 -1
  121. package/dist/ui/assets/{erDiagram-Q63AITRT-K4zJcEKd.js → erDiagram-Q63AITRT-Bb60TqAM.js} +1 -1
  122. package/dist/ui/assets/{erb-Cq4OQqkl.js → erb-Ce9TpP4g.js} +1 -1
  123. package/dist/ui/assets/{erlang-CHoXLODu.js → erlang-CN2GEiqk.js} +1 -1
  124. package/dist/ui/assets/{erlang-repl-Brp70Zip.js → erlang-repl-D8K4O_cp.js} +1 -1
  125. package/dist/ui/assets/{excel-DjS-QR9P.js → excel-eVZU1r0f.js} +1 -1
  126. package/dist/ui/assets/{fix-BsO9Oq6H.js → fix-BzKerEv0.js} +1 -1
  127. package/dist/ui/assets/{flix-2A7CKozm.js → flix-B9CE3skV.js} +1 -1
  128. package/dist/ui/assets/{flowDiagram-23GEKE2U-Ck4tfxWX.js → flowDiagram-23GEKE2U-DzMLZIyt.js} +1 -1
  129. package/dist/ui/assets/{fortran-BQu3wORI.js → fortran-B4__3vos.js} +1 -1
  130. package/dist/ui/assets/{fsharp-D439S6PZ.js → fsharp-BJ3-ARHz.js} +1 -1
  131. package/dist/ui/assets/{gams-CPRxKfRH.js → gams-Cu43oSYT.js} +1 -1
  132. package/dist/ui/assets/{ganttDiagram-NO4QXBWP-QTPyXXxa.js → ganttDiagram-NO4QXBWP-D_aAoMRP.js} +1 -1
  133. package/dist/ui/assets/{gauss-GJFW9Vod.js → gauss-T8vk_TpE.js} +1 -1
  134. package/dist/ui/assets/{gcode-CF6woDAl.js → gcode-9j3BicpZ.js} +1 -1
  135. package/dist/ui/assets/{gherkin-Co-YjHfW.js → gherkin-Dyh5KFG-.js} +1 -1
  136. package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-Do9VfPHL.js → gitGraphDiagram-IHSO6WYX-CMxCHC-Z.js} +1 -1
  137. package/dist/ui/assets/{glsl-D3lldBTJ.js → glsl-DWWjN4ts.js} +1 -1
  138. package/dist/ui/assets/{gml-DyoCibnw.js → gml-BcYE-D5A.js} +1 -1
  139. package/dist/ui/assets/{go-BNeAS1jC.js → go-DUnUzOEI.js} +1 -1
  140. package/dist/ui/assets/{golo-BuXecWAH.js → golo-BDoc1QQL.js} +1 -1
  141. package/dist/ui/assets/{gradle-BP7ToLe9.js → gradle-B_WRa_bT.js} +1 -1
  142. package/dist/ui/assets/{groovy-GqWVT09g.js → groovy-CgjqFq1e.js} +1 -1
  143. package/dist/ui/assets/{haml-SLbvCHsC.js → haml-DCqcg7Ti.js} +1 -1
  144. package/dist/ui/assets/{handlebars-BnaCJTc5.js → handlebars-DSDUQrnw.js} +1 -1
  145. package/dist/ui/assets/{haskell-CrX9ftWp.js → haskell-DPVnctVi.js} +1 -1
  146. package/dist/ui/assets/{haxe-DNoaIxsE.js → haxe-BuCGXBa4.js} +1 -1
  147. package/dist/ui/assets/{hsp-CLjy3djj.js → hsp-BTKpS_u0.js} +1 -1
  148. package/dist/ui/assets/{htmlbars-w96Kz5NL.js → htmlbars-Cql3Jvy2.js} +1 -1
  149. package/dist/ui/assets/{http-VIMXIxM8.js → http-BB8I9jUh.js} +1 -1
  150. package/dist/ui/assets/{hy-_qE83_aW.js → hy-DG7xkZNz.js} +1 -1
  151. package/dist/ui/assets/index-CK_lJsTu.css +10 -0
  152. package/dist/ui/assets/index-CfTIGTiY.js +2677 -0
  153. package/dist/ui/assets/{index-DpcPfZl3.js → index-DqIiCkSD.js} +3 -3
  154. package/dist/ui/assets/{infoDiagram-FWYZ7A6U-D9O7SZ2X.js → infoDiagram-FWYZ7A6U-DIzEV-BJ.js} +1 -1
  155. package/dist/ui/assets/{inform7-CnyW73C1.js → inform7-BWNpVEkA.js} +1 -1
  156. package/dist/ui/assets/{ini-GFMFAjln.js → ini-BMw_C8EP.js} +1 -1
  157. package/dist/ui/assets/{irpf90-BPmSYATn.js → irpf90-Cy42ibFZ.js} +1 -1
  158. package/dist/ui/assets/{isbl-BnStGiBQ.js → isbl-CjFSc0hz.js} +1 -1
  159. package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-DgcUDM9X.js → ishikawaDiagram-FXEZZL3T-BZcxp5am.js} +1 -1
  160. package/dist/ui/assets/{java-CVORcFd8.js → java-BDxe9dp1.js} +1 -1
  161. package/dist/ui/assets/{javascript-B2pFzODm.js → javascript-CgLkkj7h.js} +1 -1
  162. package/dist/ui/assets/{jboss-cli-B9cQeKvZ.js → jboss-cli-C8biclrb.js} +1 -1
  163. package/dist/ui/assets/{journeyDiagram-5HDEW3XC-Bivjw4h7.js → journeyDiagram-5HDEW3XC-BbJu6m6Q.js} +1 -1
  164. package/dist/ui/assets/{json-BJof8L10.js → json-BjJKhmM6.js} +1 -1
  165. package/dist/ui/assets/{julia-D_dGrCpZ.js → julia-DvKEpg-R.js} +1 -1
  166. package/dist/ui/assets/{julia-repl-Dsw0K1B1.js → julia-repl-BDJWZxkU.js} +1 -1
  167. package/dist/ui/assets/{kanban-definition-HUTT4EX6-Dg7NbKta.js → kanban-definition-HUTT4EX6-DeIVPlbv.js} +1 -1
  168. package/dist/ui/assets/{kotlin-8oetHRtX.js → kotlin-DCoXcnEb.js} +1 -1
  169. package/dist/ui/assets/{lasso-e37r_NX1.js → lasso-C7m0QmV2.js} +1 -1
  170. package/dist/ui/assets/{latex-DAmwzl3n.js → latex-SHnTG9Eq.js} +1 -1
  171. package/dist/ui/assets/{ldif-CD0mgmt4.js → ldif-_6hUnKPV.js} +1 -1
  172. package/dist/ui/assets/{leaf-GfPKlp7a.js → leaf-Co9qxlaF.js} +1 -1
  173. package/dist/ui/assets/{less-PndaZJ6n.js → less-CJRDPwNA.js} +1 -1
  174. package/dist/ui/assets/{lisp-CNaspu3A.js → lisp-JEHGYbiW.js} +1 -1
  175. package/dist/ui/assets/{livecodeserver-DEKsXiP3.js → livecodeserver-BSYaUj4k.js} +1 -1
  176. package/dist/ui/assets/{livescript-DM7jasJn.js → livescript-WQMCQeuz.js} +1 -1
  177. package/dist/ui/assets/{llvm-D_29j9MV.js → llvm-DnAHqj5I.js} +1 -1
  178. package/dist/ui/assets/{lsl-DY0WRYhg.js → lsl--k-ghYia.js} +1 -1
  179. package/dist/ui/assets/{lua-DZ_v4xaE.js → lua-CXb23hbC.js} +1 -1
  180. package/dist/ui/assets/{makefile-VOjcUGXf.js → makefile-CM7o86yn.js} +1 -1
  181. package/dist/ui/assets/{markdown-yUEmZWvu.js → markdown-HB3HvChQ.js} +1 -1
  182. package/dist/ui/assets/{mathematica-BLXYGKkd.js → mathematica-9NTuf22N.js} +1 -1
  183. package/dist/ui/assets/{matlab-B7SkIpvh.js → matlab-CWv-ik4r.js} +1 -1
  184. package/dist/ui/assets/{maxima-C7Fw8Vyt.js → maxima-CqYiKCrw.js} +1 -1
  185. package/dist/ui/assets/{mel-C_Znst2Y.js → mel-BbsRpUm5.js} +1 -1
  186. package/dist/ui/assets/{mercury-DjUnQNsq.js → mercury-Cz2j4HhU.js} +1 -1
  187. package/dist/ui/assets/{mindmap-definition-LN4V7U3C-Dp6mEy6L.js → mindmap-definition-LN4V7U3C-WyJS8oye.js} +1 -1
  188. package/dist/ui/assets/{mipsasm-DaGHhR8c.js → mipsasm-BqWSRbQV.js} +1 -1
  189. package/dist/ui/assets/{mizar-CZnct-_Z.js → mizar-JLBfQ6vt.js} +1 -1
  190. package/dist/ui/assets/{mojolicious-BdWFK35j.js → mojolicious-D0LbMmyk.js} +1 -1
  191. package/dist/ui/assets/{monkey-ta_jgafo.js → monkey-DAGL6-JN.js} +1 -1
  192. package/dist/ui/assets/{moonscript-B9qovjV6.js → moonscript-DzbwNSKy.js} +1 -1
  193. package/dist/ui/assets/{n1ql-BciXbxiw.js → n1ql-dkgKq6Yv.js} +1 -1
  194. package/dist/ui/assets/{nginx-DRCZYbxj.js → nginx-AUoaDPV4.js} +1 -1
  195. package/dist/ui/assets/{nim-DTMCxPJt.js → nim-CdqYmVrl.js} +1 -1
  196. package/dist/ui/assets/{nix-D39yZxF9.js → nix-CxmVjwwo.js} +1 -1
  197. package/dist/ui/assets/{node-repl-vAEXdnYM.js → node-repl-B1Z3zUAh.js} +1 -1
  198. package/dist/ui/assets/{nsis-CCMP8mq3.js → nsis-CTAuPWhe.js} +1 -1
  199. package/dist/ui/assets/{objectivec-CZx4kSLP.js → objectivec-CvbKeAPz.js} +1 -1
  200. package/dist/ui/assets/{ocaml-DBnEo9uR.js → ocaml-DCiyXKOH.js} +1 -1
  201. package/dist/ui/assets/{openscad-BKc7u4Bl.js → openscad-CPGUwmeR.js} +1 -1
  202. package/dist/ui/assets/{oxygene-M_Z4lQ6l.js → oxygene-CI_bD1Gw.js} +1 -1
  203. package/dist/ui/assets/{parser3-DS9UKiKD.js → parser3-C91CVs85.js} +1 -1
  204. package/dist/ui/assets/{pegDiagram-2B236MQR-BBEXn76M.js → pegDiagram-2B236MQR-yF8AW7GR.js} +1 -1
  205. package/dist/ui/assets/{perl-D6iEALGE.js → perl-ChxfKl-n.js} +1 -1
  206. package/dist/ui/assets/{pf-JQL0ClGi.js → pf-CKCHkzIA.js} +1 -1
  207. package/dist/ui/assets/{pgsql-DEmCURBr.js → pgsql-BwOP20uH.js} +1 -1
  208. package/dist/ui/assets/{php-DVm-0PY5.js → php-B7Rs2tM5.js} +1 -1
  209. package/dist/ui/assets/{php-template-DfWbDpnE.js → php-template-Cx-Fh4AR.js} +1 -1
  210. package/dist/ui/assets/{pieDiagram-ENE6RG2P-D5PZFiDj.js → pieDiagram-ENE6RG2P-BS4hnGNX.js} +1 -1
  211. package/dist/ui/assets/{plaintext-BahVkGlu.js → plaintext-U7qkdtgS.js} +1 -1
  212. package/dist/ui/assets/{pony-wVig0caC.js → pony-_fGYgePh.js} +1 -1
  213. package/dist/ui/assets/{powershell-COjMBUit.js → powershell-CFBTcUce.js} +1 -1
  214. package/dist/ui/assets/{processing-DnUzvFZx.js → processing-BWHneU0K.js} +1 -1
  215. package/dist/ui/assets/{profile-mDlbwJeL.js → profile-BJ-HxhzS.js} +1 -1
  216. package/dist/ui/assets/{prolog-x2hG6DnA.js → prolog-ChHo7n6L.js} +1 -1
  217. package/dist/ui/assets/{properties-DzZyyivC.js → properties-e_DOYclC.js} +1 -1
  218. package/dist/ui/assets/{protobuf-a5NwbYD5.js → protobuf-5aGSIv7w.js} +1 -1
  219. package/dist/ui/assets/{puppet-CCWyPVuC.js → puppet-D2vQatzX.js} +1 -1
  220. package/dist/ui/assets/{purebasic-CXNdqtD4.js → purebasic-n6krfaeF.js} +1 -1
  221. package/dist/ui/assets/{python-iSR9YlDJ.js → python-CbIo0XxP.js} +1 -1
  222. package/dist/ui/assets/{python-repl-CCmKzWru.js → python-repl-BpIq9kyr.js} +1 -1
  223. package/dist/ui/assets/{q-B30ZmDuD.js → q-jntnvcCx.js} +1 -1
  224. package/dist/ui/assets/{qml-BGdPdB4X.js → qml-BafQlZNV.js} +1 -1
  225. package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-BBF1rAvI.js → quadrantDiagram-ABIIQ3AL-C3Th8mUJ.js} +1 -1
  226. package/dist/ui/assets/{r-B8ASdWL1.js → r-CHgvQFLK.js} +1 -1
  227. package/dist/ui/assets/{railroadDiagram-RFXS5EU6-DQFUXGVD.js → railroadDiagram-RFXS5EU6-CMQkbGJl.js} +1 -1
  228. package/dist/ui/assets/{reasonml-Dw4Bi5B5.js → reasonml-DNwlPD_T.js} +1 -1
  229. package/dist/ui/assets/{requirementDiagram-TGXJPOKE-DCgrs7-P.js → requirementDiagram-TGXJPOKE-B70_oR7v.js} +1 -1
  230. package/dist/ui/assets/{rib-CgUGGGZ9.js → rib-CX4e9JSF.js} +1 -1
  231. package/dist/ui/assets/{roboconf-CCZNQvSP.js → roboconf-ee4qsPGf.js} +1 -1
  232. package/dist/ui/assets/{routeros-DVT5M6iV.js → routeros-BJSwvu2L.js} +1 -1
  233. package/dist/ui/assets/{rsl-BY-LhdKq.js → rsl-BiKdMl_F.js} +1 -1
  234. package/dist/ui/assets/{ruby-CZW4dclw.js → ruby-CAXTU5LY.js} +1 -1
  235. package/dist/ui/assets/{ruleslanguage-CZdjv1of.js → ruleslanguage-C1kgDGXM.js} +1 -1
  236. package/dist/ui/assets/{rust-D5Xa_mSD.js → rust-DyEf_GXL.js} +1 -1
  237. package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-BXeEgUB7.js → sankeyDiagram-HTMAVEWB-CvUfseMg.js} +1 -1
  238. package/dist/ui/assets/{sas-B_UJ-HCZ.js → sas-Q1rlUxPH.js} +1 -1
  239. package/dist/ui/assets/{scala-B8wSdZik.js → scala-Dg6KNmge.js} +1 -1
  240. package/dist/ui/assets/{scheme-DD7U81eh.js → scheme-D9iooUxI.js} +1 -1
  241. package/dist/ui/assets/{scilab-aJGpbkKs.js → scilab-CztEJXJY.js} +1 -1
  242. package/dist/ui/assets/{scss-BBqyvWYh.js → scss-BMh-JkdE.js} +1 -1
  243. package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-CnDTZN18.js → sequenceDiagram-DBY2YBRQ-DB0c9kf4.js} +1 -1
  244. package/dist/ui/assets/{shell-CR23jqfz.js → shell-DWo6z0MG.js} +1 -1
  245. package/dist/ui/assets/{sizeCapture-X5ZJPWSS-joZ477RB.js → sizeCapture-X5ZJPWSS-BcQlgjfD.js} +1 -1
  246. package/dist/ui/assets/{smali-ZmLyRCrQ.js → smali-Cijeb6pL.js} +1 -1
  247. package/dist/ui/assets/{smalltalk-CnADYfPr.js → smalltalk-D0lvqa_d.js} +1 -1
  248. package/dist/ui/assets/{sml-zj1KD04_.js → sml-B-vqWZ3b.js} +1 -1
  249. package/dist/ui/assets/{sqf-DCCaZ3e3.js → sqf-BJ-1Q583.js} +1 -1
  250. package/dist/ui/assets/{sql-CHGw2SCR.js → sql-CMGLxEYV.js} +1 -1
  251. package/dist/ui/assets/{sql_more-DsnvjMwh.js → sql_more-gsRmbNCH.js} +1 -1
  252. package/dist/ui/assets/{stan-ChxdV8f9.js → stan-D1AlTSpf.js} +1 -1
  253. package/dist/ui/assets/{stata-CgFw45qg.js → stata-DnEYviI0.js} +1 -1
  254. package/dist/ui/assets/{stateDiagram-2N3HPSRC-CzLIdKbt.js → stateDiagram-2N3HPSRC-BSRgVsHO.js} +1 -1
  255. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BLdfpGJO.js +1 -0
  256. package/dist/ui/assets/{step21-DaraQMOk.js → step21-DbQV9sMo.js} +1 -1
  257. package/dist/ui/assets/{stylus-BZpiJEzN.js → stylus-Cyc7vdUc.js} +1 -1
  258. package/dist/ui/assets/{subunit-B6Gp0n7h.js → subunit-16ipyMie.js} +1 -1
  259. package/dist/ui/assets/{swift-DQzoz60p.js → swift-DTNnw4qS.js} +1 -1
  260. package/dist/ui/assets/{swimlanes-5IMT3BWC-DOMOhwX0.js → swimlanes-5IMT3BWC-DgOdcc4_.js} +2 -2
  261. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DRVnkg3M.js +8 -0
  262. package/dist/ui/assets/{taggerscript-BMLkfiab.js → taggerscript-DM6pvUWE.js} +1 -1
  263. package/dist/ui/assets/{tap-PUNWTFgu.js → tap-Ch-uyKZq.js} +1 -1
  264. package/dist/ui/assets/{tcl-BODH5qJa.js → tcl-D0T_V5dA.js} +1 -1
  265. package/dist/ui/assets/{thrift-BQ-W_YlC.js → thrift-D9xJjYw4.js} +1 -1
  266. package/dist/ui/assets/{timeline-definition-FHXFAJF6-DQBDeTzH.js → timeline-definition-FHXFAJF6-BBeDMHxb.js} +1 -1
  267. package/dist/ui/assets/{tp-Dt3WwOGF.js → tp-kUrCGo9X.js} +1 -1
  268. package/dist/ui/assets/{twig-44RQtw7Z.js → twig-Cgub6rxA.js} +1 -1
  269. package/dist/ui/assets/{typescript-BsouHXHR.js → typescript-BxNP9Ap9.js} +1 -1
  270. package/dist/ui/assets/{vala-DqJj6fPT.js → vala-DF9ZZagU.js} +1 -1
  271. package/dist/ui/assets/{vbnet-CuqWYg5r.js → vbnet-Cf46ypDg.js} +1 -1
  272. package/dist/ui/assets/{vbscript-w20MQMYP.js → vbscript-DNs-QKLH.js} +1 -1
  273. package/dist/ui/assets/{vbscript-html-BP0D0WEV.js → vbscript-html-DyS6I5L1.js} +1 -1
  274. package/dist/ui/assets/{vennDiagram-L72KCM5P-DwNnj3Kc.js → vennDiagram-L72KCM5P-8WpWycE-.js} +1 -1
  275. package/dist/ui/assets/{verilog-DIpBpJAe.js → verilog-CF5wC4X-.js} +1 -1
  276. package/dist/ui/assets/{vhdl-D5nCxDbL.js → vhdl-Dm0jpDMn.js} +1 -1
  277. package/dist/ui/assets/{vim-CPfbBM_x.js → vim-nyO2DRAx.js} +1 -1
  278. package/dist/ui/assets/{wardleyDiagram-EHGQE667-WxVQHmM7.js → wardleyDiagram-EHGQE667-UeIOK-jv.js} +1 -1
  279. package/dist/ui/assets/{x86asm-D_t4Z_eq.js → x86asm-BNw2-6GG.js} +1 -1
  280. package/dist/ui/assets/{xl-DQf5IG_W.js → xl-D-YHxr6V.js} +1 -1
  281. package/dist/ui/assets/{xml-D-Bn0NMR.js → xml-BijAlrow.js} +1 -1
  282. package/dist/ui/assets/{xquery-DqushYX1.js → xquery-z0wxWBKz.js} +1 -1
  283. package/dist/ui/assets/{xychartDiagram-FW5EYKEG-B6D8mgs8.js → xychartDiagram-FW5EYKEG-BNzHLweN.js} +1 -1
  284. package/dist/ui/assets/{yaml-B2GFZenc.js → yaml-n5TIQArR.js} +1 -1
  285. package/dist/ui/assets/{zephir-SiNGockR.js → zephir-DrGhH8jG.js} +1 -1
  286. package/dist/ui/index.html +2 -2
  287. package/dist/utils/__tests__/providers-db.test.js +2 -1
  288. package/dist/utils/__tests__/tool-injector.test.js +32 -35
  289. package/dist/utils/db.d.ts +3 -0
  290. package/dist/utils/db.js +54 -0
  291. package/dist/utils/inject-loop.d.ts +52 -1
  292. package/dist/utils/inject-loop.js +70 -2
  293. package/dist/utils/mcp-db.d.ts +35 -0
  294. package/dist/utils/mcp-db.js +79 -0
  295. package/dist/utils/mcp-manager.d.ts +36 -0
  296. package/dist/utils/mcp-manager.js +215 -0
  297. package/dist/utils/openai-converter.d.ts +99 -0
  298. package/dist/utils/openai-converter.js +293 -0
  299. package/dist/utils/providers-db.d.ts +2 -0
  300. package/dist/utils/providers-db.js +19 -7
  301. package/dist/utils/request-writer.d.ts +20 -0
  302. package/dist/utils/request-writer.js +184 -4
  303. package/dist/utils/sse-stream-processor.d.ts +27 -0
  304. package/dist/utils/sse-stream-processor.js +144 -0
  305. package/dist/utils/stats-aggregator.js +2 -0
  306. package/dist/utils/status-history.js +3 -3
  307. package/dist/utils/tool-injector.d.ts +6 -9
  308. package/dist/utils/tool-injector.js +13 -14
  309. package/dist/utils/version.d.ts +6 -0
  310. package/dist/utils/version.js +11 -1
  311. package/package.json +14 -12
  312. package/dist/ui/assets/channel-C5JlZ38H.js +0 -1
  313. package/dist/ui/assets/classDiagram-OUVF2IWQ-j5FVBKaD.js +0 -1
  314. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-j5FVBKaD.js +0 -1
  315. package/dist/ui/assets/index-Baqd6LlK.js +0 -2625
  316. package/dist/ui/assets/index-fHtNI_e8.css +0 -1
  317. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-Bg4GAkB5.js +0 -1
  318. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-99wEK8yq.js +0 -8
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ export declare function setupClaudeSettingsRoutes(fastify: FastifyInstance, config: any): Promise<void>;
@@ -0,0 +1,76 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { isClaudeInstalled } from '../utils/version.js';
5
+ function getClaudeSettingsPath() {
6
+ return path.join(os.homedir(), '.claude', 'settings.json');
7
+ }
8
+ function buildServerAddress(config) {
9
+ const host = config.server.host === '0.0.0.0' ? 'localhost' : config.server.host;
10
+ return `http://${host}:${config.server.port}`;
11
+ }
12
+ export async function setupClaudeSettingsRoutes(fastify, config) {
13
+ fastify.post('/ui/api/claude-settings/sync', async (request, reply) => {
14
+ // 1. 检测 Claude Code 是否安装
15
+ if (!isClaudeInstalled()) {
16
+ return reply.send({
17
+ success: false,
18
+ message: '未检测到 Claude Code,请安装完以后重试'
19
+ });
20
+ }
21
+ // 2. 检测 settings.json 是否存在
22
+ const settingsPath = getClaudeSettingsPath();
23
+ if (!fs.existsSync(settingsPath)) {
24
+ return reply.send({
25
+ success: false,
26
+ message: '未检测到配置文件,请手动修改'
27
+ });
28
+ }
29
+ // 3. 读取 settings.json
30
+ let settings;
31
+ try {
32
+ const raw = fs.readFileSync(settingsPath, 'utf-8');
33
+ settings = JSON.parse(raw);
34
+ }
35
+ catch {
36
+ return reply.code(500).send({
37
+ success: false,
38
+ message: '配置文件格式错误,请手动检查'
39
+ });
40
+ }
41
+ // 4. 构建当前 ccm 服务地址
42
+ const serverAddress = buildServerAddress(config);
43
+ const currentBaseUrl = settings?.env?.ANTHROPIC_BASE_URL;
44
+ // 5. 比较
45
+ if (currentBaseUrl === serverAddress) {
46
+ return reply.send({
47
+ success: true,
48
+ message: '已使用 CCM 的配置,无需改动',
49
+ alreadyMatched: true
50
+ });
51
+ }
52
+ // 6. 备份旧值 + 设置新值
53
+ if (!settings.env) {
54
+ settings.env = {};
55
+ }
56
+ if (currentBaseUrl) {
57
+ settings.env.ANTHROPIC_BASE_URL_CCM_BACKUP = currentBaseUrl;
58
+ }
59
+ settings.env.ANTHROPIC_BASE_URL = serverAddress;
60
+ // 7. 写回 settings.json
61
+ try {
62
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
63
+ }
64
+ catch (err) {
65
+ return reply.code(500).send({
66
+ success: false,
67
+ message: `写入配置文件失败: ${err.message}`
68
+ });
69
+ }
70
+ return reply.send({
71
+ success: true,
72
+ message: '修改成功,请重启 Claude 终端生效',
73
+ alreadyMatched: false
74
+ });
75
+ });
76
+ }
@@ -1,5 +1,7 @@
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 getDataClientCount(): number;
5
+ export declare function pushNewRequest(summary: any, status?: 'pending' | 'completed'): void;
5
6
  export declare function pushStatsNotify(): void;
7
+ export declare function broadcastToDataClients(msg: any): void;
@@ -7,12 +7,15 @@ export function addDataClient(ws) {
7
7
  export function removeDataClient(ws) {
8
8
  dataClients.delete(ws);
9
9
  }
10
+ export function getDataClientCount() {
11
+ return dataClients.size;
12
+ }
10
13
  // Broadcast helpers
11
- export function pushNewRequest(summary) {
14
+ export function pushNewRequest(summary, status = 'completed') {
12
15
  broadcast({
13
16
  type: 'request',
14
- action: 'new',
15
- data: summary
17
+ action: status === 'pending' ? 'new' : 'update',
18
+ data: { ...summary, status }
16
19
  });
17
20
  }
18
21
  export function pushStatsNotify() {
@@ -30,3 +33,7 @@ function broadcast(msg) {
30
33
  }
31
34
  }
32
35
  }
36
+ // Expose broadcast for global status timer (ui-route.ts)
37
+ export function broadcastToDataClients(msg) {
38
+ broadcast(msg);
39
+ }
@@ -0,0 +1,2 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ export declare function setupDocsRoutes(fastify: FastifyInstance): Promise<void>;
@@ -0,0 +1,63 @@
1
+ import multipart from '@fastify/multipart';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { registry } from '../parsers/index.js';
5
+ import { dataDir } from '../utils/paths.js';
6
+ const docsDir = path.join(dataDir, 'docs');
7
+ export async function setupDocsRoutes(fastify) {
8
+ await fastify.register(multipart, { limits: { fileSize: 10 * 1024 * 1024 } });
9
+ fastify.post('/ui/api/docs/upload', async (request, reply) => {
10
+ const data = await request.file();
11
+ if (!data) {
12
+ return reply.code(400).send({ success: false, error: 'No file uploaded' });
13
+ }
14
+ const filename = path.basename(data.filename);
15
+ const buffer = await data.toBuffer();
16
+ // 校验扩展名
17
+ const supported = registry.getSupportedExtensions();
18
+ const dotIndex = filename.lastIndexOf('.');
19
+ if (dotIndex === -1) {
20
+ return reply.code(400).send({
21
+ success: false,
22
+ error: `File has no extension. Supported types: ${supported.join(', ')}`
23
+ });
24
+ }
25
+ const ext = filename.slice(dotIndex).toLowerCase();
26
+ if (!supported.includes(ext)) {
27
+ return reply.code(400).send({
28
+ success: false,
29
+ error: `Unsupported file type: "${ext}". Supported types: ${supported.join(', ')}`
30
+ });
31
+ }
32
+ // 解析文件内容为 md
33
+ let mdContent;
34
+ try {
35
+ mdContent = await registry.parse(buffer, filename);
36
+ }
37
+ catch (err) {
38
+ request.log.error({ err, filename }, 'File parsing failed');
39
+ return reply.code(500).send({
40
+ success: false,
41
+ error: err.message || 'File parsing failed'
42
+ });
43
+ }
44
+ // 确保 docs 目录存在
45
+ if (!fs.existsSync(docsDir)) {
46
+ fs.mkdirSync(docsDir, { recursive: true });
47
+ }
48
+ // 写入 md 文件
49
+ const mdFilename = filename.slice(0, dotIndex) + '.md';
50
+ const mdPath = path.join(docsDir, mdFilename);
51
+ try {
52
+ fs.writeFileSync(mdPath, mdContent, 'utf-8');
53
+ }
54
+ catch (err) {
55
+ request.log.error({ err, mdPath }, 'Failed to write md file');
56
+ return reply.code(500).send({
57
+ success: false,
58
+ error: 'Failed to save file'
59
+ });
60
+ }
61
+ return { success: true, path: `docs/${mdFilename}` };
62
+ });
63
+ }
@@ -5,6 +5,8 @@ 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';
9
+ import { setupDocsRoutes } from './docs-route.js';
8
10
  import { requestIdMiddleware } from './middleware/request-id.js';
9
11
  export async function createServer() {
10
12
  const config = await loadConfig();
@@ -19,6 +21,8 @@ export async function createServer() {
19
21
  fastify.register(requestIdMiddleware);
20
22
  await setupUiRoutes(fastify); // UI routes registered BEFORE proxy to avoid being proxied
21
23
  await setupProxy(fastify, config.proxy);
24
+ await setupChatRoute(fastify, config.proxy); // MCP-enhanced chat endpoint
25
+ await setupDocsRoutes(fastify);
22
26
  return fastify;
23
27
  }
24
28
  export async function startServer() {
@@ -0,0 +1,2 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ export declare function setupMcpRoutes(fastify: FastifyInstance, config: any): Promise<void>;