@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,23 @@
1
+ import{_ as i,o as a,c as t,a2 as e}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"proxy-cli / 通用组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-common.md","filePath":"proxy-cli/components-common.md"}'),n={name:"proxy-cli/components-common.md"};function h(l,s,p,d,k,r){return a(),t("div",null,[...s[0]||(s[0]=[e(`<h1 id="proxy-cli-通用组件" tabindex="-1">proxy-cli / 通用组件 <a class="header-anchor" href="#proxy-cli-通用组件" aria-label="Permalink to &quot;proxy-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-cli/src/components/Tabs.tsx</code></li><li><code>apps/proxy-cli/src/components/MethodTag.tsx</code></li><li><code>apps/proxy-cli/src/components/ModelTag.tsx</code></li><li><code>apps/proxy-cli/src/components/ShikiHighlighter.tsx</code></li><li><code>apps/proxy-cli/src/components/LanguageSwitcher.tsx</code></li><li><code>apps/proxy-cli/src/components/GlowCard.tsx</code>(已在 <a href="./components-stats.html#glowcard">components-stats.md</a> 详述,本文只列引用点)</li></ul><h2 id="tabs" tabindex="-1">Tabs <a class="header-anchor" href="#tabs" aria-label="Permalink to &quot;Tabs&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/Tabs.tsx</code>。轻量 tab 容器:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Props</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
2
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> tabs</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">label</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }[]</span></span>
3
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> defaultTab</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
4
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> children</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">React</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">ReactNode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt; </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// key = tab.id</span></span>
5
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li>内部 <code>activeTab</code> state</li><li>tab 栏:横向 button 列,激活项底部 2px 边线 + 前景色变化</li><li>内容区:<code>children[activeTab]</code></li></ul><p>使用点:<code>RequestCard</code>(Headers/Body/reqHeaders/resBody 四 tab) + <code>RequestCompareModal</code>。</p><p><strong>约束</strong>:<code>children</code> 是对象而非 React children,key 必须精确匹配 <code>tabs[].id</code>。</p><h2 id="methodtag" tabindex="-1">MethodTag <a class="header-anchor" href="#methodtag" aria-label="Permalink to &quot;MethodTag&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/MethodTag.tsx</code>。HTTP method 徽章。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Props</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">method</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">statusCode</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span></code></pre></div><ul><li><strong>无 statusCode</strong>:按 method 上色 —— GET 绿、POST 蓝、PUT/PATCH 琥珀、DELETE 红、HEAD/OPTIONS 灰</li><li><strong>有 statusCode</strong>:<strong>覆盖</strong> method 色 —— 2xx 绿、非 2xx 红</li></ul><p>设计意图:请求列表里 method 一眼分类;status 出错时更醒目(红色覆盖蓝色 POST)。</p><h2 id="modeltag" tabindex="-1">ModelTag <a class="header-anchor" href="#modeltag" aria-label="Permalink to &quot;ModelTag&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/ModelTag.tsx</code>。极简:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ModelTag</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> JSX</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">Element</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
6
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span></span>
7
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">span</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> className</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;px-2 py-0.5 text-xs font-semibold rounded border bg-purple-500/20 text-purple-600 border-purple-500/30&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
8
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {model}</span></span>
9
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">span</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
10
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )</span></span>
11
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>紫色徽章。用在 <code>RequestCard</code> 头部显示转发后的 model。</p><h2 id="shikihighlighter" tabindex="-1">ShikiHighlighter <a class="header-anchor" href="#shikihighlighter" aria-label="Permalink to &quot;ShikiHighlighter&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/ShikiHighlighter.tsx</code>。JSON/Markdown 语法高亮。</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Props</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
12
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
13
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> lang</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;json&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> |</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;markdown&#39;</span></span>
14
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> theme</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // 默认 &#39;github-dark&#39;</span></span>
15
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
16
+ <span class="line"></span>
17
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ShikiHighlighter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">code</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">lang</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">theme</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;github-dark&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Props</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
18
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">html</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setHtml</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
19
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useEffect</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 style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">codeToHtml</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(code, { lang, theme }).</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">then</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(setHtml) }, [code, lang, theme])</span></span>
20
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> className</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;max-h-[400px] overflow-y-auto ...&quot;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> dangerouslySetInnerHTML</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{ __html: html }} /&gt;</span></span>
21
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li><strong>异步渲染</strong>:<code>codeToHtml</code> 是 async,首次 render 是空 div,第二次 render 有内容</li><li><strong>容器最大高度 400px</strong>:防止巨型 JSON 拉长页面,超出滚动</li><li><strong><code>dangerouslySetInnerHTML</code></strong>:Shiki 产出的 HTML 已经 escape,安全</li><li><strong>样式复写</strong>:<code>[&amp;_pre]:m-0 [&amp;_pre]:p-0 [&amp;_pre]:bg-transparent</code> 移除 Shiki 自带样式</li></ul><p>Shiki 4 采用 bundled themes/languages,<code>github-dark</code> 主题打包体积友好。</p><h2 id="languageswitcher" tabindex="-1">LanguageSwitcher <a class="header-anchor" href="#languageswitcher" aria-label="Permalink to &quot;LanguageSwitcher&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/LanguageSwitcher.tsx</code>:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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:#6F42C1;--shiki-dark:#B392F0;"> toggleLanguage</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>
22
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> i18n.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">changeLanguage</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(i18n.language </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;zh&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;en&#39;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;zh&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
23
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>按钮显示<strong>对面</strong>语言(当前中文 → 显示 <code>EN</code>,反之显示 <code>中</code>)+ <code>Languages</code> 图标。title tooltip 是完整语言名。</p><h2 id="glowcard" tabindex="-1">GlowCard <a class="header-anchor" href="#glowcard" aria-label="Permalink to &quot;GlowCard&quot;">​</a></h2><p>见 <a href="./components-stats.html#glowcard">components-stats.md</a>。用在:</p><ul><li><code>TodayStatsCards</code>(5 张彩色卡)</li><li><code>ConfigEditor</code>(Address 蓝 + ConfigPath 绿)</li></ul><h2 id="通用视觉规范" tabindex="-1">通用视觉规范 <a class="header-anchor" href="#通用视觉规范" aria-label="Permalink to &quot;通用视觉规范&quot;">​</a></h2><p>从多处组件汇总:</p><table tabindex="0"><thead><tr><th>用途</th><th>颜色</th><th>语义 CSS 变量</th></tr></thead><tbody><tr><td>主背景</td><td>深灰</td><td><code>bg-primary</code></td></tr><tr><td>次背景</td><td>更深灰</td><td><code>bg-secondary</code></td></tr><tr><td>卡片背景</td><td>中灰</td><td><code>bg-card</code></td></tr><tr><td>hover</td><td>浅灰</td><td><code>bg-hover</code></td></tr><tr><td>主文字</td><td>白色</td><td><code>text-primary</code></td></tr><tr><td>次文字</td><td>中灰</td><td><code>text-muted</code></td></tr><tr><td>三级文字</td><td>深灰</td><td><code>text-secondary</code></td></tr><tr><td>边框</td><td>深灰</td><td><code>border</code></td></tr><tr><td>主色/品牌</td><td>蓝 <code>#3B82F6</code></td><td><code>primary</code></td></tr><tr><td>成功</td><td>绿</td><td><code>success</code></td></tr><tr><td>警告</td><td>黄/橙</td><td><code>warning</code></td></tr><tr><td>错误</td><td>红</td><td><code>error</code></td></tr><tr><td>强调</td><td>青</td><td><code>accent</code></td></tr></tbody></table><p><code>TOKEN_COLORS</code> 中的四色专用于 Token 分类:</p><ul><li>Input = Primary 蓝</li><li>Output = Success 绿</li><li>Cache Read = Warning 橙</li><li>Cache Create = Info 青蓝</li></ul><h2 id="相关" tabindex="-1">相关 <a class="header-anchor" href="#相关" aria-label="Permalink to &quot;相关&quot;">​</a></h2><ul><li>主 Layout → <a href="./app-shell.html">app-shell.md</a></li><li>Chart 主题 → <a href="./components-status.html#chart-theme">components-status.md</a></li></ul>`,37)])])}const g=i(n,[["render",h]]);export{c as __pageData,g as default};
@@ -0,0 +1 @@
1
+ import{_ as i,o as a,c as t,a2 as e}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"proxy-cli / 通用组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-common.md","filePath":"proxy-cli/components-common.md"}'),n={name:"proxy-cli/components-common.md"};function h(l,s,p,d,k,r){return a(),t("div",null,[...s[0]||(s[0]=[e("",37)])])}const g=i(n,[["render",h]]);export{c as __pageData,g as default};
@@ -0,0 +1,46 @@
1
+ import{_ as i,o as a,c as e,a2 as n}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"proxy-cli / 配置类组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-config.md","filePath":"proxy-cli/components-config.md"}'),t={name:"proxy-cli/components-config.md"};function l(p,s,h,r,o,d){return a(),e("div",null,[...s[0]||(s[0]=[n(`<h1 id="proxy-cli-配置类组件" tabindex="-1">proxy-cli / 配置类组件 <a class="header-anchor" href="#proxy-cli-配置类组件" aria-label="Permalink to &quot;proxy-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-cli/src/components/ConfigEditor.tsx</code></li><li><code>apps/proxy-cli/src/components/ProviderManagerModal.tsx</code></li><li><code>apps/proxy-cli/src/types/providers.ts</code></li><li><code>apps/proxy-cli/src/api/providers.ts</code></li></ul><h2 id="configeditor" tabindex="-1">ConfigEditor <a class="header-anchor" href="#configeditor" aria-label="Permalink to &quot;ConfigEditor&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/ConfigEditor.tsx</code>。右侧下半部分——<strong>当前实现只显示两个只读地址卡 + 两个按钮</strong>(重启 + 供应商管理),不再直接编辑 JSON 字段(历史版本曾有完整字段编辑器,现被 <code>ProviderManagerModal</code> + 「直接改文件」的模式取代)。</p><h3 id="ui-结构" tabindex="-1">UI 结构 <a class="header-anchor" href="#ui-结构" aria-label="Permalink to &quot;UI 结构&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>┌ 配置 [重启] [🗄️]</span></span>
2
+ <span class="line"><span>│ ┌ 服务器</span></span>
3
+ <span class="line"><span>│ │ ┌ GlowCard(input) 地址 http://localhost:9527 ┐</span></span>
4
+ <span class="line"><span>│ │ ┌ GlowCard(output) 配置路径 ~/.cc-monitoring ┐</span></span></code></pre></div><ul><li>顶部 heading + 两个按钮:<code>RefreshCw</code> 图标(重启) + <code>DatabaseZap</code> 图标(供应商)</li><li>两张 <code>GlowCard</code>:Address(蓝框)+ ConfigPath(绿框)</li><li>Address 硬编码 <code>http://localhost:9527</code>(<strong>未从 config 动态取</strong>——遗留 hardcode)</li><li>ConfigPath 用 <code>configPath.replace(/\\/config\\.json$/, &#39;&#39;)</code> 去尾巴显示目录部分;未加载时显示 <code>~/.cc-monitoring</code></li></ul><h3 id="重启流程-handlerestart" tabindex="-1">重启流程 <code>handleRestart</code> <a class="header-anchor" href="#重启流程-handlerestart" aria-label="Permalink to &quot;重启流程 \`handleRestart\`&quot;">​</a></h3><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;">sequenceDiagram</span></span>
5
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> actor U as 用户</span></span>
6
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant BTN as 重启按钮</span></span>
7
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant API as controlProcess</span></span>
8
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant P as 轮询循环</span></span>
9
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> participant S as fetchStatus</span></span>
10
+ <span class="line"></span>
11
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> U-&gt;&gt;BTN: click</span></span>
12
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> BTN-&gt;&gt;BTN: setIsRestarting(true), setMessage(&#39;重启中&#39;)</span></span>
13
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> BTN-&gt;&gt;API: controlProcess(&#39;restart&#39;)</span></span>
14
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Note over API: 后端 setTimeout 1000ms 再 reload</span></span>
15
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> BTN-&gt;&gt;BTN: 前端再等 2000ms</span></span>
16
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> BTN-&gt;&gt;P: setInterval 每 800ms</span></span>
17
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> loop 每 800ms</span></span>
18
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> P-&gt;&gt;S: fetchStatus()</span></span>
19
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> S--&gt;&gt;P: {status, cpu, ...}</span></span>
20
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> alt elapsed &gt;= 3000 AND status=online</span></span>
21
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> P-&gt;&gt;P: clearInterval, setSuccess, 3s 后清消息</span></span>
22
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> else</span></span>
23
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> P-&gt;&gt;P: 继续轮询</span></span>
24
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
25
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> end</span></span>
26
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Note over BTN: 45s 超时保护</span></span></code></pre></div><p>关键实现细节:</p><ul><li><strong>前端等待 2s + 至少再等 3s</strong>:即使 PM2 快速重启(&lt;3s),也强制看到&quot;重启中&quot;至少 5s,避免闪烁</li><li><strong><code>elapsed &gt;= minWaitTime</code> 才检查 online</strong>:防止早期观测到&quot;上一个进程还在&quot; 误判成功</li><li><strong>800ms 轮询间隔</strong>:兼顾响应速度和请求密度</li><li><strong>45s 超时兜底</strong>:任何异常都不会永久卡在&quot;重启中&quot;</li><li><strong><code>controlProcess</code> 请求失败也继续轮询</strong>:重启过程中 API 可能不可达</li><li><strong><code>setIsRestarting(current =&gt; ...)</code></strong>:函数式 setState,从超时定时器里读最新值</li></ul><h3 id="供应商弹窗" tabindex="-1">供应商弹窗 <a class="header-anchor" href="#供应商弹窗" aria-label="Permalink to &quot;供应商弹窗&quot;">​</a></h3><p><code>isProviderModalOpen</code> 控制 <code>&lt;ProviderManagerModal&gt;</code> 的显隐。</p><h2 id="providermanagermodal" tabindex="-1">ProviderManagerModal <a class="header-anchor" href="#providermanagermodal" aria-label="Permalink to &quot;ProviderManagerModal&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/ProviderManagerModal.tsx</code>。全屏 modal + 表格编辑器。</p><h3 id="数据流" tabindex="-1">数据流 <a class="header-anchor" href="#数据流" aria-label="Permalink to &quot;数据流&quot;">​</a></h3><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>
27
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> OPEN[isOpen 变 true] --&gt; FETCH[fetchProviders]</span></span>
28
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> FETCH --&gt; ROWS[rows: ProviderInput 数组]</span></span>
29
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ROWS --&gt; EDIT[表格逐格编辑]</span></span>
30
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> EDIT --&gt; SAVE_BTN[点击保存]</span></span>
31
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SAVE_BTN --&gt; VALIDATE[saveProviders]</span></span>
32
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> VALIDATE --&gt; RESULT{result}</span></span>
33
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESULT -- success --&gt; TOAST_OK[成功 toast, 3s 后清]</span></span>
34
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESULT -- errors --&gt; LIST_ERR[分行显示 fieldMessage]</span></span>
35
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RESULT -- error --&gt; TOAST_ERR[单条错误 toast]</span></span></code></pre></div><h3 id="字段" tabindex="-1">字段 <a class="header-anchor" href="#字段" aria-label="Permalink to &quot;字段&quot;">​</a></h3><p><code>FIELDS</code> 常量列 9 列(<code>ProviderManagerModal.tsx:24-34</code>):</p><p><code>name</code> / <code>base_url</code> / <code>api_key</code> / <code>model</code> / <code>haiku_model</code> / <code>sonnet_model</code> / <code>opus_model</code> / <code>subagent_model</code> / <code>provider</code></p><ul><li>一列操作按钮(激活 / 删除)。</li></ul><p><code>EMPTY_ROW</code> 是所有字段空串 + <code>default: false</code>。</p><h3 id="行为" tabindex="-1">行为 <a class="header-anchor" href="#行为" aria-label="Permalink to &quot;行为&quot;">​</a></h3><ul><li><strong>添加行</strong>:<code>handleAddRow</code> push 一个 <code>EMPTY_ROW</code> 副本</li><li><strong>删除行</strong>:<code>window.confirm(...)</code> 确认后从数组 filter 掉</li><li><strong>激活</strong>:<code>handleActivate(index)</code> 把所有行的 <code>default</code> 置 false,仅指定行 true——保证唯一</li><li><strong>字段编辑</strong>:受控 <code>&lt;input&gt;</code>,每次 change 生成新数组</li><li><strong>保存</strong>:<code>saveProviders(rows)</code> 全量提交;成功清空错误、显示 toast;错误 <code>errors</code> 数组按 <code>{row, field, message}</code> 格式化显示</li></ul><h3 id="providertoinput" tabindex="-1"><code>providerToInput</code> <a class="header-anchor" href="#providertoinput" aria-label="Permalink to &quot;\`providerToInput\`&quot;">​</a></h3><p>后端 <code>Provider</code> 类型的 <code>base_url</code> 等字段是 <code>string | null</code>——前端为方便 <code>&lt;input&gt;</code> 绑定,把 null 一律转为空串(<code>ProviderManagerModal.tsx:36-49</code>)。</p><h3 id="formaterrors" tabindex="-1"><code>formatErrors</code> <a class="header-anchor" href="#formaterrors" aria-label="Permalink to &quot;\`formatErrors\`&quot;">​</a></h3><p>用 i18n key <code>providers:error.fieldMessage</code> 拼装 <code>第 X 行: field 校验消息</code>。</p><h3 id="自动清除-toast" tabindex="-1">自动清除 toast <a class="header-anchor" href="#自动清除-toast" aria-label="Permalink to &quot;自动清除 toast&quot;">​</a></h3><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:#6F42C1;--shiki-dark:#B392F0;">useEffect</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>
36
+ <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;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">message </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> messageType </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!==</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;success&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span></span>
37
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> timer</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setTimeout</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 style="--shiki-light:#D73A49;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (mountedRef.current) </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setMessage</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) }, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">3000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
38
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> () </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> clearTimeout</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(timer)</span></span>
39
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}, [message, messageType])</span></span></code></pre></div><ul><li>只有 success toast 3s 后自动消失;error 常驻直到用户下一次操作</li><li><code>mountedRef</code> 保护 unmount 后 setState</li></ul><h3 id="关闭-modal-的三种方式" tabindex="-1">关闭 modal 的三种方式 <a class="header-anchor" href="#关闭-modal-的三种方式" aria-label="Permalink to &quot;关闭 modal 的三种方式&quot;">​</a></h3><ul><li>点右上角 <code>Close</code> 按钮</li><li>点底部第二个 <code>Close</code> 按钮</li><li>点遮罩背景(<code>onClick</code> handler 判断 <code>e.target === e.currentTarget</code>)</li></ul><h2 id="与后端的契约" tabindex="-1">与后端的契约 <a class="header-anchor" href="#与后端的契约" aria-label="Permalink to &quot;与后端的契约&quot;">​</a></h2><p>见 <a href="./../proxy-core/providers.html">../proxy-core/providers.md</a>。重点:</p><ul><li>POST <code>/ui/api/providers</code> <strong>需要 Bearer 认证</strong>(当 <code>config.auth.token</code> 或 <code>UI_AUTH_TOKEN</code> 设置时)</li><li>目前前端<strong>不发</strong> Authorization 头 —— 生产环境启用认证后此功能会 401</li><li>Destructive replace:整个表格提交即全量替换后端 providers 表内容</li></ul><h2 id="类型" tabindex="-1">类型 <a class="header-anchor" href="#类型" aria-label="Permalink to &quot;类型&quot;">​</a></h2><p><code>apps/proxy-cli/src/types/providers.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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Provider</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
40
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> id</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">name</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">base_url</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">api_key</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">model</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
41
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> haiku_model</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">sonnet_model</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">opus_model</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">subagent_model</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
42
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> provider</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">default</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">created_at</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">updated_at</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ProviderInput</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;">Provider without id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">/</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">timestamps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
45
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ProviderValidationError</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">index</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">field</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">message</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
46
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ProviderSaveResult</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">success</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">errors</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">error</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span></code></pre></div><p><code>Provider</code> 和后端返回结构一致;<code>ProviderInput</code> 是前端提交时的形状(同结构,仅所有字段可选空串)。</p><h2 id="相关" tabindex="-1">相关 <a class="header-anchor" href="#相关" aria-label="Permalink to &quot;相关&quot;">​</a></h2><ul><li>后端 SQLite 全量替换实现 → <a href="./../proxy-core/providers.html#saveproviders-db-providers">../proxy-core/providers.md</a></li><li>API 客户端 → <a href="./api-layer.html#saveproviders-providers">api-layer.md</a></li><li>通用组件(GlowCard 等) → <a href="./components-common.html">components-common.md</a></li></ul>`,43)])])}const E=i(t,[["render",l]]);export{c as __pageData,E as default};
@@ -0,0 +1 @@
1
+ import{_ as i,o as a,c as e,a2 as n}from"./chunks/framework.D_Xv2a7c.js";const c=JSON.parse('{"title":"proxy-cli / 配置类组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-config.md","filePath":"proxy-cli/components-config.md"}'),t={name:"proxy-cli/components-config.md"};function l(p,s,h,r,o,d){return a(),e("div",null,[...s[0]||(s[0]=[n("",43)])])}const E=i(t,[["render",l]]);export{c as __pageData,E as default};
@@ -0,0 +1,84 @@
1
+ import{_ as i,o as a,c as n,a2 as h}from"./chunks/framework.D_Xv2a7c.js";const g=JSON.parse('{"title":"proxy-cli / 请求类组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-requests.md","filePath":"proxy-cli/components-requests.md"}'),t={name:"proxy-cli/components-requests.md"};function l(k,s,e,p,r,d){return a(),n("div",null,[...s[0]||(s[0]=[h(`<h1 id="proxy-cli-请求类组件" tabindex="-1">proxy-cli / 请求类组件 <a class="header-anchor" href="#proxy-cli-请求类组件" aria-label="Permalink to &quot;proxy-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-cli/src/components/RequestHistory.tsx</code></li><li><code>apps/proxy-cli/src/components/RequestCard.tsx</code></li><li><code>apps/proxy-cli/src/components/RequestCompareModal.tsx</code></li><li><code>apps/proxy-cli/src/components/DiffPanel.tsx</code></li><li><code>apps/proxy-cli/src/components/ParsedResponseBlocks.tsx</code></li><li><code>apps/proxy-cli/src/utils/parse-events.ts</code></li></ul><h2 id="requesthistory" tabindex="-1">RequestHistory <a class="header-anchor" href="#requesthistory" aria-label="Permalink to &quot;RequestHistory&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/RequestHistory.tsx</code>。左侧主区,功能:</p><ol><li>按 <code>sessionId</code> <strong>保序</strong>分组</li><li>每组可折叠展开(点击 chip)</li><li>单卡展开显示详情(Headers / Body / Events)</li><li>勾选任意两条 → 「对比」按钮亮起 → 打开 <code>RequestCompareModal</code></li></ol><h3 id="保序分组" tabindex="-1">保序分组 <a class="header-anchor" href="#保序分组" aria-label="Permalink to &quot;保序分组&quot;">​</a></h3><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;"> sessionGroups</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">sessionId</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">items</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>
2
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> groupIndex</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;"> Map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">number</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;()</span></span>
3
+ <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;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> summary</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> of</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> requests) { </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// requests 已按 timestamp 倒序</span></span>
4
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> idx</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> groupIndex.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">get</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(summary.sessionId)</span></span>
5
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (idx </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> undefined</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
6
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> groupIndex.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">set</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(summary.sessionId, sessionGroups.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">length</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
7
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sessionGroups.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">push</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ sessionId, items: [summary] })</span></span>
8
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">else</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
9
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sessionGroups[idx].items.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">push</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(summary)</span></span>
10
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
11
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li>遍历时保持 <code>requests</code> 数组顺序 → 组内自然倒序</li><li>最新活跃 session(该 session 最新请求最靠前)先被创建 → 组顺序也按活跃度倒序</li></ul><h3 id="分组头" tabindex="-1">分组头 <a class="header-anchor" href="#分组头" aria-label="Permalink to &quot;分组头&quot;">​</a></h3><p>每 session 分隔条:<code>─── &lt;sessionId&gt; [&lt;count&gt;] ───</code>。点数字 chip 展开/收起该组(<code>expandedSessions: Set&lt;string&gt;</code>)。</p><h3 id="选中与对比" tabindex="-1">选中与对比 <a class="header-anchor" href="#选中与对比" aria-label="Permalink to &quot;选中与对比&quot;">​</a></h3><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:#24292E;--shiki-dark:#E1E4E8;"> [</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">selectedIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">setSelectedIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useState</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[]&gt;([])</span></span>
12
+ <span class="line"></span>
13
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">handleToggleSelect</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(id) {</span></span>
14
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setSelectedIds</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">prev</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
15
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (prev.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">includes</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(id)) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> prev.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">filter</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">x</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> x </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!==</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> id)</span></span>
16
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (prev.</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;"> 2</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;"> [prev[</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], id] </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// FIFO:满 2 时淘汰最早</span></span>
17
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</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;">prev, id]</span></span>
18
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
19
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li>上限 2;达到上限后新选择挤掉最早</li><li>「Compare」按钮 <code>disabled</code> 直到 <code>selectedIds.length === 2</code></li><li>打开 modal,关闭时清空选择</li></ul><h3 id="单卡展开" tabindex="-1">单卡展开 <a class="header-anchor" href="#单卡展开" aria-label="Permalink to &quot;单卡展开&quot;">​</a></h3><p><code>expandedCardId: string | null</code> —— <strong>只允许一张卡同时展开</strong>(避免多个 Shiki 高亮同时挂)。</p><h2 id="requestcard" tabindex="-1">RequestCard <a class="header-anchor" href="#requestcard" aria-label="Permalink to &quot;RequestCard&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/RequestCard.tsx</code>。一条请求的展现。</p><h3 id="头部-始终显示" tabindex="-1">头部(始终显示) <a class="header-anchor" href="#头部-始终显示" aria-label="Permalink to &quot;头部(始终显示)&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>[MM-DD HH:mm:ss] [MethodTag] /v1/messages [TokenBarChart] 3.2s [ModelTag] ▸</span></span></code></pre></div><ul><li>时间戳 <code>formatTime(timestamp, &#39;monthDayTime&#39;)</code></li><li><code>MethodTag</code>:GET/POST 底色 + 状态码染色(2xx 绿、非 2xx 红)</li><li>路径</li><li><code>TokenBarChart</code>:微型四柱条(input/output/cacheRead/cacheCreate)</li><li><code>formatDuration</code>:<code>(ms / 1000).toFixed(1)</code>s</li><li><code>ModelTag</code>:紫色 tag</li><li>展开三角</li></ul><p>复选框 <code>onToggleSelect</code> 传入时才显示。</p><h3 id="展开加载" tabindex="-1">展开加载 <a class="header-anchor" href="#展开加载" aria-label="Permalink to &quot;展开加载&quot;">​</a></h3><p>点击头部 → <code>handleExpand()</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;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (isExpanded) { </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">onCollapse</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;"> }</span></span>
20
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">setLoading</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
21
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">try</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
22
+ <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;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`/ui/api/requests/\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">summary</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">compositeId</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
23
+ <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;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">res.ok) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">throw</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> new</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Error</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`HTTP \${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">res</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">status</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
24
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> data</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> RequestDetails</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> res.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">json</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
25
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setDetails</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(data)</span></span>
26
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onExpand</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">?.()</span></span>
27
+ <span class="line"><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;"> (err) {</span></span>
28
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> setError</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>
29
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onExpand</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">?.() </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// 仍展开,显示错误</span></span>
30
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>请求 <code>GET /ui/api/requests/:compositeId</code> 拿完整详情(含 headers/body/events)。失败时展开显示错误块 + 重试按钮。</p><h3 id="展开体-tabs-懒渲染" tabindex="-1">展开体(Tabs + 懒渲染) <a class="header-anchor" href="#展开体-tabs-懒渲染" aria-label="Permalink to &quot;展开体(Tabs + 懒渲染)&quot;">​</a></h3><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">&lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ref</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{detailRef}&gt;</span></span>
31
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {inView </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span></span>
32
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">Tabs</span></span>
33
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> tabs</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{[</span></span>
34
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;reqHeaders&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;请求 Headers&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
35
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;reqBody&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;请求 Body&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
36
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;resHeaders&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;响应 Headers&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
37
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { id: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;resBody&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;响应 Body&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
38
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ]}</span></span>
39
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defaultTab</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;reqHeaders&quot;</span></span>
40
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> children</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{{</span></span>
41
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> reqHeaders: &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">ShikiHighlighter</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">JSON</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">stringify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(headers, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)} </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">lang</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;json&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;,</span></span>
42
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> reqBody: &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">ShikiHighlighter</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">JSON</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">stringify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(body, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)} </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">lang</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;json&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;,</span></span>
43
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> resHeaders: &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">ShikiHighlighter</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">JSON</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">stringify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(resHeaders, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)} </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">lang</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;json&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;,</span></span>
44
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> resBody: &lt;&gt;</span></span>
45
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">ParsedResponseBlocks</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> events</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{events} /&gt;</span></span>
46
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">details</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;&lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">summary</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;原始 Events ({events.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">length</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">})&lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">summary</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
47
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {events.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">map</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">event</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">ShikiHighlighter</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> code</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">JSON</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">stringify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(event, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)} </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">lang</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;json&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;)}</span></span>
48
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">details</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
49
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;/&gt;</span></span>
50
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }}</span></span>
51
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> /&gt;</span></span>
52
+ <span class="line"><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>
53
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;滚动到此处显示详情...&lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span>
54
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> )}</span></span>
55
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span></code></pre></div><ul><li><code>useInViewControl</code> 提供 <code>ref + inView</code>:卡片展开但仍在视口外时,<code>inView=false</code>,不渲染 tabs(因 Shiki 是重组件)</li><li>视口内滚动到时才真正渲染</li></ul><h3 id="三种响应体展示" tabindex="-1">三种响应体展示 <a class="header-anchor" href="#三种响应体展示" aria-label="Permalink to &quot;三种响应体展示&quot;">​</a></h3><p><code>resBody</code> 里按可用性分三档:</p><ol><li><strong>有 events</strong>:<code>ParsedResponseBlocks</code>(结构化)+ 折叠的「原始 Events」</li><li><strong>有 error</strong>:显示错误块</li><li><strong>都无</strong>:显示&quot;无数据&quot;</li></ol><h2 id="parsedresponseblocks" tabindex="-1">ParsedResponseBlocks <a class="header-anchor" href="#parsedresponseblocks" aria-label="Permalink to &quot;ParsedResponseBlocks&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/ParsedResponseBlocks.tsx</code>。把 SSE events 数组解析后<strong>分类显示</strong>:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;"> parsed</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> parseEvents</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(events)</span></span></code></pre></div><p>三个块(有则显示):</p><ol><li><strong>🤔 AI 思考过程</strong>(<code>thinking</code>):蓝色区,<code>whitespace-pre-wrap</code> 保留换行</li><li><strong>💬 AI 回复内容</strong>(<code>text</code>):绿色区,<code>&lt;ReactMarkdown&gt;</code> 渲染 Markdown(含 typography)</li><li><strong>🔧 工具调用</strong>(<code>toolCalls</code>):紫色区,每个 tool 显示 <code>name (id)</code> + <code>&lt;ShikiHighlighter lang=&quot;json&quot;&gt;</code> 参数</li></ol><h2 id="parse-events" tabindex="-1">parse-events <a class="header-anchor" href="#parse-events" aria-label="Permalink to &quot;parse-events&quot;">​</a></h2><p><code>apps/proxy-cli/src/utils/parse-events.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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> ParsedResponse</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
56
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> thinking</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
57
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> text</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
58
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> toolCalls</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Array</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;{ </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">name</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">input</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">any</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt; }&gt;</span></span>
59
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> usage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">inputTokens</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">outputTokens</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">cacheReadTokens</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
60
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> stopReason</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
61
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>流程:</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>
62
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> E[events 数组] --&gt; LOOP{event.type}</span></span>
63
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP -- message_start --&gt; USAGE_IN[usage.inputTokens = message.usage.input_tokens]</span></span>
64
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP -- content_block_start --&gt; BLOCK[blocks.set index &amp;lbrace;type, content:&#39;&#39;, id, name&amp;rbrace;]</span></span>
65
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP -- content_block_delta --&gt; DELTA{delta.type}</span></span>
66
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> DELTA -- thinking_delta --&gt; APPEND1[block.content += delta.thinking]</span></span>
67
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> DELTA -- input_json_delta --&gt; APPEND2[block.content += delta.partial_json]</span></span>
68
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> DELTA -- text_delta --&gt; APPEND3[block.content += delta.text]</span></span>
69
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOP -- message_delta --&gt; USAGE_OUT[usage.outputTokens + cacheReadTokens + stopReason]</span></span>
70
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> BLOCK --&gt; COLLECT[find blocks by type]</span></span>
71
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> COLLECT --&gt; THINKING[thinking block content]</span></span>
72
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> COLLECT --&gt; TEXT[text block content]</span></span>
73
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> COLLECT --&gt; TOOLS[tool_use blocks map to &amp;lbrace;name, id, input:JSON.parse&amp;rbrace;]</span></span></code></pre></div><p><strong>与后端 <code>inject-loop.ts</code> 的 <code>parseUpstreamEvents</code> 的区别</strong>:</p><ul><li>前端把 thinking 单独归到 <code>thinking</code> 字段;后端把 thinking delta 累加到 text(因为后端 <code>blocksToAssistantContent</code> 只保留 text/tool_use)</li><li>前端返回<strong>平铺的字段</strong>(thinking/text/toolCalls)供 UI 显示;后端返回<strong>有序 blocks 数组</strong>供再次转发</li><li>前端 <code>parseToolInput</code> 尝试 JSON.parse 失败降级 <code>{ _raw: content }</code>;后端降级 <code>{}</code></li></ul><h2 id="requestcomparemodal" tabindex="-1">RequestCompareModal <a class="header-anchor" href="#requestcomparemodal" aria-label="Permalink to &quot;RequestCompareModal&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/RequestCompareModal.tsx</code>。全屏 modal,宽 90vw × 高 90vh:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> Props</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">leftId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">rightId</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">onClose</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:#005CC5;--shiki-dark:#79B8FF;"> void</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span></code></pre></div><ul><li>挂载时 <code>Promise.allSettled([fetch left, fetch right])</code> 并发拉两份详情</li><li>每份独立处理成功/失败(<code>errorLeft / errorRight</code>)</li><li>显示 4 个 Tab(Headers / Body / resHeaders / resBody),每个 Tab 里用 <code>DiffPanel</code> 显示两侧对比</li></ul><h3 id="序列化" tabindex="-1">序列化 <a class="header-anchor" href="#序列化" aria-label="Permalink to &quot;序列化&quot;">​</a></h3><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;">function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> stringify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">value</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> unknown</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
74
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (value </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">==</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;&#39;</span></span>
75
+ <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:#005CC5;--shiki-dark:#79B8FF;"> JSON</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">stringify</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(value, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</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:#6F42C1;--shiki-dark:#B392F0;"> String</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(value) }</span></span>
76
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><ul><li>JSON.stringify 失败(循环引用等)→ <code>String(value)</code> 兜底</li><li>null/undefined → 空串(DiffPanel 会显示&quot;无数据&quot;)</li></ul><h3 id="关闭清理" tabindex="-1">关闭清理 <a class="header-anchor" href="#关闭清理" aria-label="Permalink to &quot;关闭清理&quot;">​</a></h3><p><code>useEffect</code> cleanup 用 <code>cancelled</code> 标志防止 unmount 后 setState。</p><h2 id="diffpanel" tabindex="-1">DiffPanel <a class="header-anchor" href="#diffpanel" aria-label="Permalink to &quot;DiffPanel&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/DiffPanel.tsx</code>。基于 <code>@pierre/diffs</code>:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;"> fileDiff</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> useMemo</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>
77
+ <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;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">leftText </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">||</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> !</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">rightText) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span></span>
78
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> oldFile</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`left.\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">lang</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, contents: leftText, lang }</span></span>
79
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> newFile</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`right.\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">lang</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, contents: rightText, lang }</span></span>
80
+ <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;"> parseDiffFromFile</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(oldFile, newFile) }</span></span>
81
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> catch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (err) { console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">error</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 style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
82
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}, [leftText, rightText, lang])</span></span>
83
+ <span class="line"></span>
84
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> fileDiff </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">FileDiff</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> fileDiff</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">{fileDiff} /&gt; </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> &lt;</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;无数据&lt;/</span><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">div</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">&gt;</span></span></code></pre></div><ul><li><code>parseDiffFromFile</code> 产生行级 diff 结构</li><li><code>&lt;FileDiff&gt;</code> 是 <code>@pierre/diffs/react</code> 提供的展示组件</li><li><code>lang</code> 默认 <code>&#39;json&#39;</code> — 语法高亮</li><li>单侧空 → 直接显示&quot;无数据&quot;(可优化为「新增/删除」标记,当前实现选择简单)</li></ul><h2 id="相关" tabindex="-1">相关 <a class="header-anchor" href="#相关" aria-label="Permalink to &quot;相关&quot;">​</a></h2><ul><li>请求详情 API → <a href="./api-layer.html#fetchrequests-limit--1000">api-layer.md</a></li><li>后端 events 结构 → <a href="./../proxy-core/tool.html#每步解析">../proxy-core/tool.md</a></li></ul>`,59)])])}const o=i(t,[["render",l]]);export{g as __pageData,o as default};
@@ -0,0 +1 @@
1
+ import{_ as i,o as a,c as n,a2 as h}from"./chunks/framework.D_Xv2a7c.js";const g=JSON.parse('{"title":"proxy-cli / 请求类组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-requests.md","filePath":"proxy-cli/components-requests.md"}'),t={name:"proxy-cli/components-requests.md"};function l(k,s,e,p,r,d){return a(),n("div",null,[...s[0]||(s[0]=[h("",59)])])}const o=i(t,[["render",l]]);export{g as __pageData,o as default};
@@ -0,0 +1,14 @@
1
+ import{_ as s,o as t,c as i,a2 as e}from"./chunks/framework.D_Xv2a7c.js";const k=JSON.parse('{"title":"proxy-cli / 统计类组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-stats.md","filePath":"proxy-cli/components-stats.md"}'),l={name:"proxy-cli/components-stats.md"};function o(n,a,p,r,d,h){return t(),i("div",null,[...a[0]||(a[0]=[e(`<h1 id="proxy-cli-统计类组件" tabindex="-1">proxy-cli / 统计类组件 <a class="header-anchor" href="#proxy-cli-统计类组件" aria-label="Permalink to &quot;proxy-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-cli/src/components/StatsBarChart.tsx</code></li><li><code>apps/proxy-cli/src/components/TodayStatsCards.tsx</code></li><li><code>apps/proxy-cli/src/components/TokenBarChart.tsx</code></li><li><code>apps/proxy-cli/src/components/GlowCard.tsx</code></li><li><code>apps/proxy-cli/src/components/chart-theme.ts</code></li></ul><h2 id="statsbarchart" tabindex="-1">StatsBarChart <a class="header-anchor" href="#statsbarchart" aria-label="Permalink to &quot;StatsBarChart&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/StatsBarChart.tsx</code>。顶部区域主要视图:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> StatsBarChartProps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">stats</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> StatsData</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">todayStats</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> TodayStats</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span></code></pre></div><p>三个视觉块:</p><ol><li><strong>TodayStatsCards</strong>(今日五张卡)——见下文</li><li><strong>Hour/Day 切换按钮</strong></li><li><strong>Recharts BarChart</strong>(24 小时 / 30 天)</li></ol><h3 id="时间尺度构造-generatetimescale-mode" tabindex="-1">时间尺度构造 <code>generateTimeScale(mode)</code> <a class="header-anchor" href="#时间尺度构造-generatetimescale-mode" aria-label="Permalink to &quot;时间尺度构造 \`generateTimeScale(mode)\`&quot;">​</a></h3><p>前端<strong>主动构造完整时间轴</strong>(24 或 30 个桶),再从 <code>stats.hourly / stats.daily</code> 匹配值。空桶显示为 0——避免柱状图不连续。</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>
2
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MODE{mode} --&gt; HOUR</span></span>
3
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MODE --&gt; DAY</span></span>
4
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> HOUR[&quot;for i in 23..0&lt;br/&gt;time = now - i 小时&lt;br/&gt;utcKey = &#39;YYYY-MM-DD-HH&#39; UTC&lt;br/&gt;display = &#39;HH:00&#39; 本地&quot;] --&gt; LOOKUP1[stats.hourly utcKey]</span></span>
5
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> DAY[&quot;for i in 29..0&lt;br/&gt;time = now - i 天&lt;br/&gt;localKey = &#39;YYYY-MM-DD&#39; 本地&lt;br/&gt;display = &#39;MM-DD&#39; 本地&quot;] --&gt; LOOKUP2[stats.daily localKey]</span></span>
6
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOKUP1 --&gt; RESULT1[time + input/output/cache]</span></span>
7
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> LOOKUP2 --&gt; RESULT2[time + input/output/cache]</span></span></code></pre></div><ul><li><strong>hourly 用 UTC key</strong>(<code>time.getUTCFullYear() ...</code>):因为后端 <code>strftime(&#39;%Y-%m-%d-%H&#39;, timestamp)</code> 是 UTC</li><li><strong>daily 用本地 key</strong>:后端 <code>datetime(timestamp, &#39;+8 hours&#39;)</code> 硬编码 +8——在 UTC+8 用户上表现是&quot;本地&quot;日期串,其他时区用户会跟真实本地日期错开</li><li>display 只用于 X 轴 tick 文本</li></ul><h3 id="图表本身" tabindex="-1">图表本身 <a class="header-anchor" href="#图表本身" aria-label="Permalink to &quot;图表本身&quot;">​</a></h3><ul><li><code>&lt;BarChart&gt;</code> + 三个 <code>&lt;Bar&gt;</code>:input(蓝)、output(绿)、cache(橙)</li><li>Y 轴 <code>tickFormatter={formatCompactNumber}</code> 用 <code>Intl.NumberFormat compact</code> 显示 1.2K / 1M / 1.5B</li><li>Tooltip 深色主题</li><li><code>Legend</code></li><li>容器 <code>&lt;ResponsiveContainer height={200}&gt;</code></li></ul><h3 id="底部脚注" tabindex="-1">底部脚注 <a class="header-anchor" href="#底部脚注" aria-label="Permalink to &quot;底部脚注&quot;">​</a></h3><p><code>{t(&#39;lastUpdated&#39;)}: {formatTime(stats.lastUpdated)}</code> — 从聚合表 <code>MAX(updated_at)</code> 读的时间戳,格式化为本地日期时间。</p><h2 id="todaystatscards" tabindex="-1">TodayStatsCards <a class="header-anchor" href="#todaystatscards" aria-label="Permalink to &quot;TodayStatsCards&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/TodayStatsCards.tsx</code>。五张 GlowCard 排一行:</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;">graph LR</span></span>
8
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> A[Input Tokens&lt;br/&gt;蓝] --- B[Output Tokens&lt;br/&gt;绿] --- C[Cache Read&lt;br/&gt;橙] --- D[请求次数&lt;br/&gt;青蓝] --- E[Models 使用次数&lt;br/&gt;紫]</span></span></code></pre></div><p><strong>卡 1-4</strong> 结构相同:</p><ul><li>顶部:标签文字 + <code>lucide-react</code> 图标(<code>ArrowDownToLine / ArrowUpFromLine / DatabaseZap / Activity</code>)</li><li>中间:<code>&lt;CountUp&gt;</code> 数字动画(0 → value,1.5s,千分位逗号),<code>enableReinitialize + preserveValue</code> 保证增量更新时接续动画</li><li>颜色:<code>TOKEN_COLORS.{input, output, cacheRead, cacheCreate}</code></li></ul><p><strong>卡 5</strong> 特殊——「模型使用」用竖向柱条:</p><ul><li><code>Object.entries(today.models)</code> 遍历模型</li><li>每个模型一根小柱条,高度按 <code>count / maxCount * 100%</code>,最小 8%</li><li>hover 显示 tooltip <code>{model}: {count}</code></li><li>无数据时显示 <code>t(&#39;today.noModels&#39;)</code></li><li>用紫色 <code>#A855F7</code>(<code>MODEL_COLOR</code> 常量)</li></ul><h2 id="tokenbarchart" tabindex="-1">TokenBarChart <a class="header-anchor" href="#tokenbarchart" aria-label="Permalink to &quot;TokenBarChart&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/TokenBarChart.tsx</code>。<strong>单条请求的 Token 迷你柱状图</strong>(不是全局统计)。用在 <code>RequestCard</code> 的头部:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">interface</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> TokenBarChartProps</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">usage</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> TokenUsage</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span></code></pre></div><p>四根柱条:input / output / cacheRead / cacheCreate(TOKEN_COLORS)。</p><ul><li>每根柱条宽 <code>w-3</code> 高度按值 / 最大值 * 16px 计算,最小 2px</li><li>布局 <code>flex items-end gap-1</code> 使柱子等宽底对齐</li><li>hover 每根显示 tooltip <code>{label}: {value}</code></li></ul><p><strong>微型可视化</strong>:让请求列表一眼看出成本占比。</p><h2 id="glowcard" tabindex="-1">GlowCard <a class="header-anchor" href="#glowcard" aria-label="Permalink to &quot;GlowCard&quot;">​</a></h2><p><code>apps/proxy-cli/src/components/GlowCard.tsx</code>。带旋转发光边框的卡片容器:</p><div class="language-tsx vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">tsx</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> GlowCard</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">children</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">color</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 style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">children</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> React</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">ReactNode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">; </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">color</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> JSX</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">Element</span></span></code></pre></div><p><strong>实现思路</strong>:</p><ul><li>外层 <code>overflow-hidden rounded-lg</code></li><li><strong>背景层</strong>:一个 300% × 300% 的 <code>conic-gradient</code>(透明→彩色→透明的圆锥),用 <code>animation: glowRotate 6s linear infinite</code> 无限旋转</li><li><strong>遮罩层</strong>:内嵌 <code>inset-[1px]</code> 的 <code>bg-bg-secondary</code>,只留 1px 边框缝隙露出旋转的渐变 → 视觉上是&quot;发光边框&quot;</li><li><strong>内容层</strong>:<code>relative z-10 p-3</code> 承载 children</li><li><strong><code>colorWithAlpha(alpha)</code></strong>:把 hex <code>#RRGGBB</code> 转成 <code>rgba()</code>,让渐变里能用 alpha 过渡</li></ul><p>用于 <code>TodayStatsCards</code> 的 5 张卡 + <code>ConfigEditor</code> 的两张地址卡——需要视觉焦点的元素。</p><h2 id="chart-theme" tabindex="-1">chart-theme <a class="header-anchor" href="#chart-theme" aria-label="Permalink to &quot;chart-theme&quot;">​</a></h2><p>见 <a href="./components-status.html#chart-theme">components-status.md</a>。本组分文档主要复用 <code>TOKEN_COLORS</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>useWebSocketData → stats (预聚合) + todayStats (实时)</span></span>
9
+ <span class="line"><span> ↓</span></span>
10
+ <span class="line"><span> App.tsx</span></span>
11
+ <span class="line"><span> ↓</span></span>
12
+ <span class="line"><span> StatsBarChart(stats, todayStats)</span></span>
13
+ <span class="line"><span> ├── TodayStatsCards(todayStats) → 5 张 GlowCard</span></span>
14
+ <span class="line"><span> └── BarChart(generateTimeScale) → 3 组柱条</span></span></code></pre></div><p><code>todayStats</code> 在收到 WebSocket <code>type=request</code> 消息时前端主动重新 GET,让今日数据近实时;<code>stats</code> 只在收到 <code>stats notify</code> 消息(目前无发送方)或首帧 REST 时更新。</p><h2 id="相关" tabindex="-1">相关 <a class="header-anchor" href="#相关" aria-label="Permalink to &quot;相关&quot;">​</a></h2><ul><li>数据管道 → <a href="./data-hooks.html">data-hooks.md</a></li><li>后端聚合 → <a href="./../proxy-core/stats.html">../proxy-core/stats.md</a></li></ul>`,42)])])}const g=s(l,[["render",o]]);export{k as __pageData,g as default};
@@ -0,0 +1 @@
1
+ import{_ as s,o as t,c as i,a2 as e}from"./chunks/framework.D_Xv2a7c.js";const k=JSON.parse('{"title":"proxy-cli / 统计类组件","description":"","frontmatter":{},"headers":[],"relativePath":"proxy-cli/components-stats.md","filePath":"proxy-cli/components-stats.md"}'),l={name:"proxy-cli/components-stats.md"};function o(n,a,p,r,d,h){return t(),i("div",null,[...a[0]||(a[0]=[e("",42)])])}const g=s(l,[["render",o]]);export{k as __pageData,g as default};