@cc-monitoring/proxy-core 0.1.5 → 0.1.7

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 (445) hide show
  1. package/dist/docs/404.html +22 -0
  2. package/dist/docs/assets/app.BxFOH0P1.js +1 -0
  3. package/dist/docs/assets/chunks/@localSearchIndexroot.Cuu7C9vz.js +1 -0
  4. package/dist/docs/assets/chunks/VPLocalSearchBox.CYDhNgXW.js +9 -0
  5. package/dist/docs/assets/chunks/abnfDiagram-VRR7QNED.RG1C5NpS.js +1 -0
  6. package/dist/docs/assets/chunks/arc.C9NMazfV.js +1 -0
  7. package/dist/docs/assets/chunks/architectureDiagram-ZJ3FMSHR.u2IZtOa6.js +36 -0
  8. package/dist/docs/assets/chunks/blockDiagram-677ZJIJ3.DdHVir7t.js +132 -0
  9. package/dist/docs/assets/chunks/c4Diagram-LMCZKHZV.gSbgoaJo.js +10 -0
  10. package/dist/docs/assets/chunks/channel.Cc6zpfFP.js +1 -0
  11. package/dist/docs/assets/chunks/chunk-2Q5K7J3B.HRSdtksv.js +1 -0
  12. package/dist/docs/assets/chunks/chunk-32BRIVSS.BYzKapof.js +1 -0
  13. package/dist/docs/assets/chunks/chunk-5VM5RSS4.c3oeF0uS.js +15 -0
  14. package/dist/docs/assets/chunks/chunk-EX3LRPZG.Cz5AKl7t.js +231 -0
  15. package/dist/docs/assets/chunks/chunk-JWPE2WC7.DtJxsA7-.js +1 -0
  16. package/dist/docs/assets/chunks/chunk-MOJQB5TN.h5kO0Dtu.js +88 -0
  17. package/dist/docs/assets/chunks/chunk-RYQCIY6F.Ch_NfMTR.js +1 -0
  18. package/dist/docs/assets/chunks/chunk-V7JOEXUC.CHrHyPoW.js +206 -0
  19. package/dist/docs/assets/chunks/chunk-VR4S4FIN.DG8DIrH3.js +1 -0
  20. package/dist/docs/assets/chunks/chunk-XXDRQBXY.CSXBN12Y.js +1 -0
  21. package/dist/docs/assets/chunks/classDiagram-OUVF2IWQ.DV5B4KLJ.js +1 -0
  22. package/dist/docs/assets/chunks/classDiagram-v2-EOCWNBFH.DV5B4KLJ.js +1 -0
  23. package/dist/docs/assets/chunks/cose-bilkent-JH36ORCC.BeFuOTgi.js +1 -0
  24. package/dist/docs/assets/chunks/cynefin-VYW2F7L2.DaXIfh7Y.js +178 -0
  25. package/dist/docs/assets/chunks/cynefinDiagram-TSTJHNR4.BrJcHEEe.js +62 -0
  26. package/dist/docs/assets/chunks/cytoscape.esm.CUqq0XTU.js +331 -0
  27. package/dist/docs/assets/chunks/dagre-VKFMJZFB.D4vaA23X.js +4 -0
  28. package/dist/docs/assets/chunks/defaultLocale.DX6XiGOO.js +1 -0
  29. package/dist/docs/assets/chunks/diagram-FQU43EPY.uwRFLKRx.js +3 -0
  30. package/dist/docs/assets/chunks/diagram-G47NLZAW.Byfc9d0H.js +24 -0
  31. package/dist/docs/assets/chunks/diagram-NH7WQ7WH.CxjBEGZX.js +24 -0
  32. package/dist/docs/assets/chunks/diagram-OA4YK3LP.CU1jGXMi.js +30 -0
  33. package/dist/docs/assets/chunks/diagram-WEI45ONY.yXgVkURA.js +41 -0
  34. package/dist/docs/assets/chunks/ebnfDiagram-CCIWWBDH.UucqGQ_d.js +1 -0
  35. package/dist/docs/assets/chunks/erDiagram-Q63AITRT.C6qmOrvh.js +85 -0
  36. package/dist/docs/assets/chunks/flowDiagram-23GEKE2U.BZLu-WUl.js +156 -0
  37. package/dist/docs/assets/chunks/framework.D_Xv2a7c.js +19 -0
  38. package/dist/docs/assets/chunks/ganttDiagram-NO4QXBWP.DUzsw4Yr.js +292 -0
  39. package/dist/docs/assets/chunks/gitGraphDiagram-IHSO6WYX.BqLfYTI7.js +106 -0
  40. package/dist/docs/assets/chunks/graph.C2PyVmSI.js +1 -0
  41. package/dist/docs/assets/chunks/infoDiagram-FWYZ7A6U.CiKWveW9.js +2 -0
  42. package/dist/docs/assets/chunks/init.Gi6I4Gst.js +1 -0
  43. package/dist/docs/assets/chunks/ishikawaDiagram-FXEZZL3T.jerUXEXA.js +70 -0
  44. package/dist/docs/assets/chunks/journeyDiagram-5HDEW3XC.Cqzvo6I_.js +139 -0
  45. package/dist/docs/assets/chunks/kanban-definition-HUTT4EX6.BzJ4OPe5.js +89 -0
  46. package/dist/docs/assets/chunks/katex.C5jXJg4s.js +257 -0
  47. package/dist/docs/assets/chunks/layout.BG3qr61M.js +1 -0
  48. package/dist/docs/assets/chunks/linear.hFjgYGMN.js +1 -0
  49. package/dist/docs/assets/chunks/map.DwDi8XlU.js +1 -0
  50. package/dist/docs/assets/chunks/mermaid-client.D3gEaJ5e.js +2 -0
  51. package/dist/docs/assets/chunks/mermaid.core.CEHdFh45.js +314 -0
  52. package/dist/docs/assets/chunks/mindmap-definition-LN4V7U3C.ChC5FJW6.js +96 -0
  53. package/dist/docs/assets/chunks/ordinal.BYWQX77i.js +1 -0
  54. package/dist/docs/assets/chunks/pegDiagram-2B236MQR.ClnjsRYs.js +1 -0
  55. package/dist/docs/assets/chunks/pieDiagram-ENE6RG2P.Bb0MqerK.js +39 -0
  56. package/dist/docs/assets/chunks/quadrantDiagram-ABIIQ3AL.Do6HK_yb.js +7 -0
  57. package/dist/docs/assets/chunks/railroadDiagram-RFXS5EU6.D35m6hQn.js +1 -0
  58. package/dist/docs/assets/chunks/requirementDiagram-TGXJPOKE.DMtjRYUg.js +84 -0
  59. package/dist/docs/assets/chunks/sankeyDiagram-HTMAVEWB.dfXDu62B.js +40 -0
  60. package/dist/docs/assets/chunks/sequenceDiagram-DBY2YBRQ.CLZ0rZTY.js +162 -0
  61. package/dist/docs/assets/chunks/sizeCapture-X5ZJPWSS.DWvGYLUT.js +1 -0
  62. package/dist/docs/assets/chunks/stateDiagram-2N3HPSRC.DY8sDkI0.js +1 -0
  63. package/dist/docs/assets/chunks/stateDiagram-v2-6OUMAXLB.B9v-Vq5L.js +1 -0
  64. package/dist/docs/assets/chunks/swimlanes-5IMT3BWC.Dy9SffeT.js +2 -0
  65. package/dist/docs/assets/chunks/swimlanesDiagram-G3AALYLV.Kb9LnCTH.js +8 -0
  66. package/dist/docs/assets/chunks/theme.BLEczZWC.js +2 -0
  67. package/dist/docs/assets/chunks/timeline-definition-FHXFAJF6.CH6uzgIu.js +120 -0
  68. package/dist/docs/assets/chunks/vennDiagram-L72KCM5P.7EBCJmyP.js +34 -0
  69. package/dist/docs/assets/chunks/wardleyDiagram-EHGQE667.DPHAQssL.js +78 -0
  70. package/dist/docs/assets/chunks/xychartDiagram-FW5EYKEG.aKgxZVbK.js +7 -0
  71. package/dist/docs/assets/index.md.p9floL_p.js +1 -0
  72. package/dist/docs/assets/index.md.p9floL_p.lean.js +1 -0
  73. package/dist/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  74. package/dist/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  75. package/dist/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  76. package/dist/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  77. package/dist/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  78. package/dist/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  79. package/dist/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  80. package/dist/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  81. package/dist/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  82. package/dist/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  83. package/dist/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  84. package/dist/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  85. package/dist/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  86. package/dist/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  87. package/dist/docs/assets/overview.md.BKVdLT3o.js +70 -0
  88. package/dist/docs/assets/overview.md.BKVdLT3o.lean.js +1 -0
  89. package/dist/docs/assets/packages-utils.md.CvgYp5Ll.js +31 -0
  90. package/dist/docs/assets/packages-utils.md.CvgYp5Ll.lean.js +1 -0
  91. package/dist/docs/assets/proxy-admin_env-and-build.md.xkeQNYS3.js +40 -0
  92. package/dist/docs/assets/proxy-admin_env-and-build.md.xkeQNYS3.lean.js +1 -0
  93. package/dist/docs/assets/proxy-admin_index.md.DBLI0n0G.js +38 -0
  94. package/dist/docs/assets/proxy-admin_index.md.DBLI0n0G.lean.js +1 -0
  95. package/dist/docs/assets/proxy-admin_layout-and-menu.md.BKGcu49p.js +48 -0
  96. package/dist/docs/assets/proxy-admin_layout-and-menu.md.BKGcu49p.lean.js +1 -0
  97. package/dist/docs/assets/proxy-admin_pages.md.m_fGvvOH.js +51 -0
  98. package/dist/docs/assets/proxy-admin_pages.md.m_fGvvOH.lean.js +1 -0
  99. package/dist/docs/assets/proxy-admin_routing-and-auth.md.DZsdFese.js +106 -0
  100. package/dist/docs/assets/proxy-admin_routing-and-auth.md.DZsdFese.lean.js +1 -0
  101. package/dist/docs/assets/proxy-admin_services-and-mock.md.sdNPcf25.js +66 -0
  102. package/dist/docs/assets/proxy-admin_services-and-mock.md.sdNPcf25.lean.js +1 -0
  103. package/dist/docs/assets/proxy-cli_api-layer.md.GfdbtEUx.js +1 -0
  104. package/dist/docs/assets/proxy-cli_api-layer.md.GfdbtEUx.lean.js +1 -0
  105. package/dist/docs/assets/proxy-cli_app-shell.md.Do18CYhW.js +83 -0
  106. package/dist/docs/assets/proxy-cli_app-shell.md.Do18CYhW.lean.js +1 -0
  107. package/dist/docs/assets/proxy-cli_components-common.md.Dd6Yazvz.js +23 -0
  108. package/dist/docs/assets/proxy-cli_components-common.md.Dd6Yazvz.lean.js +1 -0
  109. package/dist/docs/assets/proxy-cli_components-config.md.B81Y3ta2.js +46 -0
  110. package/dist/docs/assets/proxy-cli_components-config.md.B81Y3ta2.lean.js +1 -0
  111. package/dist/docs/assets/proxy-cli_components-requests.md.vN8IrwL_.js +84 -0
  112. package/dist/docs/assets/proxy-cli_components-requests.md.vN8IrwL_.lean.js +1 -0
  113. package/dist/docs/assets/proxy-cli_components-stats.md.B90esaNa.js +14 -0
  114. package/dist/docs/assets/proxy-cli_components-stats.md.B90esaNa.lean.js +1 -0
  115. package/dist/docs/assets/proxy-cli_components-status.md.C5lAzS2c.js +42 -0
  116. package/dist/docs/assets/proxy-cli_components-status.md.C5lAzS2c.lean.js +1 -0
  117. package/dist/docs/assets/proxy-cli_data-hooks.md.w9Oe1OD3.js +87 -0
  118. package/dist/docs/assets/proxy-cli_data-hooks.md.w9Oe1OD3.lean.js +1 -0
  119. package/dist/docs/assets/proxy-cli_index.md.BA6g8QD-.js +34 -0
  120. package/dist/docs/assets/proxy-cli_index.md.BA6g8QD-.lean.js +1 -0
  121. package/dist/docs/assets/proxy-cli_utils-and-i18n.md.Ch_e-g_o.js +34 -0
  122. package/dist/docs/assets/proxy-cli_utils-and-i18n.md.Ch_e-g_o.lean.js +1 -0
  123. package/dist/docs/assets/proxy-core_chat-api.md.DHihiBxR.js +152 -0
  124. package/dist/docs/assets/proxy-core_chat-api.md.DHihiBxR.lean.js +1 -0
  125. package/dist/docs/assets/proxy-core_cli.md.DCFYX4Bd.js +37 -0
  126. package/dist/docs/assets/proxy-core_cli.md.DCFYX4Bd.lean.js +1 -0
  127. package/dist/docs/assets/proxy-core_config.md.BXSOyxYE.js +83 -0
  128. package/dist/docs/assets/proxy-core_config.md.BXSOyxYE.lean.js +1 -0
  129. package/dist/docs/assets/proxy-core_data-layer.md.Cdomb3Gz.js +85 -0
  130. package/dist/docs/assets/proxy-core_data-layer.md.Cdomb3Gz.lean.js +1 -0
  131. package/dist/docs/assets/proxy-core_entry.md.BZmIcCUM.js +90 -0
  132. package/dist/docs/assets/proxy-core_entry.md.BZmIcCUM.lean.js +1 -0
  133. package/dist/docs/assets/proxy-core_index.md.BM6VV5Qe.js +55 -0
  134. package/dist/docs/assets/proxy-core_index.md.BM6VV5Qe.lean.js +1 -0
  135. package/dist/docs/assets/proxy-core_pm2.md.DUhWEtgn.js +79 -0
  136. package/dist/docs/assets/proxy-core_pm2.md.DUhWEtgn.lean.js +1 -0
  137. package/dist/docs/assets/proxy-core_providers.md.CbDZ6b_7.js +1 -0
  138. package/dist/docs/assets/proxy-core_providers.md.CbDZ6b_7.lean.js +1 -0
  139. package/dist/docs/assets/proxy-core_proxy.md.CzQYmX6X.js +46 -0
  140. package/dist/docs/assets/proxy-core_proxy.md.CzQYmX6X.lean.js +1 -0
  141. package/dist/docs/assets/proxy-core_stats.md.BsM6wuK_.js +42 -0
  142. package/dist/docs/assets/proxy-core_stats.md.BsM6wuK_.lean.js +1 -0
  143. package/dist/docs/assets/proxy-core_tool.md.B6Le1nQr.js +100 -0
  144. package/dist/docs/assets/proxy-core_tool.md.B6Le1nQr.lean.js +1 -0
  145. package/dist/docs/assets/proxy-core_ui-routes.md.Dyqkeoiv.js +27 -0
  146. package/dist/docs/assets/proxy-core_ui-routes.md.Dyqkeoiv.lean.js +1 -0
  147. package/dist/docs/assets/proxy-core_utilities.md.C18pjnkz.js +63 -0
  148. package/dist/docs/assets/proxy-core_utilities.md.C18pjnkz.lean.js +1 -0
  149. package/dist/docs/assets/quickstart.md.Cy_FmXIY.js +38 -0
  150. package/dist/docs/assets/quickstart.md.Cy_FmXIY.lean.js +1 -0
  151. package/dist/docs/assets/request-flow.md.C1fyxdPE.js +146 -0
  152. package/dist/docs/assets/request-flow.md.C1fyxdPE.lean.js +1 -0
  153. package/dist/docs/assets/style.DU_kNMWy.css +1 -0
  154. package/dist/docs/hashmap.json +1 -0
  155. package/dist/docs/index.html +25 -0
  156. package/dist/docs/overview.html +94 -0
  157. package/dist/docs/packages-utils.html +55 -0
  158. package/dist/docs/proxy-admin/env-and-build.html +64 -0
  159. package/dist/docs/proxy-admin/index.html +62 -0
  160. package/dist/docs/proxy-admin/layout-and-menu.html +72 -0
  161. package/dist/docs/proxy-admin/pages.html +75 -0
  162. package/dist/docs/proxy-admin/routing-and-auth.html +130 -0
  163. package/dist/docs/proxy-admin/services-and-mock.html +90 -0
  164. package/dist/docs/proxy-cli/api-layer.html +38 -0
  165. package/dist/docs/proxy-cli/app-shell.html +107 -0
  166. package/dist/docs/proxy-cli/components-common.html +47 -0
  167. package/dist/docs/proxy-cli/components-config.html +70 -0
  168. package/dist/docs/proxy-cli/components-requests.html +108 -0
  169. package/dist/docs/proxy-cli/components-stats.html +38 -0
  170. package/dist/docs/proxy-cli/components-status.html +66 -0
  171. package/dist/docs/proxy-cli/data-hooks.html +111 -0
  172. package/dist/docs/proxy-cli/index.html +58 -0
  173. package/dist/docs/proxy-cli/utils-and-i18n.html +58 -0
  174. package/dist/docs/proxy-core/chat-api.html +176 -0
  175. package/dist/docs/proxy-core/cli.html +61 -0
  176. package/dist/docs/proxy-core/config.html +107 -0
  177. package/dist/docs/proxy-core/data-layer.html +109 -0
  178. package/dist/docs/proxy-core/entry.html +114 -0
  179. package/dist/docs/proxy-core/index.html +79 -0
  180. package/dist/docs/proxy-core/pm2.html +103 -0
  181. package/dist/docs/proxy-core/providers.html +39 -0
  182. package/dist/docs/proxy-core/proxy.html +70 -0
  183. package/dist/docs/proxy-core/stats.html +66 -0
  184. package/dist/docs/proxy-core/tool.html +124 -0
  185. package/dist/docs/proxy-core/ui-routes.html +51 -0
  186. package/dist/docs/proxy-core/utilities.html +87 -0
  187. package/dist/docs/quickstart.html +62 -0
  188. package/dist/docs/request-flow.html +170 -0
  189. package/dist/docs/vp-icons.css +0 -0
  190. package/dist/server/proxy.js +2 -1
  191. package/dist/ui/assets/{1c-KmWe8RWs.js → 1c-DPsrzNHI.js} +1 -1
  192. package/dist/ui/assets/{abnf-BKQ6qIuo.js → abnf-DNkBIQRO.js} +1 -1
  193. package/dist/ui/assets/{abnfDiagram-VRR7QNED-CkRuDPu1.js → abnfDiagram-VRR7QNED-BqvHvzR8.js} +1 -1
  194. package/dist/ui/assets/{accesslog-DD9H5Ktc.js → accesslog-D5NxQ43Q.js} +1 -1
  195. package/dist/ui/assets/{actionscript-CAjf2Qtd.js → actionscript-DLr-LB2m.js} +1 -1
  196. package/dist/ui/assets/{ada-BXkXW16O.js → ada-BRSz3tHX.js} +1 -1
  197. package/dist/ui/assets/{angelscript-BxT7o0Up.js → angelscript-DMtEGgIa.js} +1 -1
  198. package/dist/ui/assets/{apache-C5z_tmVm.js → apache-C4gn4cSd.js} +1 -1
  199. package/dist/ui/assets/{applescript-DdIxl8rr.js → applescript-DoodcTwg.js} +1 -1
  200. package/dist/ui/assets/{arc-hSdFaqKn.js → arc-HmnzaGf9.js} +1 -1
  201. package/dist/ui/assets/{arcade-D5m0roat.js → arcade-RJZZSHSl.js} +1 -1
  202. package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-DOSHSqzf.js → architectureDiagram-ZJ3FMSHR-BUfDpSIw.js} +1 -1
  203. package/dist/ui/assets/{arduino-FDap8kq-.js → arduino-n6Dpx6Ig.js} +1 -1
  204. package/dist/ui/assets/{armasm-Kzp-Jr1v.js → armasm-DzCVITGB.js} +1 -1
  205. package/dist/ui/assets/{asciidoc-DbGMW3EE.js → asciidoc-CaqMsApq.js} +1 -1
  206. package/dist/ui/assets/{aspectj-CVYMmBCO.js → aspectj-B0kIcV0v.js} +1 -1
  207. package/dist/ui/assets/{autohotkey-9PmBGTPd.js → autohotkey-xUEXewap.js} +1 -1
  208. package/dist/ui/assets/{autoit-B4F86jgh.js → autoit-D3OfN2VX.js} +1 -1
  209. package/dist/ui/assets/{avrasm-CSzv2eHX.js → avrasm-Cbf0F4Kf.js} +1 -1
  210. package/dist/ui/assets/{awk-CjsvYvZE.js → awk-Cc0rWEwe.js} +1 -1
  211. package/dist/ui/assets/{axapta-BVgMoNRY.js → axapta-BKEeoUEe.js} +1 -1
  212. package/dist/ui/assets/{bash-IeBjW3pt.js → bash-D6JH6L3m.js} +1 -1
  213. package/dist/ui/assets/{basic-BTFJfmV1.js → basic-ka6JXc9C.js} +1 -1
  214. package/dist/ui/assets/{blockDiagram-677ZJIJ3-DLw3Bbhf.js → blockDiagram-677ZJIJ3-BHXRSjnM.js} +1 -1
  215. package/dist/ui/assets/{bnf-rCkeRYk0.js → bnf-Bxclk5tZ.js} +1 -1
  216. package/dist/ui/assets/{brainfuck-DBHuB3uZ.js → brainfuck--s_Fd8b9.js} +1 -1
  217. package/dist/ui/assets/{coq-TwFFolHa.js → c-BsgdDna0.js} +1 -1
  218. package/dist/ui/assets/{c-like-CK1xGeX_.js → c-like-CNkOkbqh.js} +1 -1
  219. package/dist/ui/assets/{c4Diagram-LMCZKHZV-cqY51yJw.js → c4Diagram-LMCZKHZV-Bp1uSrW8.js} +1 -1
  220. package/dist/ui/assets/{cal-BxGPpEZK.js → cal-LVlIOy9W.js} +1 -1
  221. package/dist/ui/assets/{capnproto-Bo2fgXF9.js → capnproto-r9DiQ1H8.js} +1 -1
  222. package/dist/ui/assets/{ceylon-C4Bb4pNB.js → ceylon-CTNzyZJX.js} +1 -1
  223. package/dist/ui/assets/channel-_rFUXR2i.js +1 -0
  224. package/dist/ui/assets/{chunk-2Q5K7J3B-CGTiTBmo.js → chunk-2Q5K7J3B-nnLVtUW3.js} +1 -1
  225. package/dist/ui/assets/{chunk-32BRIVSS-DWagYBp9.js → chunk-32BRIVSS-BDNS6igp.js} +1 -1
  226. package/dist/ui/assets/{chunk-5VM5RSS4-BzSBMKJX.js → chunk-5VM5RSS4-D713xBhI.js} +1 -1
  227. package/dist/ui/assets/{chunk-EX3LRPZG-4-aKwCgZ.js → chunk-EX3LRPZG-DExsU6Rd.js} +1 -1
  228. package/dist/ui/assets/{chunk-JWPE2WC7-CPC_cBN0.js → chunk-JWPE2WC7-DcpW5RnW.js} +1 -1
  229. package/dist/ui/assets/{chunk-MOJQB5TN-DrDE4H9w.js → chunk-MOJQB5TN-BQiSZNTn.js} +1 -1
  230. package/dist/ui/assets/{chunk-RYQCIY6F-DkdXe_kU.js → chunk-RYQCIY6F-DfblgZPd.js} +1 -1
  231. package/dist/ui/assets/{chunk-V7JOEXUC-Da6EWcQt.js → chunk-V7JOEXUC-np--VgmN.js} +1 -1
  232. package/dist/ui/assets/{chunk-VR4S4FIN-nP6dstD5.js → chunk-VR4S4FIN-BG0IhjO6.js} +1 -1
  233. package/dist/ui/assets/{chunk-XXDRQBXY-Bi_rRAPA.js → chunk-XXDRQBXY-DHuoh-RB.js} +1 -1
  234. package/dist/ui/assets/classDiagram-OUVF2IWQ-DqgbMzM1.js +1 -0
  235. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-DqgbMzM1.js +1 -0
  236. package/dist/ui/assets/{clean-cc1m9AxK.js → clean-CtVj0-EB.js} +1 -1
  237. package/dist/ui/assets/{clojure-DX5V8QA8.js → clojure-CZwle60-.js} +1 -1
  238. package/dist/ui/assets/{clojure-repl-FzjnVNWQ.js → clojure-repl-DJXWH00I.js} +1 -1
  239. package/dist/ui/assets/{cmake-COZZyrKs.js → cmake-Boxf0e7r.js} +1 -1
  240. package/dist/ui/assets/{coffeescript-DBsnOmC4.js → coffeescript-h85ZW4Gm.js} +1 -1
  241. package/dist/ui/assets/{c-C95V0zHL.js → coq-CVLui3m8.js} +1 -1
  242. package/dist/ui/assets/{cos-Dm5g-IQT.js → cos-CL0igafw.js} +1 -1
  243. package/dist/ui/assets/{cose-bilkent-JH36ORCC-B3-weOQF.js → cose-bilkent-JH36ORCC-CnXyotYB.js} +1 -1
  244. package/dist/ui/assets/{cpp-_RZxQjg7.js → cpp-vite1NvJ.js} +1 -1
  245. package/dist/ui/assets/{crmsh-DGPJ11Gt.js → crmsh-DqT9g0Iq.js} +1 -1
  246. package/dist/ui/assets/{crystal-BOMSPGge.js → crystal-Oans-K8G.js} +1 -1
  247. package/dist/ui/assets/{csharp-DZXiHH72.js → csharp-sCaDAzIB.js} +1 -1
  248. package/dist/ui/assets/{csp-DDSIMUoU.js → csp-rMcp93pK.js} +1 -1
  249. package/dist/ui/assets/{css-Bjye-ZWr.js → css-BwDLHi_h.js} +1 -1
  250. package/dist/ui/assets/{cynefin-VYW2F7L2-Cj5c4L3y.js → cynefin-VYW2F7L2-D8Bmecdd.js} +1 -1
  251. package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-BYsfTeNX.js → cynefinDiagram-TSTJHNR4-BT2YFmPZ.js} +1 -1
  252. package/dist/ui/assets/{d-22pfurOx.js → d-BFgZm0RV.js} +1 -1
  253. package/dist/ui/assets/{dagre-VKFMJZFB-DiEob-by.js → dagre-VKFMJZFB-BeJU73ex.js} +1 -1
  254. package/dist/ui/assets/{dart-Doiu8cDW.js → dart-rIo85iL3.js} +1 -1
  255. package/dist/ui/assets/{delphi-CQ7epp84.js → delphi-Bi2Rfp1o.js} +1 -1
  256. package/dist/ui/assets/{diagram-FQU43EPY-BOPbQcL4.js → diagram-FQU43EPY-CHQiS5Fr.js} +1 -1
  257. package/dist/ui/assets/{diagram-G47NLZAW-C1UWDJTx.js → diagram-G47NLZAW-EVerd4V8.js} +1 -1
  258. package/dist/ui/assets/{diagram-NH7WQ7WH-CYsBqW3J.js → diagram-NH7WQ7WH-DMP0VOAs.js} +1 -1
  259. package/dist/ui/assets/{diagram-OA4YK3LP-Dnag0x_3.js → diagram-OA4YK3LP-CAur5jK9.js} +1 -1
  260. package/dist/ui/assets/{diagram-WEI45ONY-Bo4CsDoj.js → diagram-WEI45ONY-DvmKkPH7.js} +1 -1
  261. package/dist/ui/assets/{diff-Cs6VQQZt.js → diff-CZZCIG00.js} +1 -1
  262. package/dist/ui/assets/{django-Bo3okOrw.js → django-D88PKHy-.js} +1 -1
  263. package/dist/ui/assets/{dns-BpG60eIX.js → dns-DX4hzjUh.js} +1 -1
  264. package/dist/ui/assets/{dockerfile-BWyH8SlV.js → dockerfile-1lgzEXn1.js} +1 -1
  265. package/dist/ui/assets/{dos-DWlNbaB9.js → dos-CwrC1ROy.js} +1 -1
  266. package/dist/ui/assets/{dsconfig-D_8y8YrJ.js → dsconfig-tvVdBv4w.js} +1 -1
  267. package/dist/ui/assets/{dts-Cz4SyMYR.js → dts-DTgQkdRs.js} +1 -1
  268. package/dist/ui/assets/{dust-Cu4qLkeH.js → dust-BbLlyCpf.js} +1 -1
  269. package/dist/ui/assets/{ebnf-CTVHui3r.js → ebnf-D6Dc4oRr.js} +1 -1
  270. package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-epcXQLEj.js → ebnfDiagram-CCIWWBDH-Kvilk1RF.js} +1 -1
  271. package/dist/ui/assets/{elixir-MAlwXhfU.js → elixir-CnMolQVs.js} +1 -1
  272. package/dist/ui/assets/{elm-Bdmwbvef.js → elm-BQ7VQFn7.js} +1 -1
  273. package/dist/ui/assets/{erDiagram-Q63AITRT-Bb60TqAM.js → erDiagram-Q63AITRT-C-S9oHZd.js} +1 -1
  274. package/dist/ui/assets/{erb-Ce9TpP4g.js → erb-B_1g6fXE.js} +1 -1
  275. package/dist/ui/assets/{erlang-CN2GEiqk.js → erlang-3b3ITXJu.js} +1 -1
  276. package/dist/ui/assets/{erlang-repl-D8K4O_cp.js → erlang-repl-Cy6Z3TdH.js} +1 -1
  277. package/dist/ui/assets/{excel-eVZU1r0f.js → excel-DtkATto8.js} +1 -1
  278. package/dist/ui/assets/{fix-BzKerEv0.js → fix-DsEG7TDI.js} +1 -1
  279. package/dist/ui/assets/{flix-B9CE3skV.js → flix-CQ-rKwGO.js} +1 -1
  280. package/dist/ui/assets/{flowDiagram-23GEKE2U-DzMLZIyt.js → flowDiagram-23GEKE2U-EbHDNMCC.js} +1 -1
  281. package/dist/ui/assets/{fortran-B4__3vos.js → fortran-AqzaRCEt.js} +1 -1
  282. package/dist/ui/assets/{fsharp-BJ3-ARHz.js → fsharp-CCzWGasu.js} +1 -1
  283. package/dist/ui/assets/{gams-Cu43oSYT.js → gams-Bqa6CB_r.js} +1 -1
  284. package/dist/ui/assets/{ganttDiagram-NO4QXBWP-D_aAoMRP.js → ganttDiagram-NO4QXBWP-B6jvc6O7.js} +1 -1
  285. package/dist/ui/assets/{gauss-T8vk_TpE.js → gauss-D4Utubeh.js} +1 -1
  286. package/dist/ui/assets/{gcode-9j3BicpZ.js → gcode-By3KwWjb.js} +1 -1
  287. package/dist/ui/assets/{gherkin-Dyh5KFG-.js → gherkin-PXOPjT7Y.js} +1 -1
  288. package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-CMxCHC-Z.js → gitGraphDiagram-IHSO6WYX-C5l6rHvK.js} +1 -1
  289. package/dist/ui/assets/{glsl-DWWjN4ts.js → glsl-KmmyBk93.js} +1 -1
  290. package/dist/ui/assets/{gml-BcYE-D5A.js → gml-C1Qw_Nrt.js} +1 -1
  291. package/dist/ui/assets/{go-DUnUzOEI.js → go-DaBQtdp1.js} +1 -1
  292. package/dist/ui/assets/{golo-BDoc1QQL.js → golo-D7PDzNpb.js} +1 -1
  293. package/dist/ui/assets/{gradle-B_WRa_bT.js → gradle-nXueCYH-.js} +1 -1
  294. package/dist/ui/assets/{groovy-CgjqFq1e.js → groovy-DFDsQDhl.js} +1 -1
  295. package/dist/ui/assets/{haml-DCqcg7Ti.js → haml-B_zxHzy_.js} +1 -1
  296. package/dist/ui/assets/{handlebars-DSDUQrnw.js → handlebars-BdMY-8KA.js} +1 -1
  297. package/dist/ui/assets/{haskell-DPVnctVi.js → haskell-CftsIPps.js} +1 -1
  298. package/dist/ui/assets/{haxe-BuCGXBa4.js → haxe-BFZb0OIE.js} +1 -1
  299. package/dist/ui/assets/{hsp-BTKpS_u0.js → hsp-EPTuqwtZ.js} +1 -1
  300. package/dist/ui/assets/{htmlbars-Cql3Jvy2.js → htmlbars-B7ZSC-iN.js} +1 -1
  301. package/dist/ui/assets/{http-BB8I9jUh.js → http-BxSd_aa1.js} +1 -1
  302. package/dist/ui/assets/{hy-DG7xkZNz.js → hy-D-rBN9MQ.js} +1 -1
  303. package/dist/ui/assets/index-CWFn1h-J.css +10 -0
  304. package/dist/ui/assets/{index-CfTIGTiY.js → index-DSGZBcd1.js} +166 -171
  305. package/dist/ui/assets/{index-DqIiCkSD.js → index-Dlp8uGHu.js} +3 -3
  306. package/dist/ui/assets/{infoDiagram-FWYZ7A6U-DIzEV-BJ.js → infoDiagram-FWYZ7A6U-BOF_kBqe.js} +1 -1
  307. package/dist/ui/assets/{inform7-BWNpVEkA.js → inform7-OjpbRXZf.js} +1 -1
  308. package/dist/ui/assets/{ini-BMw_C8EP.js → ini-Dc-QApXQ.js} +1 -1
  309. package/dist/ui/assets/{irpf90-Cy42ibFZ.js → irpf90-C4OfYiST.js} +1 -1
  310. package/dist/ui/assets/{isbl-CjFSc0hz.js → isbl-9km6K6Sf.js} +1 -1
  311. package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-BZcxp5am.js → ishikawaDiagram-FXEZZL3T-BvKSD8LY.js} +1 -1
  312. package/dist/ui/assets/{java-BDxe9dp1.js → java-C2mOf3QX.js} +1 -1
  313. package/dist/ui/assets/{javascript-CgLkkj7h.js → javascript-_i0Q5MkQ.js} +1 -1
  314. package/dist/ui/assets/{jboss-cli-C8biclrb.js → jboss-cli-BS5ipQOv.js} +1 -1
  315. package/dist/ui/assets/{journeyDiagram-5HDEW3XC-BbJu6m6Q.js → journeyDiagram-5HDEW3XC-yKdSl63P.js} +1 -1
  316. package/dist/ui/assets/{json-BjJKhmM6.js → json-Dci0MO4x.js} +1 -1
  317. package/dist/ui/assets/{julia-DvKEpg-R.js → julia-bEqo4nlV.js} +1 -1
  318. package/dist/ui/assets/{julia-repl-BDJWZxkU.js → julia-repl-Co6hf47q.js} +1 -1
  319. package/dist/ui/assets/{kanban-definition-HUTT4EX6-DeIVPlbv.js → kanban-definition-HUTT4EX6-B7BbZCd6.js} +1 -1
  320. package/dist/ui/assets/{kotlin-DCoXcnEb.js → kotlin-krx8WewB.js} +1 -1
  321. package/dist/ui/assets/{lasso-C7m0QmV2.js → lasso-d3ZTv9Tj.js} +1 -1
  322. package/dist/ui/assets/{latex-SHnTG9Eq.js → latex-BNWbHYxK.js} +1 -1
  323. package/dist/ui/assets/{ldif-_6hUnKPV.js → ldif-Bs8eb63L.js} +1 -1
  324. package/dist/ui/assets/{leaf-Co9qxlaF.js → leaf-BTbRDVWB.js} +1 -1
  325. package/dist/ui/assets/{less-CJRDPwNA.js → less-DH5cqJTD.js} +1 -1
  326. package/dist/ui/assets/{lisp-JEHGYbiW.js → lisp-CBUvBYtR.js} +1 -1
  327. package/dist/ui/assets/{livecodeserver-BSYaUj4k.js → livecodeserver-CkM7-E4a.js} +1 -1
  328. package/dist/ui/assets/{livescript-WQMCQeuz.js → livescript-DomXyXUO.js} +1 -1
  329. package/dist/ui/assets/{llvm-DnAHqj5I.js → llvm-e_-ff59-.js} +1 -1
  330. package/dist/ui/assets/{lsl--k-ghYia.js → lsl-BNDsGOmv.js} +1 -1
  331. package/dist/ui/assets/{lua-CXb23hbC.js → lua-_ZmkXwc_.js} +1 -1
  332. package/dist/ui/assets/{makefile-CM7o86yn.js → makefile-BhG7cThe.js} +1 -1
  333. package/dist/ui/assets/{markdown-HB3HvChQ.js → markdown-ClW2SRy6.js} +1 -1
  334. package/dist/ui/assets/{mathematica-9NTuf22N.js → mathematica-kqoCR611.js} +1 -1
  335. package/dist/ui/assets/{matlab-CWv-ik4r.js → matlab-DqawyK3q.js} +1 -1
  336. package/dist/ui/assets/{maxima-CqYiKCrw.js → maxima-B0qzCXe1.js} +1 -1
  337. package/dist/ui/assets/{mel-BbsRpUm5.js → mel-BZaSas3B.js} +1 -1
  338. package/dist/ui/assets/{mercury-Cz2j4HhU.js → mercury-ByD0wyJH.js} +1 -1
  339. package/dist/ui/assets/{mindmap-definition-LN4V7U3C-WyJS8oye.js → mindmap-definition-LN4V7U3C-Ce6QsaH5.js} +1 -1
  340. package/dist/ui/assets/{mipsasm-BqWSRbQV.js → mipsasm-B08lqZSo.js} +1 -1
  341. package/dist/ui/assets/{mizar-JLBfQ6vt.js → mizar-7iaUqWPq.js} +1 -1
  342. package/dist/ui/assets/{mojolicious-D0LbMmyk.js → mojolicious-CbH-d8Wh.js} +1 -1
  343. package/dist/ui/assets/{monkey-DAGL6-JN.js → monkey-D5z6-hFH.js} +1 -1
  344. package/dist/ui/assets/{moonscript-DzbwNSKy.js → moonscript-DuLd7pdm.js} +1 -1
  345. package/dist/ui/assets/{n1ql-dkgKq6Yv.js → n1ql-EbVfQMfD.js} +1 -1
  346. package/dist/ui/assets/{nginx-AUoaDPV4.js → nginx-D-4AxpHP.js} +1 -1
  347. package/dist/ui/assets/{nim-CdqYmVrl.js → nim-wPHQEX5v.js} +1 -1
  348. package/dist/ui/assets/{nix-CxmVjwwo.js → nix-6SVkxAXi.js} +1 -1
  349. package/dist/ui/assets/{node-repl-B1Z3zUAh.js → node-repl-CaFKEOyj.js} +1 -1
  350. package/dist/ui/assets/{nsis-CTAuPWhe.js → nsis-BmqbwVv_.js} +1 -1
  351. package/dist/ui/assets/{objectivec-CvbKeAPz.js → objectivec-BX0R-sI2.js} +1 -1
  352. package/dist/ui/assets/{ocaml-DCiyXKOH.js → ocaml-CyfdrIqo.js} +1 -1
  353. package/dist/ui/assets/{openscad-CPGUwmeR.js → openscad-B5qfaF1E.js} +1 -1
  354. package/dist/ui/assets/{oxygene-CI_bD1Gw.js → oxygene-CmlCgXLr.js} +1 -1
  355. package/dist/ui/assets/{parser3-C91CVs85.js → parser3-DdpPyZkn.js} +1 -1
  356. package/dist/ui/assets/{pegDiagram-2B236MQR-yF8AW7GR.js → pegDiagram-2B236MQR-ByyVqaXh.js} +1 -1
  357. package/dist/ui/assets/{perl-ChxfKl-n.js → perl-D3qc2wEe.js} +1 -1
  358. package/dist/ui/assets/{pf-CKCHkzIA.js → pf-Bv3zza37.js} +1 -1
  359. package/dist/ui/assets/{pgsql-BwOP20uH.js → pgsql-BZIppw1a.js} +1 -1
  360. package/dist/ui/assets/{php-B7Rs2tM5.js → php-D1ScecZC.js} +1 -1
  361. package/dist/ui/assets/{php-template-Cx-Fh4AR.js → php-template-sEqzzKWJ.js} +1 -1
  362. package/dist/ui/assets/{pieDiagram-ENE6RG2P-BS4hnGNX.js → pieDiagram-ENE6RG2P-T1OgWN3l.js} +1 -1
  363. package/dist/ui/assets/{plaintext-U7qkdtgS.js → plaintext-DO7Jy_T2.js} +1 -1
  364. package/dist/ui/assets/{pony-_fGYgePh.js → pony-CTXTp2Tb.js} +1 -1
  365. package/dist/ui/assets/{powershell-CFBTcUce.js → powershell-C9lzZsbj.js} +1 -1
  366. package/dist/ui/assets/{processing-BWHneU0K.js → processing-hzJAP_Li.js} +1 -1
  367. package/dist/ui/assets/{profile-BJ-HxhzS.js → profile-bFiAkh7e.js} +1 -1
  368. package/dist/ui/assets/{prolog-ChHo7n6L.js → prolog-CE0trHSn.js} +1 -1
  369. package/dist/ui/assets/{properties-e_DOYclC.js → properties-MeANnTVc.js} +1 -1
  370. package/dist/ui/assets/{protobuf-5aGSIv7w.js → protobuf-S-rp7SK0.js} +1 -1
  371. package/dist/ui/assets/{puppet-D2vQatzX.js → puppet-B5YT8Ct1.js} +1 -1
  372. package/dist/ui/assets/{purebasic-n6krfaeF.js → purebasic-DO-5HeDl.js} +1 -1
  373. package/dist/ui/assets/{python-CbIo0XxP.js → python-DVGTQbwU.js} +1 -1
  374. package/dist/ui/assets/{python-repl-BpIq9kyr.js → python-repl-CQ4VlKLC.js} +1 -1
  375. package/dist/ui/assets/{q-jntnvcCx.js → q-nS96imov.js} +1 -1
  376. package/dist/ui/assets/{qml-BafQlZNV.js → qml-BkzkCgUU.js} +1 -1
  377. package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-C3Th8mUJ.js → quadrantDiagram-ABIIQ3AL-BkaCzlXD.js} +1 -1
  378. package/dist/ui/assets/{r-CHgvQFLK.js → r-y4Q5t85r.js} +1 -1
  379. package/dist/ui/assets/{railroadDiagram-RFXS5EU6-CMQkbGJl.js → railroadDiagram-RFXS5EU6-C1lbwk19.js} +1 -1
  380. package/dist/ui/assets/{reasonml-DNwlPD_T.js → reasonml-Bzhzc5Ao.js} +1 -1
  381. package/dist/ui/assets/{requirementDiagram-TGXJPOKE-B70_oR7v.js → requirementDiagram-TGXJPOKE-C8Rw6N2I.js} +1 -1
  382. package/dist/ui/assets/{rib-CX4e9JSF.js → rib-BP3Y9dW3.js} +1 -1
  383. package/dist/ui/assets/{roboconf-ee4qsPGf.js → roboconf-87QE7cIh.js} +1 -1
  384. package/dist/ui/assets/{routeros-BJSwvu2L.js → routeros-BV3nt8wW.js} +1 -1
  385. package/dist/ui/assets/{rsl-BiKdMl_F.js → rsl-DfQf4CW_.js} +1 -1
  386. package/dist/ui/assets/{ruby-CAXTU5LY.js → ruby-DQxFKbgX.js} +1 -1
  387. package/dist/ui/assets/{ruleslanguage-C1kgDGXM.js → ruleslanguage-B8oCm_aw.js} +1 -1
  388. package/dist/ui/assets/{rust-DyEf_GXL.js → rust-DzZgPf9W.js} +1 -1
  389. package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-CvUfseMg.js → sankeyDiagram-HTMAVEWB-Dxiuo8Hz.js} +1 -1
  390. package/dist/ui/assets/{sas-Q1rlUxPH.js → sas-CFh-Rsrv.js} +1 -1
  391. package/dist/ui/assets/{scala-Dg6KNmge.js → scala-3UDyJBiS.js} +1 -1
  392. package/dist/ui/assets/{scheme-D9iooUxI.js → scheme-KaUTge9W.js} +1 -1
  393. package/dist/ui/assets/{scilab-CztEJXJY.js → scilab-CLSBZzuh.js} +1 -1
  394. package/dist/ui/assets/{scss-BMh-JkdE.js → scss-DaEkfHWX.js} +1 -1
  395. package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-DB0c9kf4.js → sequenceDiagram-DBY2YBRQ-Cv__zR2v.js} +1 -1
  396. package/dist/ui/assets/{shell-DWo6z0MG.js → shell-B0d4cZTk.js} +1 -1
  397. package/dist/ui/assets/{sizeCapture-X5ZJPWSS-BcQlgjfD.js → sizeCapture-X5ZJPWSS-C4nD-ShQ.js} +1 -1
  398. package/dist/ui/assets/{smali-Cijeb6pL.js → smali-CLhfky4R.js} +1 -1
  399. package/dist/ui/assets/{smalltalk-D0lvqa_d.js → smalltalk-B4aaTMO5.js} +1 -1
  400. package/dist/ui/assets/{sml-B-vqWZ3b.js → sml-x4CTxWEZ.js} +1 -1
  401. package/dist/ui/assets/{sqf-BJ-1Q583.js → sqf-G_0vdVVs.js} +1 -1
  402. package/dist/ui/assets/{sql-CMGLxEYV.js → sql-C--WH0Fo.js} +1 -1
  403. package/dist/ui/assets/{sql_more-gsRmbNCH.js → sql_more-B4LrzCtd.js} +1 -1
  404. package/dist/ui/assets/{stan-D1AlTSpf.js → stan-CACDFOA0.js} +1 -1
  405. package/dist/ui/assets/{stata-DnEYviI0.js → stata-BP9M7sZt.js} +1 -1
  406. package/dist/ui/assets/{stateDiagram-2N3HPSRC-BSRgVsHO.js → stateDiagram-2N3HPSRC-z3-31Cr2.js} +1 -1
  407. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BKIXFHzO.js +1 -0
  408. package/dist/ui/assets/{step21-DbQV9sMo.js → step21-MAOu4dNb.js} +1 -1
  409. package/dist/ui/assets/{stylus-Cyc7vdUc.js → stylus-CpuP3pvE.js} +1 -1
  410. package/dist/ui/assets/{subunit-16ipyMie.js → subunit-NWzuqFhT.js} +1 -1
  411. package/dist/ui/assets/{swift-DTNnw4qS.js → swift-DuFKNmKv.js} +1 -1
  412. package/dist/ui/assets/{swimlanes-5IMT3BWC-DgOdcc4_.js → swimlanes-5IMT3BWC-E463-rXd.js} +2 -2
  413. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-CkQvBOYs.js +8 -0
  414. package/dist/ui/assets/{taggerscript-DM6pvUWE.js → taggerscript-BDnv2jvg.js} +1 -1
  415. package/dist/ui/assets/{tap-Ch-uyKZq.js → tap-aB2cLXdf.js} +1 -1
  416. package/dist/ui/assets/{tcl-D0T_V5dA.js → tcl-7WepIaIa.js} +1 -1
  417. package/dist/ui/assets/{thrift-D9xJjYw4.js → thrift-BLh6pdjc.js} +1 -1
  418. package/dist/ui/assets/{timeline-definition-FHXFAJF6-BBeDMHxb.js → timeline-definition-FHXFAJF6-FA_RNhFQ.js} +1 -1
  419. package/dist/ui/assets/{tp-kUrCGo9X.js → tp-D1rt5u_j.js} +1 -1
  420. package/dist/ui/assets/{twig-Cgub6rxA.js → twig-DgfeYg4W.js} +1 -1
  421. package/dist/ui/assets/{typescript-BxNP9Ap9.js → typescript-oU560Q8V.js} +1 -1
  422. package/dist/ui/assets/{vala-DF9ZZagU.js → vala-DlXsaz2B.js} +1 -1
  423. package/dist/ui/assets/{vbnet-Cf46ypDg.js → vbnet-BjpxjeMZ.js} +1 -1
  424. package/dist/ui/assets/{vbscript-DNs-QKLH.js → vbscript-DfNdtdO3.js} +1 -1
  425. package/dist/ui/assets/{vbscript-html-DyS6I5L1.js → vbscript-html-D09WPsgK.js} +1 -1
  426. package/dist/ui/assets/{vennDiagram-L72KCM5P-8WpWycE-.js → vennDiagram-L72KCM5P-zaCDWwTs.js} +1 -1
  427. package/dist/ui/assets/{verilog-CF5wC4X-.js → verilog-B9vENtLK.js} +1 -1
  428. package/dist/ui/assets/{vhdl-Dm0jpDMn.js → vhdl-CJLTZOu1.js} +1 -1
  429. package/dist/ui/assets/{vim-nyO2DRAx.js → vim-FuPhupu9.js} +1 -1
  430. package/dist/ui/assets/{wardleyDiagram-EHGQE667-UeIOK-jv.js → wardleyDiagram-EHGQE667-BS8ApwmV.js} +1 -1
  431. package/dist/ui/assets/{x86asm-BNw2-6GG.js → x86asm-kX_Cp6wB.js} +1 -1
  432. package/dist/ui/assets/{xl-D-YHxr6V.js → xl-MuHNmLUj.js} +1 -1
  433. package/dist/ui/assets/{xml-BijAlrow.js → xml-Mbn2z12n.js} +1 -1
  434. package/dist/ui/assets/{xquery-z0wxWBKz.js → xquery-Dy4lt-m-.js} +1 -1
  435. package/dist/ui/assets/{xychartDiagram-FW5EYKEG-BNzHLweN.js → xychartDiagram-FW5EYKEG-DoNZtZus.js} +1 -1
  436. package/dist/ui/assets/{yaml-n5TIQArR.js → yaml-CxxAisfE.js} +1 -1
  437. package/dist/ui/assets/{zephir-DrGhH8jG.js → zephir-WWG8qyld.js} +1 -1
  438. package/dist/ui/index.html +2 -2
  439. package/package.json +2 -2
  440. package/dist/ui/assets/channel-D9Y4iN1l.js +0 -1
  441. package/dist/ui/assets/classDiagram-OUVF2IWQ-C4UVH6RI.js +0 -1
  442. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-C4UVH6RI.js +0 -1
  443. package/dist/ui/assets/index-CK_lJsTu.css +0 -10
  444. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BLdfpGJO.js +0 -1
  445. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DRVnkg3M.js +0 -8
