@cc-monitoring/proxy-core 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (409) hide show
  1. package/dist/cli/__tests__/commands.test.js +20 -1
  2. package/dist/cli/commands/exec.js +31 -42
  3. package/dist/cli/commands/repair.d.ts +1 -0
  4. package/dist/cli/commands/repair.js +15 -0
  5. package/dist/cli/index.js +30 -0
  6. package/dist/docs/404.html +2 -2
  7. package/dist/docs/assets/{app.B9A39uFv.js → app.g7N9jkzn.js} +1 -1
  8. package/dist/docs/assets/chunks/@localSearchIndexroot.IHxQqfJH.js +1 -0
  9. package/dist/docs/assets/chunks/{VPLocalSearchBox.DdhC696L.js → VPLocalSearchBox.BHwI475_.js} +1 -1
  10. package/dist/docs/assets/chunks/{theme.CfB2tOFi.js → theme.FhAJSNDh.js} +2 -2
  11. package/dist/docs/assets/{proxy-cli_data-hooks.md.w9Oe1OD3.js → proxy-cli_data-hooks.md.Bz8CVbxO.js} +1 -1
  12. package/dist/docs/assets/{proxy-core_ui-routes.md.Dyqkeoiv.js → proxy-core_ui-routes.md.B21t1p7R.js} +1 -1
  13. package/dist/docs/hashmap.json +1 -1
  14. package/dist/docs/index.html +3 -3
  15. package/dist/docs/overview.html +3 -3
  16. package/dist/docs/packages-utils.html +3 -3
  17. package/dist/docs/proxy-admin/env-and-build.html +3 -3
  18. package/dist/docs/proxy-admin/index.html +3 -3
  19. package/dist/docs/proxy-admin/layout-and-menu.html +3 -3
  20. package/dist/docs/proxy-admin/pages.html +3 -3
  21. package/dist/docs/proxy-admin/routing-and-auth.html +3 -3
  22. package/dist/docs/proxy-admin/services-and-mock.html +3 -3
  23. package/dist/docs/proxy-cli/api-layer.html +3 -3
  24. package/dist/docs/proxy-cli/app-shell.html +3 -3
  25. package/dist/docs/proxy-cli/components-common.html +3 -3
  26. package/dist/docs/proxy-cli/components-config.html +3 -3
  27. package/dist/docs/proxy-cli/components-requests.html +3 -3
  28. package/dist/docs/proxy-cli/components-stats.html +3 -3
  29. package/dist/docs/proxy-cli/components-status.html +3 -3
  30. package/dist/docs/proxy-cli/data-hooks.html +5 -5
  31. package/dist/docs/proxy-cli/index.html +3 -3
  32. package/dist/docs/proxy-cli/utils-and-i18n.html +3 -3
  33. package/dist/docs/proxy-core/chat-api.html +3 -3
  34. package/dist/docs/proxy-core/cli.html +3 -3
  35. package/dist/docs/proxy-core/config.html +3 -3
  36. package/dist/docs/proxy-core/data-layer.html +3 -3
  37. package/dist/docs/proxy-core/entry.html +3 -3
  38. package/dist/docs/proxy-core/index.html +3 -3
  39. package/dist/docs/proxy-core/pm2.html +3 -3
  40. package/dist/docs/proxy-core/providers.html +3 -3
  41. package/dist/docs/proxy-core/proxy.html +3 -3
  42. package/dist/docs/proxy-core/stats.html +3 -3
  43. package/dist/docs/proxy-core/tool.html +3 -3
  44. package/dist/docs/proxy-core/ui-routes.html +5 -5
  45. package/dist/docs/proxy-core/utilities.html +3 -3
  46. package/dist/docs/quickstart.html +3 -3
  47. package/dist/docs/request-flow.html +3 -3
  48. package/dist/logger/index.d.ts +0 -3
  49. package/dist/logger/index.js +0 -1
  50. package/dist/mcp-server/tools.js +8 -9
  51. package/dist/server/__tests__/data-push.test.js +44 -0
  52. package/dist/server/__tests__/providers-route.test.js +1 -0
  53. package/dist/server/__tests__/proxy.test.js +281 -2
  54. package/dist/server/__tests__/server.test.js +15 -10
  55. package/dist/server/__tests__/ui-route.test.js +43 -0
  56. package/dist/server/auth.d.ts +0 -1
  57. package/dist/server/auth.js +1 -1
  58. package/dist/server/chat-route.js +48 -162
  59. package/dist/server/data-push.d.ts +2 -1
  60. package/dist/server/data-push.js +22 -7
  61. package/dist/server/index.js +4 -3
  62. package/dist/server/proxy.js +193 -229
  63. package/dist/server/ui-route.js +84 -60
  64. package/dist/tools/index.d.ts +1 -1
  65. package/dist/tools/index.js +1 -1
  66. package/dist/tools/registry.d.ts +0 -4
  67. package/dist/tools/registry.js +0 -8
  68. package/dist/types/config.d.ts +0 -13
  69. package/dist/types/pm2.d.ts +1 -2
  70. package/dist/ui/assets/{1c-DAu68mP4.js → 1c-CaPSZBmB.js} +1 -1
  71. package/dist/ui/assets/{abnf-Cu8RHCHK.js → abnf-DBDOsmne.js} +1 -1
  72. package/dist/ui/assets/{abnfDiagram-VRR7QNED-BUBToPXF.js → abnfDiagram-VRR7QNED-D8zK__Mj.js} +1 -1
  73. package/dist/ui/assets/{accesslog-BG-34XOy.js → accesslog-BOLs2Kig.js} +1 -1
  74. package/dist/ui/assets/{actionscript-iw0HHMGM.js → actionscript-BZYKhS1B.js} +1 -1
  75. package/dist/ui/assets/{ada-qRqj6VGQ.js → ada-DyacnMpg.js} +1 -1
  76. package/dist/ui/assets/{angelscript-BeaXyx_P.js → angelscript-CAN6j0H3.js} +1 -1
  77. package/dist/ui/assets/{apache-CU8d-z9X.js → apache-BE4vouiQ.js} +1 -1
  78. package/dist/ui/assets/{applescript-d1Wxkqz1.js → applescript-CS88I1yz.js} +1 -1
  79. package/dist/ui/assets/{arc-BMsPIm3j.js → arc-CTMmdrSV.js} +1 -1
  80. package/dist/ui/assets/{arcade-CtbgrWTM.js → arcade-B0f0f5SD.js} +1 -1
  81. package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-CVjC5TrS.js → architectureDiagram-ZJ3FMSHR-Dtvpnopp.js} +1 -1
  82. package/dist/ui/assets/{arduino-Bc9L39Hr.js → arduino-Bhm-OSb2.js} +1 -1
  83. package/dist/ui/assets/{armasm-DuWmpjWR.js → armasm-CEy-mDHc.js} +1 -1
  84. package/dist/ui/assets/{asciidoc-CDIhFTnx.js → asciidoc-CrZqQBTj.js} +1 -1
  85. package/dist/ui/assets/{aspectj-SYj-57Es.js → aspectj-B4IlFyyJ.js} +1 -1
  86. package/dist/ui/assets/{autohotkey-hBi5dq37.js → autohotkey-Cihy-FjA.js} +1 -1
  87. package/dist/ui/assets/{autoit-BSawXzhg.js → autoit-Dis_JVJq.js} +1 -1
  88. package/dist/ui/assets/{avrasm-CwYom8Np.js → avrasm-CVhMycHj.js} +1 -1
  89. package/dist/ui/assets/{awk-BvBRfGo2.js → awk-BCViwLf5.js} +1 -1
  90. package/dist/ui/assets/{axapta-CqUavA8k.js → axapta-pWB4JVB_.js} +1 -1
  91. package/dist/ui/assets/{bash-BS_ZnmEu.js → bash-B6Giryub.js} +1 -1
  92. package/dist/ui/assets/{basic-xbP4IXrN.js → basic-DcrjcHB0.js} +1 -1
  93. package/dist/ui/assets/{blockDiagram-677ZJIJ3-CmpI3f5p.js → blockDiagram-677ZJIJ3-DfhtgI1r.js} +1 -1
  94. package/dist/ui/assets/{bnf-BECwu6uW.js → bnf-cpKU0967.js} +1 -1
  95. package/dist/ui/assets/{brainfuck-QQgu4j4N.js → brainfuck-CFFdk4cM.js} +1 -1
  96. package/dist/ui/assets/{coq-IDMIFfem.js → c-CW6KPMeI.js} +1 -1
  97. package/dist/ui/assets/{c-like-DYrFOtXy.js → c-like-CWn59vrg.js} +1 -1
  98. package/dist/ui/assets/{c4Diagram-LMCZKHZV-B6Hgngz9.js → c4Diagram-LMCZKHZV-D1Oh6k37.js} +1 -1
  99. package/dist/ui/assets/{cal-CNMrJ6v5.js → cal-8i26_L39.js} +1 -1
  100. package/dist/ui/assets/{capnproto-DYCKl6oY.js → capnproto-CviwnFBf.js} +1 -1
  101. package/dist/ui/assets/{ceylon-mb8tRPl0.js → ceylon-CQyc4rWs.js} +1 -1
  102. package/dist/ui/assets/channel-Da2MvpNG.js +1 -0
  103. package/dist/ui/assets/{chunk-2Q5K7J3B-LxvQ-G67.js → chunk-2Q5K7J3B-oswPBwIn.js} +1 -1
  104. package/dist/ui/assets/{chunk-32BRIVSS-DxzKK6Aw.js → chunk-32BRIVSS-B5pU_9b9.js} +1 -1
  105. package/dist/ui/assets/{chunk-5VM5RSS4-CZEoYJ2W.js → chunk-5VM5RSS4-gvtfMc4w.js} +1 -1
  106. package/dist/ui/assets/{chunk-EX3LRPZG-DS2PytrN.js → chunk-EX3LRPZG-BkBaDMy4.js} +1 -1
  107. package/dist/ui/assets/{chunk-JWPE2WC7-UX0Sr1Ie.js → chunk-JWPE2WC7-Ch-C75ar.js} +1 -1
  108. package/dist/ui/assets/{chunk-MOJQB5TN-YbJgT9t4.js → chunk-MOJQB5TN-BfYhj1jN.js} +1 -1
  109. package/dist/ui/assets/{chunk-RYQCIY6F-DS2VH_U9.js → chunk-RYQCIY6F-D8izfruP.js} +1 -1
  110. package/dist/ui/assets/{chunk-V7JOEXUC-CZr0pkI1.js → chunk-V7JOEXUC-CbzHnW90.js} +1 -1
  111. package/dist/ui/assets/{chunk-VR4S4FIN-50opPAD3.js → chunk-VR4S4FIN-Dr4M5qZA.js} +1 -1
  112. package/dist/ui/assets/{chunk-XXDRQBXY-DAAX9l7U.js → chunk-XXDRQBXY-QE-R8dRe.js} +1 -1
  113. package/dist/ui/assets/classDiagram-OUVF2IWQ-mHUiWjcC.js +1 -0
  114. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-mHUiWjcC.js +1 -0
  115. package/dist/ui/assets/{clean-C4X7dSkh.js → clean-DZeAtQ7H.js} +1 -1
  116. package/dist/ui/assets/{clojure-DSg9gUa7.js → clojure-U4ebZ7NQ.js} +1 -1
  117. package/dist/ui/assets/{clojure-repl-CagRYx7h.js → clojure-repl-B4QSIzUI.js} +1 -1
  118. package/dist/ui/assets/{cmake-CFdBn53c.js → cmake-UHexZySb.js} +1 -1
  119. package/dist/ui/assets/{coffeescript-CJZtMOPx.js → coffeescript-Dg56H9Mr.js} +1 -1
  120. package/dist/ui/assets/{c-BRJEPYra.js → coq-C1g3mm0X.js} +1 -1
  121. package/dist/ui/assets/{cos-Bx2VJuzG.js → cos-BL4DdyGh.js} +1 -1
  122. package/dist/ui/assets/{cose-bilkent-JH36ORCC-zWRLsZpZ.js → cose-bilkent-JH36ORCC-BHQslHP3.js} +1 -1
  123. package/dist/ui/assets/{cpp-CsG6DlC4.js → cpp-keZI-XAd.js} +1 -1
  124. package/dist/ui/assets/{crmsh-DTy9MnmJ.js → crmsh-DdXYVeeA.js} +1 -1
  125. package/dist/ui/assets/{crystal-BwgrLrZ1.js → crystal-C4AN0m0I.js} +1 -1
  126. package/dist/ui/assets/{csharp-B2VeTPAF.js → csharp-COUyKsNR.js} +1 -1
  127. package/dist/ui/assets/{csp-CTpydNhH.js → csp-DBc-rgSJ.js} +1 -1
  128. package/dist/ui/assets/{css-B0mMUbpY.js → css-B8m6O_Pw.js} +1 -1
  129. package/dist/ui/assets/{cynefin-VYW2F7L2-BmjQEj6q.js → cynefin-VYW2F7L2-B3L-WcKn.js} +1 -1
  130. package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-Dr0Zrke0.js → cynefinDiagram-TSTJHNR4-fzaM4qcZ.js} +1 -1
  131. package/dist/ui/assets/{d-DjuDZnbI.js → d-dgQN4Rko.js} +1 -1
  132. package/dist/ui/assets/{dagre-VKFMJZFB-xoTPT2Uu.js → dagre-VKFMJZFB-DJHj16mR.js} +1 -1
  133. package/dist/ui/assets/{dart-xR3GU9TJ.js → dart-D2Y7LOq-.js} +1 -1
  134. package/dist/ui/assets/{delphi-bJas5QnG.js → delphi-DaGcSk5A.js} +1 -1
  135. package/dist/ui/assets/{diagram-FQU43EPY-rL_IU7gU.js → diagram-FQU43EPY-iZEZ1f-R.js} +1 -1
  136. package/dist/ui/assets/{diagram-G47NLZAW-EcDiCVGj.js → diagram-G47NLZAW-rkQb3r-C.js} +1 -1
  137. package/dist/ui/assets/{diagram-NH7WQ7WH-CGGXOjev.js → diagram-NH7WQ7WH-B4Fy72tP.js} +1 -1
  138. package/dist/ui/assets/{diagram-OA4YK3LP-DnE7hDjD.js → diagram-OA4YK3LP-BndmuIBq.js} +1 -1
  139. package/dist/ui/assets/{diagram-WEI45ONY-CTJH5eD8.js → diagram-WEI45ONY-CwlAiqOe.js} +1 -1
  140. package/dist/ui/assets/{diff-doJFF3fv.js → diff-prcRV1Y3.js} +1 -1
  141. package/dist/ui/assets/{django-D3b-owa_.js → django-B1zIoGSx.js} +1 -1
  142. package/dist/ui/assets/{dns-C42KYV-Z.js → dns-ZxI_aTwc.js} +1 -1
  143. package/dist/ui/assets/{dockerfile-9KUINc2j.js → dockerfile-Dp_fT6E-.js} +1 -1
  144. package/dist/ui/assets/{dos-CxnlJ6qp.js → dos-Cuu5c8vv.js} +1 -1
  145. package/dist/ui/assets/{dsconfig-6CMMCwmY.js → dsconfig-DcGTOhbS.js} +1 -1
  146. package/dist/ui/assets/{dts-D78rdUIB.js → dts-DCF8VaRk.js} +1 -1
  147. package/dist/ui/assets/{dust-Dv1uTfJU.js → dust-DeCmZWMK.js} +1 -1
  148. package/dist/ui/assets/{ebnf-BGbG1cFK.js → ebnf-BHQQcuF_.js} +1 -1
  149. package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-z2VgRSUV.js → ebnfDiagram-CCIWWBDH-DJ_RuhTm.js} +1 -1
  150. package/dist/ui/assets/{elixir-ZgAQVY1J.js → elixir-BHmweJ4d.js} +1 -1
  151. package/dist/ui/assets/{elm-CudiFuNu.js → elm-v76Hd2B3.js} +1 -1
  152. package/dist/ui/assets/{erDiagram-Q63AITRT-X1TODuRv.js → erDiagram-Q63AITRT-DVZkY5RZ.js} +1 -1
  153. package/dist/ui/assets/{erb-Bz_NZh6W.js → erb-xvWF5bfx.js} +1 -1
  154. package/dist/ui/assets/{erlang-DNuj1nb2.js → erlang-CKBMURym.js} +1 -1
  155. package/dist/ui/assets/{erlang-repl-SP1Gan9W.js → erlang-repl-BjcfXt3Z.js} +1 -1
  156. package/dist/ui/assets/{excel-0K77uECF.js → excel-Cdrtxhml.js} +1 -1
  157. package/dist/ui/assets/{fix-CalJq7JD.js → fix-CB-So5So.js} +1 -1
  158. package/dist/ui/assets/{flix-BlIs11_w.js → flix-VM9AOrq6.js} +1 -1
  159. package/dist/ui/assets/{flowDiagram-23GEKE2U-DA2dnmc0.js → flowDiagram-23GEKE2U-vyGW67Xm.js} +1 -1
  160. package/dist/ui/assets/{fortran-ZCobXY2R.js → fortran-CcwJVO8H.js} +1 -1
  161. package/dist/ui/assets/{fsharp-Be8rwUtc.js → fsharp-DiATpw1u.js} +1 -1
  162. package/dist/ui/assets/{gams-DUat8frQ.js → gams-Csg9YNPz.js} +1 -1
  163. package/dist/ui/assets/{ganttDiagram-NO4QXBWP-DdFwaIGZ.js → ganttDiagram-NO4QXBWP-C2TRbwLw.js} +1 -1
  164. package/dist/ui/assets/{gauss-BB4U88dy.js → gauss-Bc4TC8Wh.js} +1 -1
  165. package/dist/ui/assets/{gcode-DzeUZuZg.js → gcode-Rig_2OoA.js} +1 -1
  166. package/dist/ui/assets/{gherkin-B_8vW_BO.js → gherkin-ByBU06QB.js} +1 -1
  167. package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-B-Dn8x6I.js → gitGraphDiagram-IHSO6WYX-CEiqfFIF.js} +1 -1
  168. package/dist/ui/assets/{glsl-DGHGjPC1.js → glsl-C8D6y2Tn.js} +1 -1
  169. package/dist/ui/assets/{gml-BYEku8Yh.js → gml-PHpGPHbT.js} +1 -1
  170. package/dist/ui/assets/{go-D8aSgQMc.js → go-BL_o_3ez.js} +1 -1
  171. package/dist/ui/assets/{golo-CDjCU_jh.js → golo-CWQ6dTUz.js} +1 -1
  172. package/dist/ui/assets/{gradle-BeUw7tl_.js → gradle-Y_I2KN2z.js} +1 -1
  173. package/dist/ui/assets/{groovy-5iCQOtR3.js → groovy-JnIv8p2l.js} +1 -1
  174. package/dist/ui/assets/{haml-BEdL8FJi.js → haml-B8W_h6mZ.js} +1 -1
  175. package/dist/ui/assets/{handlebars-BuYQNzoK.js → handlebars-DVm8mJuD.js} +1 -1
  176. package/dist/ui/assets/{haskell-I4FCBcW0.js → haskell-DlDi2Ty7.js} +1 -1
  177. package/dist/ui/assets/{haxe-yigyKfFr.js → haxe-CftFNVE-.js} +1 -1
  178. package/dist/ui/assets/{hsp-ZUk4j7d1.js → hsp-C67xnq9C.js} +1 -1
  179. package/dist/ui/assets/{htmlbars-QYP3lT3u.js → htmlbars-CmJCm67U.js} +1 -1
  180. package/dist/ui/assets/{http-BJpD1O71.js → http-b-FPEcHP.js} +1 -1
  181. package/dist/ui/assets/{hy-CIJ1bP6S.js → hy-BWD3ncpN.js} +1 -1
  182. package/dist/ui/assets/{index-COAgrx1J.js → index-C7s1zgJb.js} +242 -242
  183. package/dist/ui/assets/{index-BDXWttnT.js → index-D2UBwfSG.js} +3 -3
  184. package/dist/ui/assets/index-DlsVXaHT.css +10 -0
  185. package/dist/ui/assets/{infoDiagram-FWYZ7A6U-fTg9eLNt.js → infoDiagram-FWYZ7A6U-C0Px17IN.js} +1 -1
  186. package/dist/ui/assets/{inform7-DAsu-lC2.js → inform7-C-OYaMO5.js} +1 -1
  187. package/dist/ui/assets/{ini-Bhz-zHCg.js → ini-CVyYmykw.js} +1 -1
  188. package/dist/ui/assets/{irpf90-BunhbwBl.js → irpf90-BcpjWXIz.js} +1 -1
  189. package/dist/ui/assets/{isbl-q9L6hOhP.js → isbl-ZraBBeEr.js} +1 -1
  190. package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-B8G0sdgd.js → ishikawaDiagram-FXEZZL3T-BjmTMgpO.js} +1 -1
  191. package/dist/ui/assets/{java-Iks5Pkau.js → java-D_mE2DT6.js} +1 -1
  192. package/dist/ui/assets/{javascript-C4vltXPw.js → javascript-akXESsox.js} +1 -1
  193. package/dist/ui/assets/{jboss-cli-BQBvd2X2.js → jboss-cli-CFe3gTDt.js} +1 -1
  194. package/dist/ui/assets/{journeyDiagram-5HDEW3XC-Crbzgrum.js → journeyDiagram-5HDEW3XC-BpgJUvs6.js} +1 -1
  195. package/dist/ui/assets/{json-DXK0_jUK.js → json-sjN7AzRC.js} +1 -1
  196. package/dist/ui/assets/{julia-CCYoBiYK.js → julia-BJJYbUMV.js} +1 -1
  197. package/dist/ui/assets/{julia-repl-y8v2Oorl.js → julia-repl-BwruD8Ix.js} +1 -1
  198. package/dist/ui/assets/{kanban-definition-HUTT4EX6-C8sCOsBX.js → kanban-definition-HUTT4EX6-DFlE9edA.js} +1 -1
  199. package/dist/ui/assets/{kotlin-Bnjk7_fw.js → kotlin-CAIQsLCF.js} +1 -1
  200. package/dist/ui/assets/{lasso-B-al6x63.js → lasso-sU67h-5u.js} +1 -1
  201. package/dist/ui/assets/{latex-BUmqlb9r.js → latex-CVX-jP88.js} +1 -1
  202. package/dist/ui/assets/{ldif-D42RWj6Q.js → ldif-DGM9xbFZ.js} +1 -1
  203. package/dist/ui/assets/{leaf-CrH4BZ0m.js → leaf-AlB_zmwz.js} +1 -1
  204. package/dist/ui/assets/{less-upmRlQQW.js → less-CKwfEdZQ.js} +1 -1
  205. package/dist/ui/assets/{lisp-DHYS22SA.js → lisp-CXYLaAPw.js} +1 -1
  206. package/dist/ui/assets/{livecodeserver-CeQNmFP3.js → livecodeserver-C02fGGTS.js} +1 -1
  207. package/dist/ui/assets/{livescript-PJWpY1JI.js → livescript-CBMa8QF_.js} +1 -1
  208. package/dist/ui/assets/{llvm-BKtKWwCt.js → llvm-WXTIohTC.js} +1 -1
  209. package/dist/ui/assets/{lsl-RWRLRjk7.js → lsl-4obd2U_I.js} +1 -1
  210. package/dist/ui/assets/{lua-BFUDiPGm.js → lua-DTSy-TjF.js} +1 -1
  211. package/dist/ui/assets/{makefile-CUDyOz5D.js → makefile-Bf2UEO0i.js} +1 -1
  212. package/dist/ui/assets/{markdown-zZCLypc6.js → markdown-BgoGmFfJ.js} +1 -1
  213. package/dist/ui/assets/{mathematica-BHbxKxnq.js → mathematica-CSiA8KQh.js} +1 -1
  214. package/dist/ui/assets/{matlab-DlGtg--p.js → matlab-DoMvLsGB.js} +1 -1
  215. package/dist/ui/assets/{maxima-BBBeS3Ra.js → maxima-BFO4dfZO.js} +1 -1
  216. package/dist/ui/assets/{mel-nh8j7W_6.js → mel-DyBpmDxt.js} +1 -1
  217. package/dist/ui/assets/{mercury-DyyD-pqr.js → mercury-OL5G5uU6.js} +1 -1
  218. package/dist/ui/assets/{mindmap-definition-LN4V7U3C-CJlhDHqM.js → mindmap-definition-LN4V7U3C-s-nUZuCs.js} +1 -1
  219. package/dist/ui/assets/{mipsasm-hiEhRRiq.js → mipsasm-KQwdm39j.js} +1 -1
  220. package/dist/ui/assets/{mizar-BZa3iAAL.js → mizar-BqndJ30I.js} +1 -1
  221. package/dist/ui/assets/{mojolicious-BCIm2V_y.js → mojolicious-Bvc1uJd-.js} +1 -1
  222. package/dist/ui/assets/{monkey-zmK-7N8b.js → monkey-Dl_gLm7-.js} +1 -1
  223. package/dist/ui/assets/{moonscript-BsS_Mn3D.js → moonscript-BL6R6eAz.js} +1 -1
  224. package/dist/ui/assets/{n1ql-D7xVgDP0.js → n1ql-C09iOJfQ.js} +1 -1
  225. package/dist/ui/assets/{nginx-ct2q4dtd.js → nginx-C7W01nBr.js} +1 -1
  226. package/dist/ui/assets/{nim-RO0UOmW3.js → nim-Dj78szvD.js} +1 -1
  227. package/dist/ui/assets/{nix-BcRJxPKH.js → nix-BOtGyPmd.js} +1 -1
  228. package/dist/ui/assets/{node-repl-DgIefwxW.js → node-repl-19nZvZ4A.js} +1 -1
  229. package/dist/ui/assets/{nsis-DqHs9QhB.js → nsis-ByCl1zIm.js} +1 -1
  230. package/dist/ui/assets/{objectivec-BBcWqc7Y.js → objectivec-BhdaT_Jr.js} +1 -1
  231. package/dist/ui/assets/{ocaml-BExfw7D6.js → ocaml-D_NXvSO7.js} +1 -1
  232. package/dist/ui/assets/{openscad-CHPRELQb.js → openscad-DOhagvnA.js} +1 -1
  233. package/dist/ui/assets/{oxygene-DpS9uMJW.js → oxygene-5BnkqMRH.js} +1 -1
  234. package/dist/ui/assets/{parser3-CjJ_QdBp.js → parser3-jSWlxi8m.js} +1 -1
  235. package/dist/ui/assets/{pegDiagram-2B236MQR-GM70woGy.js → pegDiagram-2B236MQR-CideH-XT.js} +1 -1
  236. package/dist/ui/assets/{perl-BSNM2Kt8.js → perl-CfsqjZ4b.js} +1 -1
  237. package/dist/ui/assets/{pf-Z-hKf_88.js → pf-kOewxO29.js} +1 -1
  238. package/dist/ui/assets/{pgsql-DDgznxBg.js → pgsql-CXm2Xd-Z.js} +1 -1
  239. package/dist/ui/assets/{php-BzAhxF-l.js → php-CRiA_dH8.js} +1 -1
  240. package/dist/ui/assets/{php-template-DkgcKHRc.js → php-template-ByMrxqSd.js} +1 -1
  241. package/dist/ui/assets/{pieDiagram-ENE6RG2P-Bst7mPyz.js → pieDiagram-ENE6RG2P-CJkCdB38.js} +1 -1
  242. package/dist/ui/assets/{plaintext-BYEppD0R.js → plaintext-BJx0R6A5.js} +1 -1
  243. package/dist/ui/assets/{pony-BT_kQd1K.js → pony-CozCHtz4.js} +1 -1
  244. package/dist/ui/assets/{powershell-BfRsuSsf.js → powershell-BT7gMMgn.js} +1 -1
  245. package/dist/ui/assets/{processing-DpzWe5Iu.js → processing-FOIxn_W_.js} +1 -1
  246. package/dist/ui/assets/{profile-BCOhS5cM.js → profile-BsoUuD9w.js} +1 -1
  247. package/dist/ui/assets/{prolog-OxaCCaW8.js → prolog-Bd3gvQ2N.js} +1 -1
  248. package/dist/ui/assets/{properties-DMFlA2Ca.js → properties-BWGFdny9.js} +1 -1
  249. package/dist/ui/assets/{protobuf-CRDFkXvZ.js → protobuf-pQSKoOOY.js} +1 -1
  250. package/dist/ui/assets/{puppet-DnrVyLzx.js → puppet-DnEN_mgS.js} +1 -1
  251. package/dist/ui/assets/{purebasic-Dht4Hniv.js → purebasic-BqoOGoRw.js} +1 -1
  252. package/dist/ui/assets/{python-B0aMirWu.js → python-TeVYomkE.js} +1 -1
  253. package/dist/ui/assets/{python-repl-BlYDBGa7.js → python-repl-zqu5igFS.js} +1 -1
  254. package/dist/ui/assets/{q-DzrtW9kT.js → q-CZC9Dltd.js} +1 -1
  255. package/dist/ui/assets/{qml-DnfQsR3i.js → qml-ZNInP45Q.js} +1 -1
  256. package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-DNRYurBT.js → quadrantDiagram-ABIIQ3AL-Dd7PwxsF.js} +1 -1
  257. package/dist/ui/assets/{r-DGI_ZuTD.js → r-B39DAmkC.js} +1 -1
  258. package/dist/ui/assets/{railroadDiagram-RFXS5EU6-CmbC3Vz4.js → railroadDiagram-RFXS5EU6-DtO5PVFZ.js} +1 -1
  259. package/dist/ui/assets/{reasonml-3SohMgh2.js → reasonml-B-ZWFJt_.js} +1 -1
  260. package/dist/ui/assets/{requirementDiagram-TGXJPOKE-8CxrXHco.js → requirementDiagram-TGXJPOKE-DihF4OTj.js} +1 -1
  261. package/dist/ui/assets/{rib-DfRSd4Qa.js → rib-CnGG0qMF.js} +1 -1
  262. package/dist/ui/assets/{roboconf-CQczGdGW.js → roboconf-Ewtfps4u.js} +1 -1
  263. package/dist/ui/assets/{routeros-DCka-T2i.js → routeros-CPcmP1c7.js} +1 -1
  264. package/dist/ui/assets/{rsl-Dr8MOwMo.js → rsl-NbjWFbPH.js} +1 -1
  265. package/dist/ui/assets/{ruby-C2zFSkh_.js → ruby-DWDdy5yE.js} +1 -1
  266. package/dist/ui/assets/{ruleslanguage-C97YsgQq.js → ruleslanguage-Cv_DZe2r.js} +1 -1
  267. package/dist/ui/assets/{rust-H3h8kd9A.js → rust-NZnsfER5.js} +1 -1
  268. package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-DBXLWjEq.js → sankeyDiagram-HTMAVEWB-D6i-Mzte.js} +1 -1
  269. package/dist/ui/assets/{sas-04z0Xu8P.js → sas-C4wv0P6G.js} +1 -1
  270. package/dist/ui/assets/{scala-DyB9Aoiv.js → scala-DUdTOIgx.js} +1 -1
  271. package/dist/ui/assets/{scheme-DBj6nxUi.js → scheme-DEdFa14t.js} +1 -1
  272. package/dist/ui/assets/{scilab-Btj7AD9s.js → scilab-xY51J2bR.js} +1 -1
  273. package/dist/ui/assets/{scss-BXZJyXt7.js → scss-BEYp1sXc.js} +1 -1
  274. package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-DXIkBFKC.js → sequenceDiagram-DBY2YBRQ-njQlqy_J.js} +1 -1
  275. package/dist/ui/assets/{shell-BsreQR1Z.js → shell-fq6bkhOw.js} +1 -1
  276. package/dist/ui/assets/{sizeCapture-X5ZJPWSS-ocS9jxAQ.js → sizeCapture-X5ZJPWSS-tLn70-Fb.js} +1 -1
  277. package/dist/ui/assets/{smali-D9wQw9zm.js → smali-CsSAuSYg.js} +1 -1
  278. package/dist/ui/assets/{smalltalk-Dku6G_H3.js → smalltalk-DJ7zrd87.js} +1 -1
  279. package/dist/ui/assets/{sml-BknyU6ya.js → sml-CnDwl0nH.js} +1 -1
  280. package/dist/ui/assets/{sqf-DRYMaOg8.js → sqf-Cc2SX4Zy.js} +1 -1
  281. package/dist/ui/assets/{sql-Cw3Ax4KA.js → sql-DUQA_V_4.js} +1 -1
  282. package/dist/ui/assets/{sql_more-vWdslLE0.js → sql_more-BHoH-8oO.js} +1 -1
  283. package/dist/ui/assets/{stan-8XH5bDS6.js → stan-D-7F5jH6.js} +1 -1
  284. package/dist/ui/assets/{stata-4e77wgfe.js → stata-xKD_DnDE.js} +1 -1
  285. package/dist/ui/assets/{stateDiagram-2N3HPSRC-RMmL9jMG.js → stateDiagram-2N3HPSRC-B4O8weor.js} +1 -1
  286. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-CO881_ht.js +1 -0
  287. package/dist/ui/assets/{step21-ByIeDMY3.js → step21-obc_kzQY.js} +1 -1
  288. package/dist/ui/assets/{stylus-ZAhJyWsw.js → stylus-CkAUSRd-.js} +1 -1
  289. package/dist/ui/assets/{subunit-pPW2UGkj.js → subunit-BDv8PGo1.js} +1 -1
  290. package/dist/ui/assets/{swift-CX3BB5az.js → swift-CHsYyW-p.js} +1 -1
  291. package/dist/ui/assets/{swimlanes-5IMT3BWC-C2zAuJ56.js → swimlanes-5IMT3BWC-DSr9Ty4A.js} +2 -2
  292. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DFMCDs8b.js +8 -0
  293. package/dist/ui/assets/{taggerscript-BHcjbWIC.js → taggerscript-C_2JQgO9.js} +1 -1
  294. package/dist/ui/assets/{tap-BOl1lBlS.js → tap-Bi497Z2c.js} +1 -1
  295. package/dist/ui/assets/{tcl-DZjeOBDh.js → tcl-B1XMvLaD.js} +1 -1
  296. package/dist/ui/assets/{thrift-BxboWg4x.js → thrift-D9X0Hmmc.js} +1 -1
  297. package/dist/ui/assets/{timeline-definition-FHXFAJF6-BOxsxyq_.js → timeline-definition-FHXFAJF6-C4_gj50B.js} +1 -1
  298. package/dist/ui/assets/{tp-BNM6ql3J.js → tp-CJG4Odbx.js} +1 -1
  299. package/dist/ui/assets/{twig-Dj9ZiXD4.js → twig-flj72_wc.js} +1 -1
  300. package/dist/ui/assets/{typescript-7MEJlu_6.js → typescript-CWPwVoLd.js} +1 -1
  301. package/dist/ui/assets/{vala-DNqOAgHJ.js → vala-LuCNWNuU.js} +1 -1
  302. package/dist/ui/assets/{vbnet-T0mNKVc_.js → vbnet-CGUT6ss0.js} +1 -1
  303. package/dist/ui/assets/{vbscript-CeuwVMAI.js → vbscript-CNiUBJhn.js} +1 -1
  304. package/dist/ui/assets/{vbscript-html-BbJSt2w6.js → vbscript-html-CJGgjjbc.js} +1 -1
  305. package/dist/ui/assets/{vennDiagram-L72KCM5P-BX9mWeiT.js → vennDiagram-L72KCM5P-BxcAUnYo.js} +1 -1
  306. package/dist/ui/assets/{verilog-DYuhYfkX.js → verilog-C4f9ZBTK.js} +1 -1
  307. package/dist/ui/assets/{vhdl-Cf9aT-t7.js → vhdl-CyDQIZve.js} +1 -1
  308. package/dist/ui/assets/{vim-DciP44K1.js → vim-XAUBqa0M.js} +1 -1
  309. package/dist/ui/assets/{wardleyDiagram-EHGQE667-CDj2rOzu.js → wardleyDiagram-EHGQE667-DlwSH77q.js} +1 -1
  310. package/dist/ui/assets/{x86asm-E-AN_LXO.js → x86asm-Cp6vHuUx.js} +1 -1
  311. package/dist/ui/assets/{xl-CxYLJelN.js → xl-BHgDofIM.js} +1 -1
  312. package/dist/ui/assets/{xml-yz1SRLuU.js → xml-QloVn4s_.js} +1 -1
  313. package/dist/ui/assets/{xquery-BLzBF3tV.js → xquery-spJZLmyM.js} +1 -1
  314. package/dist/ui/assets/{xychartDiagram-FW5EYKEG-Czapk9-Z.js → xychartDiagram-FW5EYKEG-BxGVZcnb.js} +1 -1
  315. package/dist/ui/assets/{yaml-Cv4Y7iN_.js → yaml-CUju4iq0.js} +1 -1
  316. package/dist/ui/assets/{zephir-KRcdQfEX.js → zephir-ChVpmD0Y.js} +1 -1
  317. package/dist/ui/index.html +2 -2
  318. package/dist/utils/__tests__/abort-signals.test.js +67 -0
  319. package/dist/utils/__tests__/db-maintenance.test.js +55 -0
  320. package/dist/utils/__tests__/db-migration.test.js +79 -1
  321. package/dist/utils/__tests__/inject-loop.test.js +1 -53
  322. package/dist/utils/__tests__/learn-tasks-db.test.js +82 -0
  323. package/dist/utils/__tests__/openai-converter.test.js +25 -0
  324. package/dist/utils/__tests__/pi-crawl-tools.test.js +15 -4
  325. package/dist/utils/__tests__/pi-dedup-reconcile.test.js +11 -9
  326. package/dist/utils/__tests__/pi-events.test.d.ts +1 -0
  327. package/dist/utils/__tests__/pi-events.test.js +172 -0
  328. package/dist/utils/__tests__/pi-learn-orchestrator.test.js +216 -6
  329. package/dist/utils/__tests__/pi-runtime-json.test.js +38 -3
  330. package/dist/utils/__tests__/providers-db.test.js +40 -2
  331. package/dist/utils/__tests__/request-writer.test.js +532 -39
  332. package/dist/utils/__tests__/sse-protocol.test.d.ts +1 -0
  333. package/dist/utils/__tests__/sse-protocol.test.js +115 -0
  334. package/dist/utils/__tests__/stats-aggregator.test.d.ts +1 -0
  335. package/dist/utils/__tests__/stats-aggregator.test.js +114 -0
  336. package/dist/utils/__tests__/vault.test.d.ts +1 -0
  337. package/dist/utils/__tests__/{knowledge-store.test.js → vault.test.js} +16 -16
  338. package/dist/utils/abort-signals.d.ts +13 -0
  339. package/dist/utils/abort-signals.js +33 -0
  340. package/dist/utils/db-maintenance.d.ts +8 -0
  341. package/dist/utils/db-maintenance.js +18 -0
  342. package/dist/utils/db.d.ts +2 -0
  343. package/dist/utils/db.js +86 -0
  344. package/dist/utils/esm-dirname.d.ts +0 -15
  345. package/dist/utils/esm-dirname.js +0 -4
  346. package/dist/utils/inject-loop.d.ts +0 -27
  347. package/dist/utils/inject-loop.js +2 -56
  348. package/dist/utils/learn-tasks-db.d.ts +15 -0
  349. package/dist/utils/learn-tasks-db.js +35 -0
  350. package/dist/utils/openai-converter.js +88 -78
  351. package/dist/utils/pi-browser-tools.d.ts +0 -2
  352. package/dist/utils/pi-browser-tools.js +0 -174
  353. package/dist/utils/pi-crawl-tools.d.ts +2 -1
  354. package/dist/utils/pi-crawl-tools.js +16 -11
  355. package/dist/utils/pi-dedup.d.ts +8 -30
  356. package/dist/utils/pi-dedup.js +32 -67
  357. package/dist/utils/pi-events.d.ts +65 -0
  358. package/dist/utils/pi-events.js +98 -0
  359. package/dist/utils/pi-learn-orchestrator.d.ts +6 -5
  360. package/dist/utils/pi-learn-orchestrator.js +71 -106
  361. package/dist/utils/pi-runtime.d.ts +5 -6
  362. package/dist/utils/pi-runtime.js +38 -42
  363. package/dist/utils/pi-sandbox-ops.d.ts +0 -36
  364. package/dist/utils/pi-sandbox-ops.js +5 -190
  365. package/dist/utils/providers-db.d.ts +3 -0
  366. package/dist/utils/providers-db.js +21 -7
  367. package/dist/utils/request-writer.d.ts +77 -26
  368. package/dist/utils/request-writer.js +362 -56
  369. package/dist/utils/sse-protocol.d.ts +34 -0
  370. package/dist/utils/sse-protocol.js +121 -0
  371. package/dist/utils/sse-stream-processor.d.ts +4 -9
  372. package/dist/utils/sse-stream-processor.js +13 -104
  373. package/dist/utils/sse-writer.d.ts +1 -1
  374. package/dist/utils/sse-writer.js +3 -2
  375. package/dist/utils/stats-aggregator.d.ts +1 -1
  376. package/dist/utils/stats-aggregator.js +44 -24
  377. package/dist/utils/tool-injector.js +7 -0
  378. package/dist/utils/vault.d.ts +111 -0
  379. package/dist/utils/vault.js +434 -0
  380. package/ecosystem.config.cjs +2 -1
  381. package/package.json +1 -1
  382. package/dist/docs/assets/chunks/@localSearchIndexroot.B6Qfxe6W.js +0 -1
  383. package/dist/server/middleware/__tests__/request-id.test.js +0 -28
  384. package/dist/server/middleware/request-id.d.ts +0 -2
  385. package/dist/server/middleware/request-id.js +0 -12
  386. package/dist/types/api.d.ts +0 -20
  387. package/dist/types/index.d.ts +0 -4
  388. package/dist/types/index.js +0 -4
  389. package/dist/types/log.d.ts +0 -13
  390. package/dist/ui/assets/channel-Bc4Td8eZ.js +0 -1
  391. package/dist/ui/assets/classDiagram-OUVF2IWQ-BicxhZFq.js +0 -1
  392. package/dist/ui/assets/classDiagram-v2-EOCWNBFH-BicxhZFq.js +0 -1
  393. package/dist/ui/assets/index-C0fxlU9d.css +0 -10
  394. package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-QvaEO5U6.js +0 -1
  395. package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DPgCOY0D.js +0 -8
  396. package/dist/utils/__tests__/sse-accumulator.test.js +0 -83
  397. package/dist/utils/knowledge-store.d.ts +0 -51
  398. package/dist/utils/knowledge-store.js +0 -241
  399. package/dist/utils/migrate-files-to-db.d.ts +0 -1
  400. package/dist/utils/migrate-files-to-db.js +0 -138
  401. package/dist/utils/sse-accumulator.d.ts +0 -9
  402. package/dist/utils/sse-accumulator.js +0 -59
  403. /package/dist/docs/assets/{proxy-cli_data-hooks.md.w9Oe1OD3.lean.js → proxy-cli_data-hooks.md.Bz8CVbxO.lean.js} +0 -0
  404. /package/dist/docs/assets/{proxy-core_ui-routes.md.Dyqkeoiv.lean.js → proxy-core_ui-routes.md.B21t1p7R.lean.js} +0 -0
  405. /package/dist/server/{middleware/__tests__/request-id.test.d.ts → __tests__/data-push.test.d.ts} +0 -0
  406. /package/dist/{types/api.js → utils/__tests__/abort-signals.test.d.ts} +0 -0
  407. /package/dist/{types/log.js → utils/__tests__/db-maintenance.test.d.ts} +0 -0
  408. /package/dist/utils/__tests__/{knowledge-store.test.d.ts → learn-tasks-db.test.d.ts} +0 -0
  409. /package/dist/utils/__tests__/{sse-accumulator.test.d.ts → openai-converter.test.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
- export interface RequestData {
2
- requestId: string;
1
+ export interface RecordedRequest {
3
2
  sessionId: string;
3
+ localRequestId: string;
4
4
  timestamp: string;
5
5
  apiKey?: string;
6
6
  proxyApiKey?: string;
@@ -13,14 +13,6 @@ export interface RequestData {
13
13
  headers: Record<string, string>;
14
14
  body?: any;
15
15
  };
16
- response?: {
17
- statusCode: number;
18
- headers?: Record<string, string>;
19
- events?: any[];
20
- completedAt?: string;
21
- closedAt?: string;
22
- error?: string;
23
- };
24
16
  }
25
17
  export interface TokenUsage {
26
18
  input_tokens?: number;
@@ -44,33 +36,92 @@ export interface RequestSummary {
44
36
  machineId?: string;
45
37
  userAgent?: string;
46
38
  usage?: TokenUsage;
39
+ closedAt?: string;
40
+ error?: string;
41
+ }
42
+ export interface RequestRecorder {
43
+ pending(): Promise<void>;
44
+ appendEvent(event: any): void;
45
+ headers(args: {
46
+ statusCode: number;
47
+ headers?: Record<string, string>;
48
+ }): void;
49
+ complete(args: {
50
+ cloudRequestId?: string;
51
+ statusCode: number;
52
+ headers?: Record<string, string>;
53
+ }): Promise<void>;
54
+ interrupt(args: {
55
+ statusCode: number;
56
+ error: string;
57
+ }): void;
58
+ fail(args: {
59
+ statusCode: number;
60
+ error: string;
61
+ }): void;
62
+ }
63
+ interface LoadedRequest {
64
+ requestId: string;
65
+ sessionId: string;
66
+ timestamp: string;
67
+ apiKey?: string;
68
+ proxyApiKey?: string;
69
+ baseUrl?: string;
70
+ model?: string;
71
+ machineId?: string;
72
+ request: {
73
+ method: string;
74
+ path: string;
75
+ headers: Record<string, string>;
76
+ body?: any;
77
+ };
78
+ response?: {
79
+ statusCode: number;
80
+ headers?: Record<string, string>;
81
+ events?: any[];
82
+ completedAt?: string;
83
+ closedAt?: string;
84
+ error?: string;
85
+ };
47
86
  }
48
- export declare function extractTokenUsage(events: any[] | undefined): TokenUsage | undefined;
49
- export declare const EVENT_BATCH_SIZE = 10;
50
87
  /**
51
- * Flush a batch of SSE events to the response_events table.
52
- * Called during streaming every ~10 events to avoid in-memory accumulation.
88
+ * 判断事件集合是否构成一条完整返回的流。
89
+ * Claude:出现 type === 'message_stop'。
90
+ * OpenAI 兼容:chunk 内 choices[0].finish_reason 非空
91
+ * ([DONE] 不入库,不能作为 DB 判定依据)。
53
92
  */
54
- export declare function flushEventBatch(sessionId: string, requestId: string, batch: Array<{
55
- index: number;
56
- type?: string;
57
- data: unknown;
58
- }>, startIndex: number): void;
93
+ export declare function isStreamCompleteEvents(events: any[] | undefined): boolean;
59
94
  /**
60
- * Delete response_events rows for a request (used when cloudRequestId differs from local requestId).
95
+ * 从事件集合按字段合并重建 usage,不做整体覆盖。
96
+ * Claude:message_start.usage(input_tokens / cache_*)为底;
97
+ * message_delta.usage 的字段优先(output_tokens 为主,cache 字段也合入)。
98
+ * OpenAI:取带 .usage 的 chunk(prompt_tokens/completion_tokens)。
61
99
  */
62
- export declare function deleteResponseEvents(requestId: string, sessionId: string): void;
63
- export declare function saveRequestDB(sessionId: string, requestId: string, data: RequestData): Promise<void>;
64
- export declare function updateRequestTokens(requestId: string, sessionId: string, usage: TokenUsage | undefined): void;
65
- export declare function deleteRequestRow(requestId: string, sessionId: string): void;
66
- export declare function loadRequestDB(compositeId: string): Promise<RequestData>;
100
+ export declare function reconstructUsageFromEvents(events: any[] | undefined): TokenUsage | undefined;
101
+ export declare function createRequestRecorder(meta: RecordedRequest): RequestRecorder;
102
+ export declare function recordIteration(meta: RecordedRequest & {
103
+ response: {
104
+ statusCode: number;
105
+ headers?: Record<string, string>;
106
+ events?: any[];
107
+ };
108
+ }): Promise<void>;
109
+ export declare function loadRequestDB(compositeId: string): Promise<LoadedRequest>;
67
110
  export declare function listRequestDB(limit?: number, before?: string): Promise<{
68
111
  requests: RequestSummary[];
69
112
  hasMore: boolean;
70
113
  }>;
71
114
  export declare function cleanOldRequestsDB(daysToKeep?: number): Promise<void>;
72
- export declare function sessionIdExists(sessionId: string): boolean;
115
+ export declare function interruptStaleRequestsOnStartup(maxAgeMs?: number): {
116
+ completed: number;
117
+ interrupted: number;
118
+ };
119
+ export declare function repairClosedRequests(): {
120
+ recovered: number;
121
+ tokensFilled: number;
122
+ };
73
123
  export declare function loadSessionHistory(sessionId: string): {
74
124
  messages: any[];
75
125
  system?: any;
76
126
  } | null;
127
+ export {};
@@ -1,62 +1,153 @@
1
1
  import { initDatabase, getDatabase } from './db.js';
2
2
  import { parseUpstreamEvents } from './inject-loop.js';
3
- export function extractTokenUsage(events) {
4
- if (!events)
5
- return undefined;
6
- const messageDelta = events.find((e) => e?.type === 'message_delta');
7
- return messageDelta?.usage;
8
- }
9
- // --- SSE Event Batch Writer (incremental DB writes during streaming) ---
10
- export const EVENT_BATCH_SIZE = 10;
11
- // Cached prepared statements for batch writes
3
+ import { pushNewRequest } from '../server/data-push.js';
4
+ // --- Private implementation ---
5
+ const EVENT_BATCH_SIZE = 10;
6
+ // Cached prepared statement for batch writes
12
7
  let insertEventStmt = null;
13
- let deleteRequestStmt = null;
14
8
  let cachedDbInstance = null;
15
- // Invalidate cached stmts when DB instance changes (tests create fresh DB per suite)
9
+ // Invalidate cached stmt when DB instance changes (tests create fresh DB per suite)
16
10
  function ensureStmtCacheValid(db) {
17
11
  if (db !== cachedDbInstance) {
18
12
  insertEventStmt = null;
19
- deleteRequestStmt = null;
20
13
  cachedDbInstance = db;
21
14
  }
22
15
  }
23
16
  /**
24
17
  * Flush a batch of SSE events to the response_events table.
25
- * Called during streaming every ~10 events to avoid in-memory accumulation.
26
18
  */
27
- export function flushEventBatch(sessionId, requestId, batch, startIndex) {
19
+ function flushEventBatch(sessionId, requestId, batch, startIndex) {
28
20
  const db = getDatabase();
29
21
  ensureStmtCacheValid(db);
30
22
  if (!insertEventStmt) {
31
- insertEventStmt = db.prepare('INSERT INTO response_events (request_id, session_id, event_index, event_type, event_data) VALUES (?, ?, ?, ?, ?)');
23
+ insertEventStmt = db.prepare('INSERT OR IGNORE INTO response_events (request_id, session_id, event_index, event_type, event_data) VALUES (?, ?, ?, ?, ?)');
32
24
  }
33
25
  for (let i = 0; i < batch.length; i++) {
34
26
  const event = batch[i];
35
27
  insertEventStmt.run(requestId, sessionId, startIndex + i, event.type ?? null, JSON.stringify(event.data));
36
28
  }
37
29
  }
30
+ function extractUsage(events) {
31
+ if (!events)
32
+ return undefined;
33
+ const messageDelta = events.find((e) => e?.type === 'message_delta');
34
+ return messageDelta?.usage;
35
+ }
36
+ // --- 流完整性判定与 usage 重建(纯函数,事件数组入参)---
38
37
  /**
39
- * Delete response_events rows for a request (used when cloudRequestId differs from local requestId).
38
+ * 判断事件集合是否构成一条完整返回的流。
39
+ * Claude:出现 type === 'message_stop'。
40
+ * OpenAI 兼容:chunk 内 choices[0].finish_reason 非空
41
+ * ([DONE] 不入库,不能作为 DB 判定依据)。
40
42
  */
41
- export function deleteResponseEvents(requestId, sessionId) {
42
- const db = getDatabase();
43
- db.prepare('DELETE FROM response_events WHERE request_id = ? AND session_id = ?').run(requestId, sessionId);
43
+ export function isStreamCompleteEvents(events) {
44
+ if (!Array.isArray(events))
45
+ return false;
46
+ return events.some(e => {
47
+ if (!e || typeof e !== 'object')
48
+ return false;
49
+ if (e.type === 'message_stop')
50
+ return true;
51
+ const finishReason = e.choices?.[0]?.finish_reason;
52
+ return finishReason !== undefined && finishReason !== null && finishReason !== '';
53
+ });
44
54
  }
45
- // --- Request DB Operations ---
46
- // Save request to SQLite database
47
- export async function saveRequestDB(sessionId, requestId, data) {
48
- const db = initDatabase();
49
- const events = data.response?.events;
50
- const usage = events ? extractTokenUsage(events) : undefined;
51
- // For JSON responses (non-streaming), events are still in the array — flush them first
52
- if (events && events.length > 0) {
53
- const batch = events.map((e, i) => ({
54
- index: i,
55
- type: e?.type ?? undefined,
56
- data: e
57
- }));
58
- flushEventBatch(sessionId, requestId, batch, 0);
55
+ /**
56
+ * 从事件集合按字段合并重建 usage,不做整体覆盖。
57
+ * Claude:message_start.usage(input_tokens / cache_*)为底;
58
+ * message_delta.usage 的字段优先(output_tokens 为主,cache 字段也合入)。
59
+ * OpenAI:取带 .usage 的 chunk(prompt_tokens/completion_tokens)。
60
+ */
61
+ export function reconstructUsageFromEvents(events) {
62
+ if (!Array.isArray(events))
63
+ return undefined;
64
+ const usage = {};
65
+ let found = false;
66
+ const merge = (field, value, precedence) => {
67
+ if (typeof value !== 'number')
68
+ return;
69
+ if (precedence || usage[field] === undefined) {
70
+ usage[field] = value;
71
+ found = true;
72
+ }
73
+ };
74
+ for (const e of events) {
75
+ if (!e || typeof e !== 'object')
76
+ continue;
77
+ if (e.type === 'message_start' || e.type === 'message_delta') {
78
+ const u = e.usage;
79
+ if (u && typeof u === 'object') {
80
+ const isDelta = e.type === 'message_delta';
81
+ merge('input_tokens', u.input_tokens, isDelta);
82
+ merge('output_tokens', u.output_tokens, isDelta);
83
+ merge('cache_read_input_tokens', u.cache_read_input_tokens, isDelta);
84
+ merge('cache_creation_input_tokens', u.cache_creation_input_tokens, isDelta);
85
+ }
86
+ }
87
+ // OpenAI 兼容:带 usage 的 chunk(event_type 通常为 NULL)
88
+ if (e.usage && typeof e.usage === 'object' && e.type !== 'message_start' && e.type !== 'message_delta') {
89
+ const u = e.usage;
90
+ merge('input_tokens', u.input_tokens ?? u.prompt_tokens, false);
91
+ merge('output_tokens', u.output_tokens ?? u.completion_tokens, false);
92
+ }
59
93
  }
94
+ return found ? usage : undefined;
95
+ }
96
+ // 定向加载重建所需事件,禁止全量加载事件流(实测有 8000+ 行):
97
+ // 1) Claude 锚点事件(message_start/message_delta/message_stop,通常仅数行)
98
+ // 2) 尾部 10 条事件(覆盖 OpenAI 的 finish_reason / usage,其 event_type 可能为 NULL)
99
+ function loadTargetedEvents(db, requestId, sessionId) {
100
+ const anchorRows = db.prepare(`
101
+ SELECT event_data FROM response_events
102
+ WHERE request_id = ? AND session_id = ?
103
+ AND event_type IN ('message_start', 'message_delta', 'message_stop')
104
+ ORDER BY event_index ASC
105
+ `).all(requestId, sessionId);
106
+ const tailRows = db.prepare(`
107
+ SELECT event_data FROM response_events
108
+ WHERE request_id = ? AND session_id = ?
109
+ ORDER BY event_index DESC
110
+ LIMIT 10
111
+ `).all(requestId, sessionId);
112
+ const seen = new Set();
113
+ const events = [];
114
+ for (const row of [...anchorRows, ...tailRows]) {
115
+ if (seen.has(row.event_data))
116
+ continue;
117
+ seen.add(row.event_data);
118
+ try {
119
+ events.push(JSON.parse(row.event_data));
120
+ }
121
+ catch {
122
+ // 忽略损坏行
123
+ }
124
+ }
125
+ return events;
126
+ }
127
+ // 按字段回填 token 列(只补 NULL 列),返回是否有列被更新
128
+ function fillTokenColumns(db, requestId, sessionId, usage) {
129
+ const current = db.prepare(`
130
+ SELECT input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens
131
+ FROM requests WHERE request_id = ? AND session_id = ?
132
+ `).get(requestId, sessionId);
133
+ if (!current)
134
+ return false;
135
+ const pairs = [
136
+ ['input_tokens', usage.input_tokens],
137
+ ['output_tokens', usage.output_tokens],
138
+ ['cache_read_tokens', usage.cache_read_input_tokens],
139
+ ['cache_creation_tokens', usage.cache_creation_input_tokens]
140
+ ];
141
+ const updatable = pairs.filter(([col, v]) => current[col] === null && typeof v === 'number');
142
+ if (updatable.length === 0)
143
+ return false;
144
+ const setSql = updatable.map(([col]) => `${col} = ?`).join(', ');
145
+ db.prepare(`UPDATE requests SET ${setSql} WHERE request_id = ? AND session_id = ?`).run(...updatable.map(([, v]) => v), requestId, sessionId);
146
+ return true;
147
+ }
148
+ function writeCompletedRow(args) {
149
+ const db = getDatabase();
150
+ const { meta } = args;
60
151
  const stmt = db.prepare(`
61
152
  INSERT OR REPLACE INTO requests (
62
153
  request_id, session_id, timestamp, method, path, status_code, response_time,
@@ -68,24 +159,171 @@ export async function saveRequestDB(sessionId, requestId, data) {
68
159
  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
69
160
  )
70
161
  `);
71
- stmt.run(requestId, sessionId, data.timestamp, data.request.method, data.request.path, data.response?.statusCode ?? 0, data.response?.completedAt && data.timestamp
72
- ? Math.round(new Date(data.response.completedAt).getTime() - new Date(data.timestamp).getTime())
73
- : 0, data.apiKey || null, data.proxyApiKey || null, data.baseUrl || null, data.model || null, data.machineId || null, data.request.headers['user-agent'] || null, usage?.input_tokens || null, usage?.output_tokens || null, usage?.cache_read_input_tokens || null, usage?.cache_creation_input_tokens || null, JSON.stringify(data.request.headers), data.request.body ? JSON.stringify(data.request.body) : null, data.response?.headers ? JSON.stringify(data.response.headers) : null, null, // response_events now stored in separate table
74
- data.response?.completedAt || null, data.response?.closedAt || null, data.response?.error || null);
162
+ stmt.run(args.requestId, meta.sessionId, meta.timestamp, meta.request.method, meta.request.path, args.statusCode, args.responseTime, meta.apiKey || null, meta.proxyApiKey || null, meta.baseUrl || null, meta.model || null, meta.machineId || null, meta.request.headers['user-agent'] || null, args.usage?.input_tokens || null, args.usage?.output_tokens || null, args.usage?.cache_read_input_tokens || null, args.usage?.cache_creation_input_tokens || null, JSON.stringify(meta.request.headers), meta.request.body ? JSON.stringify(meta.request.body) : null, args.headers ? JSON.stringify(args.headers) : null, null, // response_events now stored in separate table
163
+ args.completedAt || null, args.closedAt || null, args.error || null);
75
164
  }
76
- // Update token columns for a request (streaming: usage extracted from tailBuffer after save)
77
- export function updateRequestTokens(requestId, sessionId, usage) {
78
- const db = getDatabase();
79
- db.prepare('UPDATE requests SET input_tokens = ?, output_tokens = ?, cache_read_tokens = ?, cache_creation_tokens = ? WHERE request_id = ? AND session_id = ?').run(usage?.input_tokens || null, usage?.output_tokens || null, usage?.cache_read_input_tokens || null, usage?.cache_creation_input_tokens || null, requestId, sessionId);
165
+ function buildSummary(meta, requestId, statusCode, responseTime, usage, withPendingId, closedAt) {
166
+ return {
167
+ requestId,
168
+ sessionId: meta.sessionId,
169
+ compositeId: `${meta.sessionId}:${requestId}`,
170
+ timestamp: meta.timestamp,
171
+ method: meta.request.method,
172
+ path: meta.request.path,
173
+ statusCode,
174
+ responseTime,
175
+ baseUrl: meta.baseUrl,
176
+ model: meta.model,
177
+ machineId: meta.machineId,
178
+ userAgent: meta.request.headers['user-agent'],
179
+ usage,
180
+ pendingId: withPendingId ? `${meta.sessionId}:${meta.localRequestId}` : undefined,
181
+ closedAt
182
+ };
80
183
  }
81
- // Delete a request row by requestId + sessionId (for pending → completed replacement)
82
- export function deleteRequestRow(requestId, sessionId) {
83
- const db = getDatabase();
84
- ensureStmtCacheValid(db);
85
- if (!deleteRequestStmt) {
86
- deleteRequestStmt = db.prepare('DELETE FROM requests WHERE request_id = ? AND session_id = ?');
184
+ // --- Public API ---
185
+ export function createRequestRecorder(meta) {
186
+ const eventBatch = [];
187
+ const tailBuffer = [];
188
+ let eventIndex = 0;
189
+ const startTime = Date.now();
190
+ let pendingCalled = false;
191
+ // recorder 生命周期开始前的事件行下界。complete() 把事件从 localRequestId 迁到
192
+ // cloudRequestId 时只允许迁移 id 大于它的行:request_id(req-N 计数器)在进程
193
+ // 重启后可能复用,同 localRequestId 的历史残留事件属于别的请求,不能被一起迁走。
194
+ const startRow = getDatabase()
195
+ .prepare('SELECT MAX(id) AS m FROM response_events')
196
+ .get();
197
+ const startEventRowId = startRow.m ?? 0;
198
+ function flushRemaining() {
199
+ if (eventBatch.length > 0) {
200
+ flushEventBatch(meta.sessionId, meta.localRequestId, eventBatch, eventIndex - eventBatch.length);
201
+ eventBatch.length = 0;
202
+ }
87
203
  }
88
- deleteRequestStmt.run(requestId, sessionId);
204
+ function appendEvent(event) {
205
+ const entry = { index: eventIndex, type: event?.type, data: event };
206
+ eventBatch.push(entry);
207
+ // Maintain tail buffer (last 5 events for usage extraction)
208
+ tailBuffer.push(event);
209
+ if (tailBuffer.length > 5) {
210
+ tailBuffer.shift();
211
+ }
212
+ // Flush batch to DB when threshold reached
213
+ if (eventBatch.length >= EVENT_BATCH_SIZE) {
214
+ flushEventBatch(meta.sessionId, meta.localRequestId, eventBatch, eventIndex - eventBatch.length + 1);
215
+ eventBatch.length = 0; // Reset batch (memory freed)
216
+ }
217
+ eventIndex++;
218
+ }
219
+ return {
220
+ async pending() {
221
+ if (pendingCalled)
222
+ return;
223
+ pendingCalled = true;
224
+ writeCompletedRow({
225
+ meta,
226
+ requestId: meta.localRequestId,
227
+ statusCode: 0,
228
+ responseTime: 0
229
+ });
230
+ pushNewRequest(buildSummary(meta, meta.localRequestId, 0, 0, undefined, false), 'pending');
231
+ },
232
+ appendEvent,
233
+ // 上游响应头到达:回写真实 status_code,状态仍 pending(UI 保留 spinner)
234
+ headers({ statusCode, headers }) {
235
+ getDatabase().prepare('UPDATE requests SET status_code = ?, response_headers = ? WHERE request_id = ? AND session_id = ?').run(statusCode, headers ? JSON.stringify(headers) : null, meta.localRequestId, meta.sessionId);
236
+ pushNewRequest(buildSummary(meta, meta.localRequestId, statusCode, 0, undefined, false, undefined), 'pending');
237
+ },
238
+ async complete({ cloudRequestId, statusCode, headers }) {
239
+ // Flush remaining events in batch
240
+ flushRemaining();
241
+ // Usage synthesis: prefer message_delta, otherwise convert OpenAI-style usage
242
+ let usage = extractUsage(tailBuffer);
243
+ if (!usage) {
244
+ const openaiEvent = tailBuffer.find((e) => e?.usage);
245
+ if (openaiEvent) {
246
+ appendEvent({
247
+ type: 'message_delta',
248
+ usage: {
249
+ output_tokens: openaiEvent.usage.completion_tokens || 0
250
+ }
251
+ });
252
+ usage = extractUsage(tailBuffer);
253
+ }
254
+ }
255
+ // Ensure the synthetic event (if any) is written before row replacement
256
+ flushRemaining();
257
+ const completedAt = new Date().toISOString();
258
+ const finalId = cloudRequestId ?? meta.localRequestId;
259
+ const responseTime = Date.now() - startTime;
260
+ const db = getDatabase();
261
+ if (finalId !== meta.localRequestId) {
262
+ const replace = db.transaction(() => {
263
+ // id > startEventRowId:只迁本 recorder 创建后写入的事件,
264
+ // 不迁同 localRequestId 的历史残留事件
265
+ db.prepare('UPDATE response_events SET request_id = ? WHERE request_id = ? AND session_id = ? AND id > ?').run(finalId, meta.localRequestId, meta.sessionId, startEventRowId);
266
+ writeCompletedRow({
267
+ meta, requestId: finalId, statusCode, responseTime, headers, usage, completedAt
268
+ });
269
+ db.prepare('DELETE FROM requests WHERE request_id = ? AND session_id = ?').run(meta.localRequestId, meta.sessionId);
270
+ });
271
+ replace();
272
+ }
273
+ else {
274
+ writeCompletedRow({
275
+ meta, requestId: finalId, statusCode, responseTime, headers, usage, completedAt
276
+ });
277
+ }
278
+ pushNewRequest(buildSummary(meta, finalId, statusCode, responseTime, usage, finalId !== meta.localRequestId), 'completed');
279
+ },
280
+ // 流被截断/挂死:保留真实 status_code,通过 closed_at + error 标记中断;
281
+ // 同时通过定向 SQL(锚点事件 + 尾部事件)重建 usage 并按字段回填 token
282
+ interrupt({ statusCode, error }) {
283
+ flushRemaining();
284
+ const db = getDatabase();
285
+ const responseTime = Date.now() - startTime;
286
+ const closedAt = new Date().toISOString();
287
+ db.prepare('UPDATE requests SET status_code = ?, response_time = ?, closed_at = ?, error = ? WHERE request_id = ? AND session_id = ?').run(statusCode, responseTime, closedAt, error, meta.localRequestId, meta.sessionId);
288
+ const events = loadTargetedEvents(db, meta.localRequestId, meta.sessionId);
289
+ const usage = reconstructUsageFromEvents(events);
290
+ if (usage) {
291
+ fillTokenColumns(db, meta.localRequestId, meta.sessionId, usage);
292
+ }
293
+ pushNewRequest(buildSummary(meta, meta.localRequestId, statusCode, responseTime, usage, false, closedAt), 'completed');
294
+ },
295
+ fail({ statusCode, error }) {
296
+ const responseTime = Date.now() - startTime;
297
+ const closedAt = new Date().toISOString();
298
+ getDatabase().prepare('UPDATE requests SET status_code = ?, response_time = ?, closed_at = ?, error = ? WHERE request_id = ? AND session_id = ?').run(statusCode, responseTime, closedAt, error, meta.localRequestId, meta.sessionId);
299
+ pushNewRequest(buildSummary(meta, meta.localRequestId, statusCode, responseTime, undefined, false, closedAt), 'completed');
300
+ }
301
+ };
302
+ }
303
+ // Record an inject loop iteration: completed row + events + push, no pending, responseTime 0
304
+ export async function recordIteration(meta) {
305
+ initDatabase();
306
+ const events = meta.response.events ?? [];
307
+ if (events.length > 0) {
308
+ const batch = events.map((e, i) => ({
309
+ index: i,
310
+ type: e?.type,
311
+ data: e
312
+ }));
313
+ flushEventBatch(meta.sessionId, meta.localRequestId, batch, 0);
314
+ }
315
+ const usage = extractUsage(events);
316
+ const completedAt = new Date().toISOString();
317
+ writeCompletedRow({
318
+ meta,
319
+ requestId: meta.localRequestId,
320
+ statusCode: meta.response.statusCode,
321
+ responseTime: 0,
322
+ headers: meta.response.headers,
323
+ usage,
324
+ completedAt
325
+ });
326
+ pushNewRequest(buildSummary(meta, meta.localRequestId, meta.response.statusCode, 0, usage, false), 'completed');
89
327
  }
90
328
  // Load single request by compositeId (sessionId:requestId)
91
329
  export async function loadRequestDB(compositeId) {
@@ -165,7 +403,7 @@ export async function listRequestDB(limit = 1000, before) {
165
403
  SELECT
166
404
  request_id, session_id, timestamp, method, path, status_code, response_time,
167
405
  api_key, proxy_api_key, base_url, model, machine_id, user_agent,
168
- input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens
406
+ input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, closed_at, error
169
407
  FROM requests
170
408
  ${whereClause}
171
409
  ORDER BY timestamp DESC
@@ -194,7 +432,9 @@ export async function listRequestDB(limit = 1000, before) {
194
432
  output_tokens: row.output_tokens,
195
433
  cache_read_input_tokens: row.cache_read_tokens,
196
434
  cache_creation_input_tokens: row.cache_creation_tokens
197
- } : undefined
435
+ } : undefined,
436
+ closedAt: row.closed_at || undefined,
437
+ error: row.error || undefined
198
438
  })),
199
439
  hasMore
200
440
  };
@@ -211,14 +451,80 @@ export async function cleanOldRequestsDB(daysToKeep = 7) {
211
451
  // Delete response_events first (foreign data), then requests
212
452
  db.prepare(`DELETE FROM response_events WHERE request_id IN (SELECT request_id FROM requests WHERE timestamp < ?)`).run(cutoff);
213
453
  db.prepare(`DELETE FROM requests WHERE timestamp < ?`).run(cutoff);
454
+ // 例行还页:auto_vacuum 未开启时为 no-op;经 ccm vacuum 开启
455
+ // INCREMENTAL 后,删除产生的空闲页在此廉价归还文件系统。
456
+ db.pragma('incremental_vacuum');
214
457
  }
215
- // Check if a sessionId exists in the database
216
- export function sessionIdExists(sessionId) {
458
+ // 启动时回收上次进程遗留的僵尸 SSE 行:未完成、未关闭且超龄,逐行分流
459
+ // (status_code 保持原值不动)——事件流完整(message_stop / OpenAI finish_reason)
460
+ // 的走完成语义:写 completed_at,不写 closed_at/error;不完整的维持
461
+ // closed_at + 'interrupted: proxy restarted'。两条路径都按字段回填 token 列。
462
+ export function interruptStaleRequestsOnStartup(maxAgeMs = 5 * 60000) {
217
463
  const db = initDatabase();
218
- const row = db.prepare(`
219
- SELECT 1 FROM requests WHERE session_id = ? LIMIT 1
220
- `).get(sessionId);
221
- return !!row;
464
+ const cutoff = new Date(Date.now() - maxAgeMs).toISOString();
465
+ const rows = db.prepare(`
466
+ SELECT request_id, session_id, timestamp, response_time
467
+ FROM requests
468
+ WHERE completed_at IS NULL AND closed_at IS NULL AND timestamp < ?
469
+ `).all(cutoff);
470
+ let completed = 0;
471
+ let interrupted = 0;
472
+ const nowIso = new Date().toISOString();
473
+ for (const row of rows) {
474
+ const events = loadTargetedEvents(db, row.request_id, row.session_id);
475
+ const usage = reconstructUsageFromEvents(events);
476
+ if (isStreamCompleteEvents(events)) {
477
+ // response_time 原值为 0(pending 占位)时,用 timestamp→现在给合理值
478
+ const responseTime = row.response_time > 0
479
+ ? row.response_time
480
+ : Math.max(0, Date.now() - Date.parse(row.timestamp));
481
+ db.prepare('UPDATE requests SET completed_at = ?, response_time = ? WHERE request_id = ? AND session_id = ?').run(nowIso, responseTime, row.request_id, row.session_id);
482
+ completed += 1;
483
+ }
484
+ else {
485
+ db.prepare('UPDATE requests SET closed_at = ?, error = ? WHERE request_id = ? AND session_id = ?').run(nowIso, 'interrupted: proxy restarted', row.request_id, row.session_id);
486
+ interrupted += 1;
487
+ }
488
+ if (usage) {
489
+ fillTokenColumns(db, row.request_id, row.session_id, usage);
490
+ }
491
+ }
492
+ return { completed, interrupted };
493
+ }
494
+ // 存量回填(供 CLI repair-requests 使用),幂等可重跑:
495
+ // 扫描 closed_at 非空的行——事件流完整且 completed_at 为空的:清 closed_at/error、
496
+ // 写 completed_at(completed_at 已非空的跳过);对 token 全 NULL 但事件可恢复
497
+ // usage 的行按字段补 token。同样只走定向 SQL。
498
+ export function repairClosedRequests() {
499
+ const db = initDatabase();
500
+ const rows = db.prepare(`
501
+ SELECT
502
+ request_id, session_id, completed_at,
503
+ input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens
504
+ FROM requests
505
+ WHERE closed_at IS NOT NULL
506
+ `).all();
507
+ let recovered = 0;
508
+ let tokensFilled = 0;
509
+ const nowIso = new Date().toISOString();
510
+ for (const row of rows) {
511
+ const events = loadTargetedEvents(db, row.request_id, row.session_id);
512
+ if (row.completed_at === null && isStreamCompleteEvents(events)) {
513
+ db.prepare('UPDATE requests SET closed_at = NULL, error = NULL, completed_at = ? WHERE request_id = ? AND session_id = ?').run(nowIso, row.request_id, row.session_id);
514
+ recovered += 1;
515
+ }
516
+ const allTokensNull = row.input_tokens === null &&
517
+ row.output_tokens === null &&
518
+ row.cache_read_tokens === null &&
519
+ row.cache_creation_tokens === null;
520
+ if (allTokensNull) {
521
+ const usage = reconstructUsageFromEvents(events);
522
+ if (usage && fillTokenColumns(db, row.request_id, row.session_id, usage)) {
523
+ tokensFilled += 1;
524
+ }
525
+ }
526
+ }
527
+ return { recovered, tokensFilled };
222
528
  }
223
529
  // Load session history for multi-turn chat resume
224
530
  // Returns the last request's messages + assistant response, to prepend to new messages
@@ -0,0 +1,34 @@
1
+ /**
2
+ * SSE 帧协议:字节流 ↔ SSE 帧 的唯一知识收敛点。
3
+ *
4
+ * - SSE 帧(frame):字节流按 SSE 规范切分出的单位,由若干字段行
5
+ * (event: / data: / id: / 注释 / 空行分发)组成。
6
+ * - SSE 事件(event):SSE 帧的 data 字段解析出的 JSON 消息。
7
+ *
8
+ * 解析遵循 HTML spec 的 event stream 语义:残帧缓冲、LF/CRLF/CR 行尾、
9
+ * 空行分发、字段行去掉恰好一个可选空格。
10
+ */
11
+ export interface SSEFrame {
12
+ event?: string;
13
+ data: string[];
14
+ id?: string;
15
+ }
16
+ export interface SSEDecoder {
17
+ write(chunk: Buffer | string): void;
18
+ end(): void;
19
+ }
20
+ /** 创建 SSE 帧解码器:每分发一个完整 SSE 帧回调一次 */
21
+ export declare function createSSEDecoder(onFrame: (frame: SSEFrame) => void): SSEDecoder;
22
+ /**
23
+ * 编码单个 SSE 帧。data 为已序列化好的字符串(调用方负责 JSON.stringify)。
24
+ * 有 event:`event: <event>\ndata: <data>\n\n`;无 event:`data: <data>\n\n`。
25
+ */
26
+ export declare function encodeSSEFrame(args: {
27
+ event?: string;
28
+ data: string;
29
+ }): string;
30
+ /**
31
+ * 创建 SSE 事件解码器:帧 data 用 \n join 后,[DONE] 触发 onDone,
32
+ * 其余尝试 JSON.parse 成功后触发 onEvent,解析失败静默跳过。
33
+ */
34
+ export declare function createEventDecoder(onEvent: (event: any) => void, onDone?: () => void): SSEDecoder;