@@ -0,0 +1,176 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN" dir="ltr">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>proxy-core / Chat API (/api/chat) | CC Monitoring</title>
7
+ <meta name="description" content="Claude Code 代理 + 监控系统文档">
8
+ <meta name="generator" content="VitePress v1.6.4">
9
+ <link rel="preload stylesheet" href="/docs/assets/style.DU_kNMWy.css" as="style">
10
+ <link rel="preload stylesheet" href="/docs/vp-icons.css" as="style">
11
+
12
+ <script type="module" src="/docs/assets/app.BxFOH0P1.js"></script>
13
+ <link rel="preload" href="/docs/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
+ <link rel="modulepreload" href="/docs/assets/chunks/theme.BLEczZWC.js">
15
+ <link rel="modulepreload" href="/docs/assets/chunks/framework.D_Xv2a7c.js">
16
+ <link rel="modulepreload" href="/docs/assets/proxy-core_chat-api.md.DHihiBxR.lean.js">
17
+ <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
18
+ <script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
19
+ </head>
20
+ <body>
21
+ <div id="app"><div class="Layout" data-v-0fd5f79a><!--[--><!--]--><!--[--><span tabindex="-1" data-v-13bcab17></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-13bcab17>Skip to content</a><!--]--><!----><header class="VPNav" data-v-0fd5f79a data-v-221ddc7b><div class="VPNavBar" data-v-221ddc7b data-v-6a82b350><div class="wrapper" data-v-6a82b350><div class="container" data-v-6a82b350><div class="title" data-v-6a82b350><div class="VPNavBarTitle has-sidebar" data-v-6a82b350 data-v-98825d79><a class="title" href="/docs/" data-v-98825d79><!--[--><!--]--><!----><span data-v-98825d79>CC Monitoring</span><!--[--><!--]--></a></div></div><div class="content" data-v-6a82b350><div class="content-body" data-v-6a82b350><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6a82b350><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6a82b350 data-v-2fa375b4><span id="main-nav-aria-label" class="visually-hidden" data-v-2fa375b4> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/overview.html" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>概览</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/quickstart.html" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>快速开始</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/proxy-core/" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>Proxy Core</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/proxy-cli/" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>Proxy CLI</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/proxy-admin/" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>Proxy Admin</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6a82b350 data-v-c7859fea><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-c7859fea data-v-458e2939 data-v-2fadb15f><span class="check" data-v-2fadb15f><span class="icon" data-v-2fadb15f><!--[--><span class="vpi-sun sun" data-v-458e2939></span><span class="vpi-moon moon" data-v-458e2939></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6a82b350 data-v-4a332738 data-v-3416cc30><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-3416cc30><span class="vpi-more-horizontal icon" data-v-3416cc30></span></button><div class="menu" data-v-3416cc30><div class="VPMenu" data-v-3416cc30 data-v-70b241a4><!----><!--[--><!--[--><!----><div class="group" data-v-4a332738><div class="item appearance" data-v-4a332738><p class="label" data-v-4a332738>Appearance</p><div class="appearance-action" data-v-4a332738><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-4a332738 data-v-458e2939 data-v-2fadb15f><span class="check" data-v-2fadb15f><span class="icon" data-v-2fadb15f><!--[--><span class="vpi-sun sun" data-v-458e2939></span><span class="vpi-moon moon" data-v-458e2939></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6a82b350 data-v-2b9279da><span class="container" data-v-2b9279da><span class="top" data-v-2b9279da></span><span class="middle" data-v-2b9279da></span><span class="bottom" data-v-2b9279da></span></span></button></div></div></div></div><div class="divider" data-v-6a82b350><div class="divider-line" data-v-6a82b350></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-0fd5f79a data-v-751e8533><div class="container" data-v-751e8533><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-751e8533><span class="vpi-align-left menu-icon" data-v-751e8533></span><span class="menu-text" data-v-751e8533>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-751e8533 data-v-afd8288e><button data-v-afd8288e>Return to top</button><!----></div></div></div><aside class="VPSidebar" data-v-0fd5f79a data-v-711af969><div class="curtain" data-v-711af969></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-711af969><span class="visually-hidden" id="sidebar-aria-label" data-v-711af969> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-4ebb8294><section class="VPSidebarItem level-0 has-active" data-v-4ebb8294 data-v-04203d25><div class="item" role="button" tabindex="0" data-v-04203d25><div class="indicator" data-v-04203d25></div><h2 class="text" data-v-04203d25>Proxy Core</h2><!----></div><div class="items" data-v-04203d25><!--[--><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/" data-v-04203d25><!--[--><p class="text" data-v-04203d25>模块概览</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/entry.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>入口与启动</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/cli.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>CLI 命令</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/proxy.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>代理转发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/ui-routes.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>UI 路由</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/providers.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>供应商管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/config.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>配置与日志</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/data-layer.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>数据层</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/stats.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>统计与历史</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/tool.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>工具注入</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/pm2.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>PM2 集成</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/utilities.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>工具函数</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/chat-api.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>Chat API</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-0fd5f79a data-v-3aa167b9><div class="VPDoc has-sidebar has-aside" data-v-3aa167b9 data-v-b2c5ca34><!--[--><!--]--><div class="container" data-v-b2c5ca34><div class="aside" data-v-b2c5ca34><div class="aside-curtain" data-v-b2c5ca34></div><div class="aside-container" data-v-b2c5ca34><div class="aside-content" data-v-b2c5ca34><div class="VPDocAside" data-v-b2c5ca34 data-v-af7efbb6><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-af7efbb6 data-v-db542fa8><div class="content" data-v-db542fa8><div class="outline-marker" data-v-db542fa8></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-db542fa8>On this page</div><ul class="VPDocOutlineItem root" data-v-db542fa8 data-v-1d036821><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-af7efbb6></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-b2c5ca34><div class="content-container" data-v-b2c5ca34><!--[--><!--]--><main class="main" data-v-b2c5ca34><div style="position:relative;" class="vp-doc _docs_proxy-core_chat-api" data-v-b2c5ca34><div><h1 id="proxy-core-chat-api-api-chat" tabindex="-1">proxy-core / Chat API (<code>/api/chat</code>) <a class="header-anchor" href="#proxy-core-chat-api-api-chat" aria-label="Permalink to &quot;proxy-core / Chat API (`/api/chat`)&quot;">​</a></h1><h2 id="本文档覆盖的源文件" tabindex="-1">本文档覆盖的源文件 <a class="header-anchor" href="#本文档覆盖的源文件" aria-label="Permalink to &quot;本文档覆盖的源文件&quot;">​</a></h2><ul><li><code>apps/proxy-core/src/server/chat-route.ts</code></li><li><code>apps/proxy-core/src/utils/sse-stream-processor.ts</code></li><li><code>apps/proxy-core/src/utils/inject-loop.ts</code>(<code>runStreamingInjectLoop</code> 部分)</li><li><code>apps/proxy-core/src/utils/sse-writer.ts</code>(<code>writeSSEEvent</code> 部分)</li><li><code>apps/proxy-core/src/utils/request-writer.ts</code>(session 管理 + DB)</li></ul><h2 id="与-v1-的区别" tabindex="-1">与 <code>/v1/*</code> 的区别 <a class="header-anchor" href="#与-v1-的区别" aria-label="Permalink to &quot;与 `/v1/*` 的区别&quot;">​</a></h2><p><code>/v1/*</code> 是纯透明代理(proxy.md),不改请求体结构,只做 header 过滤 + SSE pipe。</p><p><code>/api/chat</code> 是<strong>增强型代理</strong>,在转发前和转发后对请求/响应做多层处理:</p><table tabindex="0"><thead><tr><th>能力</th><th><code>/v1/*</code></th><th><code>/api/chat</code></th></tr></thead><tbody><tr><td>请求体修改</td><td>仅 model 替换</td><td>model 替换 + MCP tool 注入</td></tr><tr><td>响应处理</td><td>透传原样</td><td>SSE 流式转发 + inject loop 续接</td></tr><tr><td>Session 管理</td><td>从 header 读 <code>x-claude-code-session-id</code></td><td>生成/复用 <code>x-chat-session-id</code>,支持 resume</td></tr><tr><td>DB 记录</td><td>单条(原始请求)</td><td>多条(原始 + 每次 loop 迭代独立记录)</td></tr><tr><td>客户端信号</td><td>无</td><td><code>proxy_status</code> SSE 事件通知 tool 执行状态</td></tr></tbody></table><h2 id="请求流程总览" tabindex="-1">请求流程总览 <a class="header-anchor" href="#请求流程总览" aria-label="Permalink to &quot;请求流程总览&quot;">​</a></h2><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>客户端 → Fastify (解析 body)</span></span>
22
+ <span class="line"><span> → 生成/复用 sessionId</span></span>
23
+ <span class="line"><span> → session resume(如有历史)</span></span>
24
+ <span class="line"><span> → model tier 替换</span></span>
25
+ <span class="line"><span> → MCP tool 注入</span></span>
26
+ <span class="line"><span> → header 过滤 + 注入 x-chat-session-id</span></span>
27
+ <span class="line"><span> → fetch 上游 /v1/messages</span></span>
28
+ <span class="line"><span> → 响应分支处理(见下文)</span></span></code></pre></div><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart TD</span></span>
29
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> START([POST /api/chat]) --&gt; VALID{body 有 model + messages?}</span></span>
30
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> VALID -- 否 --&gt; 400[400 invalid_request]</span></span>
31
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> VALID -- 是 --&gt; SESSION[生成/复用 sessionId&lt;br/&gt;x-chat-session-id header]</span></span>
32
+ <span class="line"></span>
33
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SESSION --&gt; RESUME{x-chat-session-id 存在?}</span></span>
34
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESUME -- 是 --&gt; HISTORY[loadSessionHistory&lt;br/&gt;prepend 历史 messages]</span></span>
35
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESUME -- 否 --&gt; MODEL</span></span>
36
+ <span class="line"></span>
37
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HISTORY --&gt; MODEL[getProxyModel 替换 model]</span></span>
38
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MODEL --&gt; INJECT[injectMcpTools 追加 tools]</span></span>
39
+ <span class="line"></span>
40
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> INJECT --&gt; HEADER[filterForwardHeaders&lt;br/&gt;+ 注入 x-chat-session-id]</span></span>
41
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HEADER --&gt; MOCK{shouldMock?}</span></span>
42
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOCK -- 是 --&gt; MOCK_RESP[writeTextAsSSE 合成响应&lt;br/&gt;不上上游]</span></span>
43
+ <span class="line"></span>
44
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOCK -- 否 --&gt; FETCH[fetch 上游 /v1/messages]</span></span>
45
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> FETCH --&gt; CT{content-type?}</span></span>
46
+ <span class="line"></span>
47
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CT -- application/json --&gt; JSON_PATH[JSON 分支&lt;br/&gt;见 §JSON 响应]</span></span>
48
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CT -- text/event-stream --&gt; SSE_PATH[SSE 分支&lt;br/&gt;见 §SSE 流式响应]</span></span>
49
+ <span class="line"></span>
50
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SSE_PATH --&gt; PHASE1[Phase 1: 流式转发原始 SSE&lt;br/&gt;SSEStreamProcessor 边转边解析]</span></span>
51
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PHASE1 --&gt; STREAM_END[stream end]</span></span>
52
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> STREAM_END --&gt; DB1[保存原始请求到 DB]</span></span>
53
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> DB1 --&gt; HIT{hasInjectedToolUse?}</span></span>
54
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HIT -- 否 --&gt; CLOSE[reply.raw.end 结束]</span></span>
55
+ <span class="line"></span>
56
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HIT -- 是 --&gt; PROXY_STATUS[发 proxy_status 事件&lt;br/&gt;通知客户端 tool 执行中]</span></span>
57
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PROXY_STATUS --&gt; LOOP[Phase 2: runStreamingInjectLoop&lt;br/&gt;见 §Streaming Inject Loop]</span></span>
58
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP --&gt; LOOP_ITER{迭代: 执行 tool → 调上游 → 流式转发}</span></span>
59
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP_ITER --&gt; ITER_END[迭代 stream end]</span></span>
60
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ITER_END --&gt; DB2[保存迭代到 DB(独立记录)]</span></span>
61
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ITER_END --&gt; NEXT_HIT{还有 injected tool_use?}</span></span>
62
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> NEXT_HIT -- 是 --&gt; LOOP_ITER</span></span>
63
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> NEXT_HIT -- 否 --&gt; CLOSE</span></span>
64
+ <span class="line"></span>
65
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOCK_RESP --&gt; END([返回])</span></span>
66
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> JSON_PATH --&gt; END</span></span>
67
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> CLOSE --&gt; END</span></span></code></pre></div><h2 id="session-管理" tabindex="-1">Session 管理 <a class="header-anchor" href="#session-管理" aria-label="Permalink to &quot;Session 管理&quot;">​</a></h2><h3 id="session-id-生成" tabindex="-1">Session ID 生成 <a class="header-anchor" href="#session-id-生成" aria-label="Permalink to &quot;Session ID 生成&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> providedSessionId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.headers[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-chat-session-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> undefined</span></span>
68
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> sessionId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> providedSessionId </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> randomUUID</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
69
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">forwardHeaders[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-chat-session-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sessionId</span></span></code></pre></div><ul><li>客户端首次请求不带 <code>x-chat-session-id</code> → server 生成 UUID</li><li>生成的 sessionId 注入到 <code>forwardHeaders</code>,上游始终能看到此 header</li><li>Session ID 通过 response header <code>x-chat-session-id</code> 返回给客户端</li><li>客户端后续请求带上此 header → server 复用同一 sessionId</li></ul><h3 id="session-resume" tabindex="-1">Session Resume <a class="header-anchor" href="#session-resume" aria-label="Permalink to &quot;Session Resume&quot;">​</a></h3><p>当客户端带 <code>x-chat-session-id</code> 且 DB 中有历史记录:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (providedSessionId) {</span></span>
70
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> history</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> loadSessionHistory</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(providedSessionId)</span></span>
71
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (history) {</span></span>
72
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.body.messages </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">history.messages, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">request.body.messages]</span></span>
73
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (history.system </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&amp;&amp;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">request.body.system </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&amp;&amp;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">request.body.system_prompt) {</span></span>
74
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.body.system </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> history.system</span></span>
75
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
76
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
77
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li><code>loadSessionHistory(sessionId)</code>:从 SQLite 加载该 session 的历史 messages + system prompt</li><li>历史 messages prepend 到当前请求的 messages 前面</li><li>system prompt 仅在当前请求未提供时 carry over</li></ul><h2 id="model-tier-替换" tabindex="-1">Model Tier 替换 <a class="header-anchor" href="#model-tier-替换" aria-label="Permalink to &quot;Model Tier 替换&quot;">​</a></h2><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> originalModel</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.body.model</span></span>
78
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> proxyModel</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> getProxyModel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(originalModel, resolved)</span></span>
79
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (proxyModel) {</span></span>
80
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> request.body.model </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> proxyModel</span></span>
81
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>根据 provider 配置的 tier 映射替换请求中的 model。例如:<code>claude-sonnet</code> → provider 的 <code>sonnet_model</code>(可能是 <code>glm-5.1</code> 等国内模型)。</p><h2 id="mcp-tool-注入" tabindex="-1">MCP Tool 注入 <a class="header-anchor" href="#mcp-tool-注入" aria-label="Permalink to &quot;MCP Tool 注入&quot;">​</a></h2><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> injectedNames</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> injectMcpTools</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(request.body)</span></span>
82
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> injected</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> injectedNames.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">length</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &gt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 0</span></span></code></pre></div><p>与 <code>/v1/*</code> 路径的 tool 注入相同(详见 <a href="./tool.html">tool.md</a>)。在请求体的 <code>tools</code> 数组末尾追加已启用 tool 的三件套(name + description + input_schema)。</p><p><strong>关键区别</strong>:<code>/api/chat</code> 使用 <code>injectMcpTools</code>(仅注入 MCP 动态 tool),而 <code>/v1/*</code> 使用 <code>injectTools</code>(注入所有已启用 tool,包括 probe/curl)。</p><h2 id="sse-流式响应-核心路径" tabindex="-1">SSE 流式响应(核心路径) <a class="header-anchor" href="#sse-流式响应-核心路径" aria-label="Permalink to &quot;SSE 流式响应(核心路径)&quot;">​</a></h2><p>这是 <code>/api/chat</code> 的主要响应路径。<strong>统一处理</strong>,无论是否有 tool 注入——始终先流式转发原始 SSE,stream end 后再检测注入。</p><h3 id="phase-1-流式转发原始-sse" tabindex="-1">Phase 1:流式转发原始 SSE <a class="header-anchor" href="#phase-1-流式转发原始-sse" aria-label="Permalink to &quot;Phase 1:流式转发原始 SSE&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">hijack</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
83
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.raw.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">writeHead</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(response.status, { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">Object.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">fromEntries</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(response.headers), </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-chat-session-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: sessionId })</span></span>
84
+ <span class="line"></span>
85
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> processor</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SSEStreamProcessor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(reply.raw)</span></span>
86
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> nodeStream</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Readable.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">fromWeb</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(response.body)</span></span>
87
+ <span class="line"></span>
88
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">nodeStream.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">on</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;data&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">chunk</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> processor.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">processChunk</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(chunk))</span></span></code></pre></div><p><strong>SSEStreamProcessor</strong> 的核心职责:</p><ol><li><strong>转发</strong>:<code>processChunk(chunk)</code> 中 <code>this.raw.write(chunk)</code> 把原始 chunk 立即写给客户端</li><li><strong>解析</strong>:同步拆行解析 <code>data:</code> JSON,push 到 <code>events[]</code></li><li><strong>累积状态</strong>:增量更新 <code>contentBlocks</code> Map + <code>stopReason</code> + <code>usage</code></li><li><strong>跨 chunk 行边界</strong>:<code>leftover</code> 缓冲不完整行,下次 chunk 补齐</li></ol><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>上游 SSE chunk → SSEStreamProcessor.processChunk()</span></span>
89
+ <span class="line"><span> → reply.raw.write(chunk) // 客户端立即收到原始数据</span></span>
90
+ <span class="line"><span> → 解析 data: 行 → events[]</span></span>
91
+ <span class="line"><span> → processEvent → contentBlocks / stopReason / usage</span></span></code></pre></div><p>客户端看到的是<strong>与上游完全一致的原始 SSE 流</strong>,包括 thinking 块、text 块、tool_use 块。零延迟,零缓冲。</p><h3 id="ssestreamprocessor-内部结构" tabindex="-1">SSEStreamProcessor 内部结构 <a class="header-anchor" href="#ssestreamprocessor-内部结构" aria-label="Permalink to &quot;SSEStreamProcessor 内部结构&quot;">​</a></h3><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>SSEStreamProcessor</span></span>
92
+ <span class="line"><span>├── raw: ServerResponse // reply.raw,用于转发 chunk</span></span>
93
+ <span class="line"><span>├── events: any[] // 解析出的 JSON 事件(供 DB 记录)</span></span>
94
+ <span class="line"><span>├── contentBlocks: Map&lt;number, ParsedBlock&gt; // 增量累积的 content block 状态</span></span>
95
+ <span class="line"><span>├── stopReason: string // 从 message_delta 捕获</span></span>
96
+ <span class="line"><span>├── usage: any // 从 message_delta 捕获</span></span>
97
+ <span class="line"><span>├── leftover: string // 跨 chunk 的不完整行缓冲</span></span>
98
+ <span class="line"><span>│</span></span>
99
+ <span class="line"><span>├── processChunk(chunk) // 转发 + 解析 + 累积</span></span>
100
+ <span class="line"><span>├── flushLeftover() // stream end 后处理残留行</span></span>
101
+ <span class="line"><span>├── processEvent(e) // 增量更新 contentBlocks/stopReason</span></span>
102
+ <span class="line"><span>├── getParsedUpstream() // 从累积状态构建 ParsedUpstream</span></span>
103
+ <span class="line"><span>└── hasInjectedToolUse() // stopReason=tool_use + findInjectedCall</span></span></code></pre></div><p><code>processEvent</code> 逻辑与 <code>parseUpstreamEvents</code> 完全一致,改为逐事件调用:</p><table tabindex="0"><thead><tr><th>事件类型</th><th>累积操作</th></tr></thead><tbody><tr><td><code>content_block_start</code></td><td><code>contentBlocks.set(index, {type, text/id/name/input 初始化})</code></td></tr><tr><td><code>content_block_delta</code></td><td>累加 text/thinking/input 到对应 block</td></tr><tr><td><code>message_delta</code></td><td>更新 stopReason + usage</td></tr></tbody></table><h3 id="stream-end-→-检测-分支" tabindex="-1">Stream End → 检测 + 分支 <a class="header-anchor" href="#stream-end-→-检测-分支" aria-label="Permalink to &quot;Stream End → 检测 + 分支&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">nodeStream.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">on</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;end&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
104
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> processor.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">flushLeftover</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
105
+ <span class="line"></span>
106
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 保存原始请求到 DB(第 1 条记录)</span></span>
107
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> requestData.response</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.events </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> processor.events</span></span>
108
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> saveRequestDB</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(sessionId, cloudRequestId, requestData)</span></span>
109
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> pushNewRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
110
+ <span class="line"></span>
111
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (processor.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">hasInjectedToolUse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()) {</span></span>
112
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 发 proxy_status → 跑 inject loop</span></span>
113
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ...</span></span>
114
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
115
+ <span class="line"></span>
116
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> reply.raw.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">end</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
117
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p><strong>关键设计</strong>:DB 第 1 条记录保存的是 <code>processor.events</code>——客户端实际收到的原始 SSE 事件。DB 记录与客户端看到的内容<strong>完全一致</strong>。</p><h3 id="phase-2-streaming-inject-loop" tabindex="-1">Phase 2:Streaming Inject Loop <a class="header-anchor" href="#phase-2-streaming-inject-loop" aria-label="Permalink to &quot;Phase 2:Streaming Inject Loop&quot;">​</a></h3><p>当 <code>hasInjectedToolUse()</code> 返回 true(即 <code>stop_reason === &#39;tool_use&#39;</code> 且命中了注入的 MCP tool),进入 Phase 2。</p><h4 id="proxy-status-信号" tabindex="-1">proxy_status 信号 <a class="header-anchor" href="#proxy-status-信号" aria-label="Permalink to &quot;proxy_status 信号&quot;">​</a></h4><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">writeSSEEvent</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(reply.raw, { type: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;proxy_status&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, status: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;tool_executing&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, tool: injectedCall?.name })</span></span></code></pre></div><p>在第一条 <code>message_stop</code> 后、loop 开始前,发一个自定义 SSE 事件:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>event: proxy_status</span></span>
118
+ <span class="line"><span>data: {&quot;type&quot;:&quot;proxy_status&quot;,&quot;status&quot;:&quot;tool_executing&quot;,&quot;tool&quot;:&quot;mcp__draw-io__list-documents&quot;}</span></span></code></pre></div><p><strong>客户端如何理解</strong>:</p><ul><li><code>proxy_status</code> → 这是 proxy 自定义事件,不是 Anthropic API 标准事件</li><li><code>status: tool_executing</code> → proxy 正在代行这个 tool,客户端不需要自己执行</li><li>同 SSE 连接上还有续接数据,继续监听</li><li>客户端可据此显示&quot;调用工具中&quot;状态</li></ul><h4 id="runstreaminginjectloop" tabindex="-1">runStreamingInjectLoop <a class="header-anchor" href="#runstreaminginjectloop" aria-label="Permalink to &quot;runStreamingInjectLoop&quot;">​</a></h4><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> runStreamingInjectLoop</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
119
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> initialParsed: processor.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getParsedUpstream</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(),</span></span>
120
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> body: request.body,</span></span>
121
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> callUpstream</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">b</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
122
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> r</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fetch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(targetUrlStr, { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
123
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { response: r, requestId: loopRequestId }</span></span>
124
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
125
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> streamAndParse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">loopResponse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
126
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> loopProcessor</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SSEStreamProcessor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(reply.raw)</span></span>
127
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 流式转发 loop 迭代的 SSE 到同一 reply.raw</span></span>
128
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { processor: loopProcessor, statusCode: loopResponse.status }</span></span>
129
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
130
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> saveIterationDB</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">loopRequestId</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">loopProcessor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">loopStatusCode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">loopBody</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
131
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 独立 DB 记录</span></span>
132
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> saveRequestDB</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
133
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> pushNewRequest</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
134
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
135
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> raw: reply.raw</span></span>
136
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p><strong>每次迭代的流程</strong>:</p><ol><li><code>findInjectedCall(parsed)</code> → 找命中的 tool_use block</li><li><code>tool.exec(call.input)</code> → 本地执行 tool,得 result</li><li><code>body.messages.push(assistant + tool_result)</code> → 追加对话</li><li><code>callUpstream(body)</code> → fetch 上游,获取新 SSE 流</li><li><code>streamAndParse(response)</code> → <strong>流式转发到同一 reply.raw</strong>(客户端实时看到续接)</li><li><code>saveIterationDB(...)</code> → 独立 DB 记录(第 N 条)</li><li>检查新 stream 的 stopReason → 还有 tool_use 则继续迭代,end_turn 则结束</li></ol><p><strong>与旧 <code>runInjectLoop</code> 的核心区别</strong>:</p><table tabindex="0"><thead><tr><th></th><th>runInjectLoop(旧)</th><th>runStreamingInjectLoop(新)</th></tr></thead><tbody><tr><td>上游响应处理</td><td><code>await response.text()</code> 全量缓冲</td><td><code>SSEStreamProcessor</code> 流式转发</td></tr><tr><td>客户端看到</td><td>合成 SSE(仅 text,<code>writeTextAsSSE</code>)</td><td>原始 SSE(thinking + text + tool_use)</td></tr><tr><td>DB 记录</td><td>原始 events 存第 1 条,loop 结果合并</td><td>原始 + 每次迭代独立记录</td></tr><tr><td>返回值</td><td><code>{ text, iterations }</code></td><td><code>{ iterations }</code>(text 已实时流到客户端)</td></tr><tr><td>连接模式</td><td>缓冲完毕后一次性 <code>reply.raw.end()</code></td><td>同连接续接,<code>reply.raw.end()</code> 在最后</td></tr></tbody></table><h3 id="完整-sse-时序示例" tabindex="-1">完整 SSE 时序示例 <a class="header-anchor" href="#完整-sse-时序示例" aria-label="Permalink to &quot;完整 SSE 时序示例&quot;">​</a></h3><p>一次带 MCP tool 注入的 SSE 响应时序:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>→ 客户端发出 POST /api/chat</span></span>
137
+ <span class="line"><span></span></span>
138
+ <span class="line"><span>← SSE Phase 1:原始上游响应(实时流到客户端)</span></span>
139
+ <span class="line"><span> event: message_start {id: &quot;msg_xxx&quot;, model: &quot;glm-5.1&quot;}</span></span>
140
+ <span class="line"><span> event: content_block_start {index: 0, type: &quot;thinking&quot;}</span></span>
141
+ <span class="line"><span> event: content_block_delta {index: 0, delta: {thinking_delta: &quot;用户要我画SSR...&quot;}}</span></span>
142
+ <span class="line"><span> ...(多个 thinking_delta)</span></span>
143
+ <span class="line"><span> event: content_block_stop {index: 0}</span></span>
144
+ <span class="line"><span> event: content_block_start {index: 1, type: &quot;text&quot;}</span></span>
145
+ <span class="line"><span> event: content_block_delta {index: 1, delta: {text_delta: &quot;当然可以!&quot;}}</span></span>
146
+ <span class="line"><span> ...(多个 text_delta)</span></span>
147
+ <span class="line"><span> event: content_block_stop {index: 1}</span></span>
148
+ <span class="line"><span> event: content_block_start {index: 2, type: &quot;tool_use&quot;, name: &quot;mcp__draw-io__list-documents&quot;}</span></span>
149
+ <span class="line"><span> event: content_block_delta {index: 2, delta: {input_json_delta: &quot;{}&quot;}}</span></span>
150
+ <span class="line"><span> event: content_block_stop {index: 2}</span></span>
151
+ <span class="line"><span> event: message_delta {delta: {stop_reason: &quot;tool_use&quot;}}</span></span>
152
+ <span class="line"><span> event: message_stop</span></span>
153
+ <span class="line"><span></span></span>
154
+ <span class="line"><span>← proxy_status 信号</span></span>
155
+ <span class="line"><span> event: proxy_status {status: &quot;tool_executing&quot;, tool: &quot;mcp__draw-io__list-documents&quot;}</span></span>
156
+ <span class="line"><span></span></span>
157
+ <span class="line"><span>← SSE Phase 2:loop 迭代(实时流到客户端,同一连接)</span></span>
158
+ <span class="line"><span> event: ping {type: &quot;ping&quot;}</span></span>
159
+ <span class="line"><span> event: message_start {id: &quot;msg_yyy&quot;, model: &quot;glm-5.1&quot;}</span></span>
160
+ <span class="line"><span> event: content_block_start {index: 0, type: &quot;thinking&quot;}</span></span>
161
+ <span class="line"><span> ...(thinking 块)</span></span>
162
+ <span class="line"><span> event: content_block_start {index: 1, type: &quot;text&quot;}</span></span>
163
+ <span class="line"><span> event: content_block_delta {index: 1, delta: {text_delta: &quot;没有打开的文档&quot;}}</span></span>
164
+ <span class="line"><span> ...(text 块)</span></span>
165
+ <span class="line"><span> event: message_delta {delta: {stop_reason: &quot;end_turn&quot;}}</span></span>
166
+ <span class="line"><span> event: message_stop</span></span>
167
+ <span class="line"><span></span></span>
168
+ <span class="line"><span>← 连接关闭(reply.raw.end)</span></span></code></pre></div><p>客户端判断逻辑:</p><ul><li><code>stop_reason: tool_use</code> + <code>proxy_status</code> → 显示&quot;调用工具中&quot;,继续监听</li><li><code>stop_reason: end_turn</code> → 最终完成,关闭连接</li></ul><h3 id="db-记录结构" tabindex="-1">DB 记录结构 <a class="header-anchor" href="#db-记录结构" aria-label="Permalink to &quot;DB 记录结构&quot;">​</a></h3><p>一条 chat 请求在 DB 中可能有 1~N 条记录:</p><table tabindex="0"><thead><tr><th>记录</th><th>requestId</th><th>内容</th><th>来源</th></tr></thead><tbody><tr><td>第 1 条</td><td><code>cloudRequestId</code></td><td>原始上游 SSE events(含 thinking + text + tool_use)</td><td>Phase 1 <code>processor.events</code></td></tr><tr><td>第 2 条</td><td><code>loop_xxx_1</code></td><td>第 1 次 loop 迭代的 SSE events</td><td>Phase 2 <code>loopProcessor.events</code></td></tr><tr><td>第 N 条</td><td><code>loop_xxx_N</code></td><td>第 N 次 loop 迭代的 SSE events</td><td>Phase 2</td></tr></tbody></table><p>所有记录共享同一 <code>sessionId</code>,通过 <code>compositeId = sessionId:requestId</code> 关联。</p><h2 id="json-响应-非流式" tabindex="-1">JSON 响应(非流式) <a class="header-anchor" href="#json-响应-非流式" aria-label="Permalink to &quot;JSON 响应(非流式)&quot;">​</a></h2><p>当上游返回 <code>content-type: application/json</code>(通常是错误或非流式请求):</p><ol><li>缓冲完整 JSON body</li><li>检测是否有 injected tool_use → 跑 <code>runJsonInjectLoop</code>(与 SSE 版对称,但处理 JSON body)</li><li>注入 <code>_sessionId</code> 到 response body + <code>x-chat-session-id</code> header</li><li>返回给客户端</li></ol><p>JSON 路径不做流式处理(JSON 本身不是流式协议)。详见代码 <code>chat-route.ts:160-292</code>。</p><h2 id="mock-拦截" tabindex="-1">Mock 拦截 <a class="header-anchor" href="#mock-拦截" aria-label="Permalink to &quot;Mock 拦截&quot;">​</a></h2><p><code>shouldMock(body)</code> 检测 user message 中是否含 <code>__MOCK__</code>。命中时:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">hijack</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
169
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.raw.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">writeHead</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">200</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;content-type&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;text/event-stream&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
170
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">writeTextAsSSE</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(reply.raw, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;[PoC] ...&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">`msg_poc_chat_${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">request</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">id</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
171
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.raw.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">end</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span></code></pre></div><p>不上上游,直接合成 SSE 返回。用于 PoC 测试。</p><h2 id="header-处理" tabindex="-1">Header 处理 <a class="header-anchor" href="#header-处理" aria-label="Permalink to &quot;Header 处理&quot;">​</a></h2><h3 id="请求-header-过滤" tabindex="-1">请求 header 过滤 <a class="header-anchor" href="#请求-header-过滤" aria-label="Permalink to &quot;请求 header 过滤&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> forwardHeaders</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> filterForwardHeaders</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">extractSafeHeaders</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(request.headers), resolved.apiKey)</span></span>
172
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">forwardHeaders[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-chat-session-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sessionId</span></span></code></pre></div><ul><li>删除 <code>host</code>(阿里云 404)、<code>content-length</code>(长度变化)</li><li>保留 <code>anthropic-version</code>、<code>x-api-key</code>、<code>accept: text/event-stream</code></li><li>有 provider key 时覆盖 <code>x-api-key</code> 和 <code>authorization</code></li><li><strong>注入 <code>x-chat-session-id</code></strong>:上游始终能看到此 header</li></ul><h3 id="响应-header" tabindex="-1">响应 header <a class="header-anchor" href="#响应-header" aria-label="Permalink to &quot;响应 header&quot;">​</a></h3><p>SSE 分支:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.raw.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">writeHead</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(response.status, { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">...</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">Object.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">fromEntries</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(response.headers), </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-chat-session-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: sessionId })</span></span></code></pre></div><p>保留上游所有 header + 注入 session ID。</p><p>JSON 分支:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">reply.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">header</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;x-chat-session-id&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, sessionId)</span></span></code></pre></div><h2 id="边界情况" tabindex="-1">边界情况 <a class="header-anchor" href="#边界情况" aria-label="Permalink to &quot;边界情况&quot;">​</a></h2><h3 id="上游返回错误-4xx-5xx" tabindex="-1">上游返回错误(4xx/5xx) <a class="header-anchor" href="#上游返回错误-4xx-5xx" aria-label="Permalink to &quot;上游返回错误(4xx/5xx)&quot;">​</a></h3><p>SSE 分支正常转发原始错误 SSE,不触发 inject loop。DB 记录包含错误事件。</p><h3 id="客户端断连" tabindex="-1">客户端断连 <a class="header-anchor" href="#客户端断连" aria-label="Permalink to &quot;客户端断连&quot;">​</a></h3><p><code>reply.raw.destroyed</code> 检查。<code>runStreamingInjectLoop</code> 每次迭代前检查此标志,断连时中断 loop。</p><h3 id="thinking-block-signature" tabindex="-1">thinking block signature <a class="header-anchor" href="#thinking-block-signature" aria-label="Permalink to &quot;thinking block signature&quot;">​</a></h3><p><code>blocksToAssistantContent</code> 跳过 thinking 块——Anthropic extended thinking 有 signature 校验,把 thinking 塞回请求会引发不一致。loop 追加 assistant content 时只包含 text + tool_use。</p><h3 id="跨-chunk-行边界" tabindex="-1">跨 chunk 行边界 <a class="header-anchor" href="#跨-chunk-行边界" aria-label="Permalink to &quot;跨 chunk 行边界&quot;">​</a></h3><p><code>SSEStreamProcessor.leftover</code> 缓冲不完整行。如果一个 <code>data: {...}</code> 事件跨 chunk 被截断,前半段留在 leftover,下次 chunk 补齐后完整解析。<code>flushLeftover()</code> 在 stream end 后处理最后的残留。</p><h3 id="多次-tool-use" tabindex="-1">多次 tool_use <a class="header-anchor" href="#多次-tool-use" aria-label="Permalink to &quot;多次 tool_use&quot;">​</a></h3><p>如果上游在一条消息中同时调用多个 tool,<code>findInjectedCall</code> 返回第一个命中的。每次 loop 迭代处理一个 tool,如果后续迭代仍有 tool_use 则继续循环。</p><h2 id="关键设计决策" tabindex="-1">关键设计决策 <a class="header-anchor" href="#关键设计决策" aria-label="Permalink to &quot;关键设计决策&quot;">​</a></h2><ol><li><p><strong>统一 SSE 路径</strong>:无论是否有 tool 注入,SSE 响应始终走同一条路径(流式转发 + stream end 后检测)。不再区分&quot;注入路径&quot;和&quot;passthrough 路径&quot;。</p></li><li><p><strong>原始 SSE 透传</strong>:客户端看到的是与上游完全一致的原始 SSE 流,包括 thinking 块、text 块、tool_use 块。不做任何合成或过滤。</p></li><li><p><strong>同连接续接</strong>:inject loop 的结果在同一 SSE 连接上续接,不新建 HTTP 连接。客户端从 <code>message_stop</code> 到下一个 <code>message_start</code> 之间看到 <code>proxy_status</code> 事件和可能的 <code>ping</code> 保活。</p></li><li><p><strong>DB 记录一致性</strong>:第 1 条 DB 记录的 events 与客户端实际收到的完全一致。每次 loop 迭代有独立 DB 记录。</p></li><li><p><strong><code>proxy_status</code> 自定义事件</strong>:在第一条 <code>message_stop</code> 后、loop 开始前发出,让客户端知道 proxy 在代行 tool。这是 proxy 自定义协议扩展,不是 Anthropic API 标准事件。</p></li><li><p><strong><code>x-chat-session-id</code> 注入到 forwardHeaders</strong>:上游始终能看到 session ID header,proxy 不需要管理 resume 逻辑,只需透传。</p></li></ol><h2 id="相关文档" tabindex="-1">相关文档 <a class="header-anchor" href="#相关文档" aria-label="Permalink to &quot;相关文档&quot;">​</a></h2><ul><li>Tool 注入机制 → <a href="./tool.html">tool.md</a></li><li><code>/v1/*</code> 纯代理路径 → <a href="./proxy.html">proxy.md</a></li><li>SSE 写入工具 → <a href="./tool.html#合成-sse-writer">tool.md#合成-sse-writer</a></li><li>数据层(DB + session 管理)→ <a href="./data-layer.html">data-layer.md</a></li></ul></div></div></main><footer class="VPDocFooter" data-v-b2c5ca34 data-v-2cae581d><!--[--><!--]--><!----><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-2cae581d><span class="visually-hidden" id="doc-footer-aria-label" data-v-2cae581d>Pager</span><div class="pager" data-v-2cae581d><a class="VPLink link pager-link prev" href="/docs/proxy-core/utilities.html" data-v-2cae581d><!--[--><span class="desc" data-v-2cae581d>Previous page</span><span class="title" data-v-2cae581d>工具函数</span><!--]--></a></div><div class="pager" data-v-2cae581d><!----></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
173
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"index.md\":\"p9floL_p\",\"overview.md\":\"BKVdLT3o\",\"packages-utils.md\":\"CvgYp5Ll\",\"proxy-admin_env-and-build.md\":\"xkeQNYS3\",\"proxy-admin_index.md\":\"DBLI0n0G\",\"proxy-admin_layout-and-menu.md\":\"BKGcu49p\",\"proxy-admin_pages.md\":\"m_fGvvOH\",\"proxy-admin_routing-and-auth.md\":\"DZsdFese\",\"proxy-admin_services-and-mock.md\":\"sdNPcf25\",\"proxy-cli_api-layer.md\":\"GfdbtEUx\",\"proxy-cli_app-shell.md\":\"Do18CYhW\",\"proxy-cli_components-common.md\":\"Dd6Yazvz\",\"proxy-cli_components-config.md\":\"B81Y3ta2\",\"proxy-cli_components-requests.md\":\"vN8IrwL_\",\"proxy-cli_components-stats.md\":\"B90esaNa\",\"proxy-cli_components-status.md\":\"C5lAzS2c\",\"proxy-cli_data-hooks.md\":\"w9Oe1OD3\",\"proxy-cli_index.md\":\"BA6g8QD-\",\"proxy-cli_utils-and-i18n.md\":\"Ch_e-g_o\",\"proxy-core_chat-api.md\":\"DHihiBxR\",\"proxy-core_cli.md\":\"DCFYX4Bd\",\"proxy-core_config.md\":\"BXSOyxYE\",\"proxy-core_data-layer.md\":\"Cdomb3Gz\",\"proxy-core_entry.md\":\"BZmIcCUM\",\"proxy-core_index.md\":\"BM6VV5Qe\",\"proxy-core_pm2.md\":\"DUhWEtgn\",\"proxy-core_providers.md\":\"CbDZ6b_7\",\"proxy-core_proxy.md\":\"CzQYmX6X\",\"proxy-core_stats.md\":\"BsM6wuK_\",\"proxy-core_tool.md\":\"B6Le1nQr\",\"proxy-core_ui-routes.md\":\"Dyqkeoiv\",\"proxy-core_utilities.md\":\"C18pjnkz\",\"quickstart.md\":\"Cy_FmXIY\",\"request-flow.md\":\"C1fyxdPE\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"CC Monitoring\",\"description\":\"Claude Code 代理 + 监控系统文档\",\"base\":\"/docs/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"nav\":[{\"text\":\"概览\",\"link\":\"/overview\"},{\"text\":\"快速开始\",\"link\":\"/quickstart\"},{\"text\":\"Proxy Core\",\"link\":\"/proxy-core/\"},{\"text\":\"Proxy CLI\",\"link\":\"/proxy-cli/\"},{\"text\":\"Proxy Admin\",\"link\":\"/proxy-admin/\"}],\"sidebar\":{\"/proxy-core/\":[{\"text\":\"Proxy Core\",\"items\":[{\"text\":\"模块概览\",\"link\":\"/proxy-core/\"},{\"text\":\"入口与启动\",\"link\":\"/proxy-core/entry\"},{\"text\":\"CLI 命令\",\"link\":\"/proxy-core/cli\"},{\"text\":\"代理转发\",\"link\":\"/proxy-core/proxy\"},{\"text\":\"UI 路由\",\"link\":\"/proxy-core/ui-routes\"},{\"text\":\"供应商管理\",\"link\":\"/proxy-core/providers\"},{\"text\":\"配置与日志\",\"link\":\"/proxy-core/config\"},{\"text\":\"数据层\",\"link\":\"/proxy-core/data-layer\"},{\"text\":\"统计与历史\",\"link\":\"/proxy-core/stats\"},{\"text\":\"工具注入\",\"link\":\"/proxy-core/tool\"},{\"text\":\"PM2 集成\",\"link\":\"/proxy-core/pm2\"},{\"text\":\"工具函数\",\"link\":\"/proxy-core/utilities\"},{\"text\":\"Chat API\",\"link\":\"/proxy-core/chat-api\"}]}],\"/proxy-cli/\":[{\"text\":\"Proxy CLI\",\"items\":[{\"text\":\"模块概览\",\"link\":\"/proxy-cli/\"},{\"text\":\"应用外壳\",\"link\":\"/proxy-cli/app-shell\"},{\"text\":\"数据 Hooks\",\"link\":\"/proxy-cli/data-hooks\"},{\"text\":\"API 层\",\"link\":\"/proxy-cli/api-layer\"},{\"text\":\"状态组件\",\"link\":\"/proxy-cli/components-status\"},{\"text\":\"统计组件\",\"link\":\"/proxy-cli/components-stats\"},{\"text\":\"请求组件\",\"link\":\"/proxy-cli/components-requests\"},{\"text\":\"配置组件\",\"link\":\"/proxy-cli/components-config\"},{\"text\":\"通用组件\",\"link\":\"/proxy-cli/components-common\"},{\"text\":\"工具与国际化\",\"link\":\"/proxy-cli/utils-and-i18n\"}]}],\"/proxy-admin/\":[{\"text\":\"Proxy Admin\",\"items\":[{\"text\":\"模块概览\",\"link\":\"/proxy-admin/\"},{\"text\":\"路由与认证\",\"link\":\"/proxy-admin/routing-and-auth\"},{\"text\":\"布局与菜单\",\"link\":\"/proxy-admin/layout-and-menu\"},{\"text\":\"页面\",\"link\":\"/proxy-admin/pages\"},{\"text\":\"服务与 Mock\",\"link\":\"/proxy-admin/services-and-mock\"},{\"text\":\"环境与构建\",\"link\":\"/proxy-admin/env-and-build\"}]}]},\"siteTitle\":\"CC Monitoring\",\"search\":{\"provider\":\"local\"}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
174
+
175
+ </body>
176
+ </html>
@@ -0,0 +1,61 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN" dir="ltr">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>proxy-core / CLI 命令 | CC Monitoring</title>
7
+ <meta name="description" content="Claude Code 代理 + 监控系统文档">
8
+ <meta name="generator" content="VitePress v1.6.4">
9
+ <link rel="preload stylesheet" href="/docs/assets/style.DU_kNMWy.css" as="style">
10
+ <link rel="preload stylesheet" href="/docs/vp-icons.css" as="style">
11
+
12
+ <script type="module" src="/docs/assets/app.BxFOH0P1.js"></script>
13
+ <link rel="preload" href="/docs/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
+ <link rel="modulepreload" href="/docs/assets/chunks/theme.BLEczZWC.js">
15
+ <link rel="modulepreload" href="/docs/assets/chunks/framework.D_Xv2a7c.js">
16
+ <link rel="modulepreload" href="/docs/assets/proxy-core_cli.md.DCFYX4Bd.lean.js">
17
+ <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
18
+ <script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
19
+ </head>
20
+ <body>
21
+ <div id="app"><div class="Layout" data-v-0fd5f79a><!--[--><!--]--><!--[--><span tabindex="-1" data-v-13bcab17></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-13bcab17>Skip to content</a><!--]--><!----><header class="VPNav" data-v-0fd5f79a data-v-221ddc7b><div class="VPNavBar" data-v-221ddc7b data-v-6a82b350><div class="wrapper" data-v-6a82b350><div class="container" data-v-6a82b350><div class="title" data-v-6a82b350><div class="VPNavBarTitle has-sidebar" data-v-6a82b350 data-v-98825d79><a class="title" href="/docs/" data-v-98825d79><!--[--><!--]--><!----><span data-v-98825d79>CC Monitoring</span><!--[--><!--]--></a></div></div><div class="content" data-v-6a82b350><div class="content-body" data-v-6a82b350><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6a82b350><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6a82b350 data-v-2fa375b4><span id="main-nav-aria-label" class="visually-hidden" data-v-2fa375b4> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/overview.html" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>概览</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/quickstart.html" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>快速开始</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/proxy-core/" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>Proxy Core</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/proxy-cli/" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>Proxy CLI</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/docs/proxy-admin/" tabindex="0" data-v-2fa375b4 data-v-88169469><!--[--><span data-v-88169469>Proxy Admin</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6a82b350 data-v-c7859fea><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-c7859fea data-v-458e2939 data-v-2fadb15f><span class="check" data-v-2fadb15f><span class="icon" data-v-2fadb15f><!--[--><span class="vpi-sun sun" data-v-458e2939></span><span class="vpi-moon moon" data-v-458e2939></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6a82b350 data-v-4a332738 data-v-3416cc30><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-3416cc30><span class="vpi-more-horizontal icon" data-v-3416cc30></span></button><div class="menu" data-v-3416cc30><div class="VPMenu" data-v-3416cc30 data-v-70b241a4><!----><!--[--><!--[--><!----><div class="group" data-v-4a332738><div class="item appearance" data-v-4a332738><p class="label" data-v-4a332738>Appearance</p><div class="appearance-action" data-v-4a332738><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-4a332738 data-v-458e2939 data-v-2fadb15f><span class="check" data-v-2fadb15f><span class="icon" data-v-2fadb15f><!--[--><span class="vpi-sun sun" data-v-458e2939></span><span class="vpi-moon moon" data-v-458e2939></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6a82b350 data-v-2b9279da><span class="container" data-v-2b9279da><span class="top" data-v-2b9279da></span><span class="middle" data-v-2b9279da></span><span class="bottom" data-v-2b9279da></span></span></button></div></div></div></div><div class="divider" data-v-6a82b350><div class="divider-line" data-v-6a82b350></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-0fd5f79a data-v-751e8533><div class="container" data-v-751e8533><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-751e8533><span class="vpi-align-left menu-icon" data-v-751e8533></span><span class="menu-text" data-v-751e8533>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-751e8533 data-v-afd8288e><button data-v-afd8288e>Return to top</button><!----></div></div></div><aside class="VPSidebar" data-v-0fd5f79a data-v-711af969><div class="curtain" data-v-711af969></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-711af969><span class="visually-hidden" id="sidebar-aria-label" data-v-711af969> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-4ebb8294><section class="VPSidebarItem level-0 has-active" data-v-4ebb8294 data-v-04203d25><div class="item" role="button" tabindex="0" data-v-04203d25><div class="indicator" data-v-04203d25></div><h2 class="text" data-v-04203d25>Proxy Core</h2><!----></div><div class="items" data-v-04203d25><!--[--><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/" data-v-04203d25><!--[--><p class="text" data-v-04203d25>模块概览</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/entry.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>入口与启动</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/cli.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>CLI 命令</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/proxy.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>代理转发</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/ui-routes.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>UI 路由</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/providers.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>供应商管理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/config.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>配置与日志</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/data-layer.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>数据层</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/stats.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>统计与历史</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/tool.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>工具注入</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/pm2.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>PM2 集成</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/utilities.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>工具函数</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-04203d25><div class="item" data-v-04203d25><div class="indicator" data-v-04203d25></div><a class="VPLink link link" href="/docs/proxy-core/chat-api.html" data-v-04203d25><!--[--><p class="text" data-v-04203d25>Chat API</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-0fd5f79a data-v-3aa167b9><div class="VPDoc has-sidebar has-aside" data-v-3aa167b9 data-v-b2c5ca34><!--[--><!--]--><div class="container" data-v-b2c5ca34><div class="aside" data-v-b2c5ca34><div class="aside-curtain" data-v-b2c5ca34></div><div class="aside-container" data-v-b2c5ca34><div class="aside-content" data-v-b2c5ca34><div class="VPDocAside" data-v-b2c5ca34 data-v-af7efbb6><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-af7efbb6 data-v-db542fa8><div class="content" data-v-db542fa8><div class="outline-marker" data-v-db542fa8></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-db542fa8>On this page</div><ul class="VPDocOutlineItem root" data-v-db542fa8 data-v-1d036821><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-af7efbb6></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-b2c5ca34><div class="content-container" data-v-b2c5ca34><!--[--><!--]--><main class="main" data-v-b2c5ca34><div style="position:relative;" class="vp-doc _docs_proxy-core_cli" data-v-b2c5ca34><div><h1 id="proxy-core-cli-命令" tabindex="-1">proxy-core / CLI 命令 <a class="header-anchor" href="#proxy-core-cli-命令" aria-label="Permalink to &quot;proxy-core / CLI 命令&quot;">​</a></h1><h2 id="本文档覆盖的源文件" tabindex="-1">本文档覆盖的源文件 <a class="header-anchor" href="#本文档覆盖的源文件" aria-label="Permalink to &quot;本文档覆盖的源文件&quot;">​</a></h2><ul><li><code>apps/proxy-core/src/cli/index.ts</code></li><li><code>apps/proxy-core/src/cli/commands/*.ts</code></li><li><code>apps/proxy-core/src/utils/pm2.ts</code></li><li><code>apps/proxy-core/src/utils/net.ts</code></li></ul><h2 id="命令总览" tabindex="-1">命令总览 <a class="header-anchor" href="#命令总览" aria-label="Permalink to &quot;命令总览&quot;">​</a></h2><p><code>cli/index.ts</code> 注册 8 条显式命令 + 1 条隐藏 <code>clean-requests</code>。全局参数 <code>-c, --config &lt;path&gt;</code> 通过 <code>preAction</code> hook 写入 <code>paths.setConfigPathOverride</code>。</p><table tabindex="0"><thead><tr><th>命令</th><th>文件</th><th>摘要</th></tr></thead><tbody><tr><td><code>start</code></td><td><code>commands/start.ts</code></td><td>PM2 守护启动 + 端口探测</td></tr><tr><td><code>stop</code></td><td><code>commands/stop.ts</code></td><td>停止 PM2 进程</td></tr><tr><td><code>status</code></td><td><code>commands/status.ts</code></td><td>打印状态快照</td></tr><tr><td><code>logs [n]</code></td><td><code>commands/logs.ts</code></td><td>打印最近 n 行日志</td></tr><tr><td><code>config</code></td><td><code>commands/config.ts</code></td><td>show / set / reset</td></tr><tr><td><code>reload</code></td><td><code>commands/reload.ts</code></td><td>优雅重启 + 探测</td></tr><tr><td><code>test</code></td><td><code>commands/test.ts</code></td><td>HEAD 探测上游</td></tr><tr><td><code>ui</code></td><td><code>commands/ui.ts</code></td><td>打开浏览器面板</td></tr><tr><td><code>clean-requests</code></td><td><code>cli/index.ts:63-78</code></td><td>清理旧请求(隐藏)</td></tr></tbody></table><p>进程名统一为 <code>cc-monitoring</code>(多个命令写死 <code>PROCESS_NAME = &#39;cc-monitoring&#39;</code>)。</p><h2 id="start" tabindex="-1">start <a class="header-anchor" href="#start" aria-label="Permalink to &quot;start&quot;">​</a></h2><p><code>apps/proxy-core/src/cli/commands/start.ts</code>:</p><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart LR</span></span>
22
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> A[Loading config] --&gt; B{options.port?}</span></span>
23
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> B -- 是 --&gt; P[覆盖端口 + saveConfig]</span></span>
24
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> B -- 否 --&gt; C[Locating PM2 config]</span></span>
25
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> P --&gt; C</span></span>
26
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> C --&gt; D[startProcess ecosystemPath]</span></span>
27
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> D --&gt; E[waitForOnline 轮询]</span></span>
28
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> E -- online --&gt; F[waitForPort 5 次退避]</span></span>
29
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> E -- 超时 --&gt; X([exit 1])</span></span>
30
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> F -- listening --&gt; G[打印 summary]</span></span>
31
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> F -- 超时 --&gt; X</span></span></code></pre></div><ul><li><strong>步骤 1</strong>:<code>loadConfig()</code>;若命令行传 <code>-p 8080</code>,就地改 <code>config.server.port</code> 并 <code>saveConfig()</code> 持久化</li><li><strong>步骤 2</strong>:用 <code>getCallerDirname(&#39;../cli&#39;)</code> 推 <code>ecosystemPath = &lt;cli&gt;/../../ecosystem.config.cjs</code>(编译后 <code>dist/cli/../../ecosystem.config.cjs</code>)</li><li><strong>步骤 3</strong>:<code>startProcess(ecosystemPath)</code> → <code>pm2.connect()</code> + <code>pm2.start()</code> + <code>pm2.disconnect()</code>(<code>utils/pm2.ts:74-78</code>)</li><li><strong>步骤 4</strong>:<code>waitForOnline(&#39;cc-monitoring&#39;, 8000, 300)</code>:8 秒内每 300ms 轮询 <code>pm2.list()</code> 直到 <code>pm2_env.status === &#39;online&#39;</code>(<code>utils/pm2.ts:93-107</code>)</li><li><strong>步骤 5</strong>:<code>waitForPort(host, port, callback)</code>:递增退避 1s → 2s → 3s → 4s → 5s(累计 15s)尝试 TCP 连接(<code>utils/net.ts:30-43</code>);host 是 <code>0.0.0.0</code>/<code>::</code>/空时探测 <code>127.0.0.1</code></li><li><strong>失败</strong>:任何一步失败打印 <code>~/.cc-monitoring/logs/error.log</code> 路径然后 <code>process.exit(1)</code></li></ul><p>Summary 输出四行:Listening / Forwarding to / Dashboard / Logs。</p><h2 id="stop" tabindex="-1">stop <a class="header-anchor" href="#stop" aria-label="Permalink to &quot;stop&quot;">​</a></h2><p><code>commands/stop.ts:3-7</code>:直接 <code>stopProcess(&#39;cc-monitoring&#39;)</code>,内部 <code>pm2.stop()</code>。无进度、无探测。</p><h2 id="status" tabindex="-1">status <a class="header-anchor" href="#status" aria-label="Permalink to &quot;status&quot;">​</a></h2><p><code>commands/status.ts:3-17</code>:<code>getProcessStatus(&#39;cc-monitoring&#39;)</code> 返回</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{ name, status, cpu, memory, uptime, restarts }</span></span></code></pre></div><p>(<code>utils/pm2.ts:109-125</code>)。文字打印四行;未找到进程输出 <code>Server not running</code>。</p><h2 id="logs-n" tabindex="-1">logs [n] <a class="header-anchor" href="#logs-n" aria-label="Permalink to &quot;logs [n]&quot;">​</a></h2><p><code>commands/logs.ts</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> config</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> loadConfig</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
32
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> logs</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> readLogs</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(config.logging.file, {</span></span>
33
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> limit: n </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> parseInt</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(n) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 50</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
34
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> level: options.level,</span></span>
35
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> grep: options.grep</span></span>
36
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span>
37
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">logs.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">forEach</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">line</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(line))</span></span></code></pre></div><p><code>readLogs</code>(<code>logger/index.ts:96-133</code>):读整个日志文件,可选按 Pino 数值 level 过滤(<code>LEVEL_MAP</code>),可选大小写不敏感的 substring 匹配。返回最近 <code>limit</code> 行。</p><h2 id="config" tabindex="-1">config <a class="header-anchor" href="#config" aria-label="Permalink to &quot;config&quot;">​</a></h2><p><code>commands/config.ts</code>:</p><ul><li><code>config show</code>:<code>loadConfig()</code> + <code>JSON.stringify(..., null, 2)</code></li><li><code>config set &lt;key&gt; &lt;value&gt;</code>:<code>key.split(&#39;.&#39;)</code> 逐层下探(<code>server.port</code> / <code>proxy.target</code> 等),保留类型(<code>typeof current[lastKey]</code> 决定 <code>parseInt</code> / <code>=== &#39;true&#39;</code> / 原样字符串),然后 <code>saveConfig(config)</code></li><li><code>config reset</code>:调 <code>resetConfig()</code>(<code>config/index.ts:43-64</code>)覆盖为默认配置</li></ul><p>任何非法 action 打印 <code>Invalid action. Use: show, set, reset</code>。</p><h2 id="reload" tabindex="-1">reload <a class="header-anchor" href="#reload" aria-label="Permalink to &quot;reload&quot;">​</a></h2><p><code>commands/reload.ts</code>:结构与 start 类似但不需要 <code>startProcess</code>:</p><ol><li><code>loadConfig</code> 拿 host/port</li><li><code>reloadProcess(&#39;cc-monitoring&#39;)</code>(<code>pm2.reload</code>,是零停机)</li><li><code>waitForOnline</code></li><li><code>waitForPort</code></li><li>打印 summary(不再打印 forwarding target)</li></ol><h2 id="test" tabindex="-1">test <a class="header-anchor" href="#test" aria-label="Permalink to &quot;test&quot;">​</a></h2><p><code>commands/test.ts</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> res</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fetch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(config.proxy.target, {</span></span>
38
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> method: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;HEAD&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
39
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> signal: AbortSignal.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">timeout</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">10000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
40
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})</span></span></code></pre></div><p>HEAD + 10 秒超时。打印 <code>Success! Target reachable. Status: &lt;code&gt;</code> 或 <code>Connection failed: &lt;msg&gt;</code>。</p><h2 id="ui" tabindex="-1">ui <a class="header-anchor" href="#ui" aria-label="Permalink to &quot;ui&quot;">​</a></h2><p><code>commands/ui.ts</code>:</p><ol><li><code>getProcessStatus</code>:未运行则报错并 return</li><li>计算 <code>uiDistPath</code>(<code>../../../ui/dist</code>——⚠️ 这个路径实际不指向 proxy-cli,是遗留 bug 但不影响主流程,因为 <code>--build</code> 才会用到,多数情况 proxy-cli 早已 build 过)</li><li>若 <code>--build</code> 或 dist 不存在:<code>execSync(&#39;pnpm --filter @proxy/ui build&#39;, ...)</code></li><li><code>open(base + &#39;/ui&#39;)</code>:动态 import <code>open</code>(ESM-only 库)</li></ol><p><code>open</code> 的选择让 macOS 用 <code>open</code> 命令、Linux 用 <code>xdg-open</code>、Windows 用 <code>start</code>。</p><h2 id="clean-requests-隐藏" tabindex="-1">clean-requests(隐藏) <a class="header-anchor" href="#clean-requests-隐藏" aria-label="Permalink to &quot;clean-requests(隐藏)&quot;">​</a></h2><p><code>cli/index.ts:63-78</code>:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">proxy</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> clean-requests</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --days</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 7</span></span></code></pre></div><p>动态 import <code>loadConfig</code> + <code>configureDbPath</code> + <code>cleanOldRequestsDB</code> 后:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> days</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> parseInt</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(options.days) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 默认 &#39;7&#39;</span></span>
41
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> cleanOldRequestsDB</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(days) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// DELETE FROM requests WHERE timestamp &lt; cutoff</span></span></code></pre></div><p><code>cleanOldRequestsDB</code> 在 <code>days &lt;= 0</code> 时直接 return(保留全部)。</p><h2 id="pm2-封装-utils-pm2-ts" tabindex="-1">PM2 封装(<code>utils/pm2.ts</code>) <a class="header-anchor" href="#pm2-封装-utils-pm2-ts" aria-label="Permalink to &quot;PM2 封装(`utils/pm2.ts`)&quot;">​</a></h2><p>所有 PM2 交互都通过 promisify:</p><table tabindex="0"><thead><tr><th>内部</th><th>对外</th></tr></thead><tbody><tr><td><code>pm2Connect / pm2Disconnect</code></td><td>每次调用后必须 disconnect,否则 daemon 会误以为持有客户端</td></tr><tr><td><code>pm2Start(options)</code></td><td>支持 string(ecosystem 路径) 或 object;错误可能是数组</td></tr><tr><td><code>pm2Stop / pm2Reload</code></td><td>单参 name</td></tr><tr><td><code>pm2List</code></td><td>返回原始 list</td></tr><tr><td><code>startProcess / stopProcess / reloadProcess</code></td><td>三合一(connect → op → disconnect)</td></tr><tr><td><code>waitForOnline(name, timeoutMs, intervalMs)</code></td><td>只在此函数内持有一次连接 + 轮询列表</td></tr><tr><td><code>getProcessStatus(name)</code></td><td>单次快照</td></tr></tbody></table><p><strong>为什么用 <code>createRequire</code></strong>:pm2 是 CJS,本文件是 ESM。<code>utils/pm2.ts:8-15</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> requireCjs</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> NodeRequire</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (() </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
42
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> createRequire</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">getCurrentModuleUrl</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()) } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> require }</span></span>
43
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})()</span></span>
44
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> pm2</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> requireCjs</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;pm2&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">as</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> any</span></span></code></pre></div><p><code>getCurrentModuleUrl()</code> 是 <code>esm-dirname.ts</code> 提供的包装器,避免直接写 <code>import.meta.url</code>(ts-jest CJS 编译会解析错)。fallback 是 CJS 环境(Jest)的 <code>require</code>。</p><h2 id="waitforport-细节-utils-net-ts" tabindex="-1"><code>waitForPort</code> 细节(<code>utils/net.ts</code>) <a class="header-anchor" href="#waitforport-细节-utils-net-ts" aria-label="Permalink to &quot;`waitForPort` 细节(`utils/net.ts`)&quot;">​</a></h2><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">for</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">let</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> attempt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; attempt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&lt;=</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 5</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; attempt</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">++</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
45
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> sleep</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(attempt </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">*</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 累计 1+2+3+4+5 = 15s</span></span>
46
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onAttempt</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">?.(attempt, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">5</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
47
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> tryConnect</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(target, port)) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> true</span></span>
48
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
49
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> false</span></span></code></pre></div><p><code>tryConnect</code> 是 <code>net.createConnection</code> 加 1s socket timeout;success/timeout/error 都 destroy 并 resolve。start / reload 命令都会传一个 <code>onAttempt</code> 回调,用 ora spinner 显示 <code>attempt X/5</code>。</p><h2 id="全局参数流转" tabindex="-1">全局参数流转 <a class="header-anchor" href="#全局参数流转" aria-label="Permalink to &quot;全局参数流转&quot;">​</a></h2><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span>proxy -c /tmp/my.json start</span></span>
50
+ <span class="line"><span> ↓</span></span>
51
+ <span class="line"><span>Commander preAction hook (index.ts:20-25)</span></span>
52
+ <span class="line"><span> ↓</span></span>
53
+ <span class="line"><span>setConfigPathOverride(&#39;/tmp/my.json&#39;) → paths.ts 内部变量</span></span>
54
+ <span class="line"><span> ↓</span></span>
55
+ <span class="line"><span>loadConfig()</span></span>
56
+ <span class="line"><span> ↓</span></span>
57
+ <span class="line"><span>getConfigPath() → 检查 override → 返回 &#39;/tmp/my.json&#39;</span></span></code></pre></div><p>同样机制适用于所有子命令。</p></div></div></main><footer class="VPDocFooter" data-v-b2c5ca34 data-v-2cae581d><!--[--><!--]--><!----><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-2cae581d><span class="visually-hidden" id="doc-footer-aria-label" data-v-2cae581d>Pager</span><div class="pager" data-v-2cae581d><a class="VPLink link pager-link prev" href="/docs/proxy-core/entry.html" data-v-2cae581d><!--[--><span class="desc" data-v-2cae581d>Previous page</span><span class="title" data-v-2cae581d>入口与启动</span><!--]--></a></div><div class="pager" data-v-2cae581d><a class="VPLink link pager-link next" href="/docs/proxy-core/proxy.html" data-v-2cae581d><!--[--><span class="desc" data-v-2cae581d>Next page</span><span class="title" data-v-2cae581d>代理转发</span><!--]--></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
58
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"index.md\":\"p9floL_p\",\"overview.md\":\"BKVdLT3o\",\"packages-utils.md\":\"CvgYp5Ll\",\"proxy-admin_env-and-build.md\":\"xkeQNYS3\",\"proxy-admin_index.md\":\"DBLI0n0G\",\"proxy-admin_layout-and-menu.md\":\"BKGcu49p\",\"proxy-admin_pages.md\":\"m_fGvvOH\",\"proxy-admin_routing-and-auth.md\":\"DZsdFese\",\"proxy-admin_services-and-mock.md\":\"sdNPcf25\",\"proxy-cli_api-layer.md\":\"GfdbtEUx\",\"proxy-cli_app-shell.md\":\"Do18CYhW\",\"proxy-cli_components-common.md\":\"Dd6Yazvz\",\"proxy-cli_components-config.md\":\"B81Y3ta2\",\"proxy-cli_components-requests.md\":\"vN8IrwL_\",\"proxy-cli_components-stats.md\":\"B90esaNa\",\"proxy-cli_components-status.md\":\"C5lAzS2c\",\"proxy-cli_data-hooks.md\":\"w9Oe1OD3\",\"proxy-cli_index.md\":\"BA6g8QD-\",\"proxy-cli_utils-and-i18n.md\":\"Ch_e-g_o\",\"proxy-core_chat-api.md\":\"DHihiBxR\",\"proxy-core_cli.md\":\"DCFYX4Bd\",\"proxy-core_config.md\":\"BXSOyxYE\",\"proxy-core_data-layer.md\":\"Cdomb3Gz\",\"proxy-core_entry.md\":\"BZmIcCUM\",\"proxy-core_index.md\":\"BM6VV5Qe\",\"proxy-core_pm2.md\":\"DUhWEtgn\",\"proxy-core_providers.md\":\"CbDZ6b_7\",\"proxy-core_proxy.md\":\"CzQYmX6X\",\"proxy-core_stats.md\":\"BsM6wuK_\",\"proxy-core_tool.md\":\"B6Le1nQr\",\"proxy-core_ui-routes.md\":\"Dyqkeoiv\",\"proxy-core_utilities.md\":\"C18pjnkz\",\"quickstart.md\":\"Cy_FmXIY\",\"request-flow.md\":\"C1fyxdPE\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"CC Monitoring\",\"description\":\"Claude Code 代理 + 监控系统文档\",\"base\":\"/docs/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"nav\":[{\"text\":\"概览\",\"link\":\"/overview\"},{\"text\":\"快速开始\",\"link\":\"/quickstart\"},{\"text\":\"Proxy Core\",\"link\":\"/proxy-core/\"},{\"text\":\"Proxy CLI\",\"link\":\"/proxy-cli/\"},{\"text\":\"Proxy Admin\",\"link\":\"/proxy-admin/\"}],\"sidebar\":{\"/proxy-core/\":[{\"text\":\"Proxy Core\",\"items\":[{\"text\":\"模块概览\",\"link\":\"/proxy-core/\"},{\"text\":\"入口与启动\",\"link\":\"/proxy-core/entry\"},{\"text\":\"CLI 命令\",\"link\":\"/proxy-core/cli\"},{\"text\":\"代理转发\",\"link\":\"/proxy-core/proxy\"},{\"text\":\"UI 路由\",\"link\":\"/proxy-core/ui-routes\"},{\"text\":\"供应商管理\",\"link\":\"/proxy-core/providers\"},{\"text\":\"配置与日志\",\"link\":\"/proxy-core/config\"},{\"text\":\"数据层\",\"link\":\"/proxy-core/data-layer\"},{\"text\":\"统计与历史\",\"link\":\"/proxy-core/stats\"},{\"text\":\"工具注入\",\"link\":\"/proxy-core/tool\"},{\"text\":\"PM2 集成\",\"link\":\"/proxy-core/pm2\"},{\"text\":\"工具函数\",\"link\":\"/proxy-core/utilities\"},{\"text\":\"Chat API\",\"link\":\"/proxy-core/chat-api\"}]}],\"/proxy-cli/\":[{\"text\":\"Proxy CLI\",\"items\":[{\"text\":\"模块概览\",\"link\":\"/proxy-cli/\"},{\"text\":\"应用外壳\",\"link\":\"/proxy-cli/app-shell\"},{\"text\":\"数据 Hooks\",\"link\":\"/proxy-cli/data-hooks\"},{\"text\":\"API 层\",\"link\":\"/proxy-cli/api-layer\"},{\"text\":\"状态组件\",\"link\":\"/proxy-cli/components-status\"},{\"text\":\"统计组件\",\"link\":\"/proxy-cli/components-stats\"},{\"text\":\"请求组件\",\"link\":\"/proxy-cli/components-requests\"},{\"text\":\"配置组件\",\"link\":\"/proxy-cli/components-config\"},{\"text\":\"通用组件\",\"link\":\"/proxy-cli/components-common\"},{\"text\":\"工具与国际化\",\"link\":\"/proxy-cli/utils-and-i18n\"}]}],\"/proxy-admin/\":[{\"text\":\"Proxy Admin\",\"items\":[{\"text\":\"模块概览\",\"link\":\"/proxy-admin/\"},{\"text\":\"路由与认证\",\"link\":\"/proxy-admin/routing-and-auth\"},{\"text\":\"布局与菜单\",\"link\":\"/proxy-admin/layout-and-menu\"},{\"text\":\"页面\",\"link\":\"/proxy-admin/pages\"},{\"text\":\"服务与 Mock\",\"link\":\"/proxy-admin/services-and-mock\"},{\"text\":\"环境与构建\",\"link\":\"/proxy-admin/env-and-build\"}]}]},\"siteTitle\":\"CC Monitoring\",\"search\":{\"provider\":\"local\"}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
59
+
60
+ </body>
61
+ </html>