@cc-monitoring/proxy-core 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/404.html +1 -1
- package/dist/docs/assets/{app.6_CicOIJ.js → app.B9A39uFv.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.B6Qfxe6W.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.ZMWZsg8z.js → VPLocalSearchBox.DdhC696L.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BkvhsjzH.js → theme.CfB2tOFi.js} +2 -2
- package/dist/docs/index.html +2 -2
- package/dist/docs/overview.html +2 -2
- package/dist/docs/packages-utils.html +2 -2
- package/dist/docs/proxy-admin/env-and-build.html +2 -2
- package/dist/docs/proxy-admin/index.html +2 -2
- package/dist/docs/proxy-admin/layout-and-menu.html +2 -2
- package/dist/docs/proxy-admin/pages.html +2 -2
- package/dist/docs/proxy-admin/routing-and-auth.html +2 -2
- package/dist/docs/proxy-admin/services-and-mock.html +2 -2
- package/dist/docs/proxy-cli/api-layer.html +2 -2
- package/dist/docs/proxy-cli/app-shell.html +2 -2
- package/dist/docs/proxy-cli/components-common.html +2 -2
- package/dist/docs/proxy-cli/components-config.html +2 -2
- package/dist/docs/proxy-cli/components-requests.html +2 -2
- package/dist/docs/proxy-cli/components-stats.html +2 -2
- package/dist/docs/proxy-cli/components-status.html +2 -2
- package/dist/docs/proxy-cli/data-hooks.html +2 -2
- package/dist/docs/proxy-cli/index.html +2 -2
- package/dist/docs/proxy-cli/utils-and-i18n.html +2 -2
- package/dist/docs/proxy-core/chat-api.html +2 -2
- package/dist/docs/proxy-core/cli.html +2 -2
- package/dist/docs/proxy-core/config.html +2 -2
- package/dist/docs/proxy-core/data-layer.html +2 -2
- package/dist/docs/proxy-core/entry.html +2 -2
- package/dist/docs/proxy-core/index.html +2 -2
- package/dist/docs/proxy-core/pm2.html +2 -2
- package/dist/docs/proxy-core/providers.html +2 -2
- package/dist/docs/proxy-core/proxy.html +2 -2
- package/dist/docs/proxy-core/stats.html +2 -2
- package/dist/docs/proxy-core/tool.html +2 -2
- package/dist/docs/proxy-core/ui-routes.html +2 -2
- package/dist/docs/proxy-core/utilities.html +2 -2
- package/dist/docs/quickstart.html +2 -2
- package/dist/docs/request-flow.html +2 -2
- package/dist/mcp-server/index.js +5 -3
- package/dist/mcp-server/tools.js +24 -2
- package/dist/server/__tests__/server.test.js +9 -1
- package/dist/server/__tests__/ui-route.test.js +8 -0
- package/dist/server/chat-route.js +6 -0
- package/dist/server/proxy.js +5 -0
- package/dist/server/ui-route.js +113 -7
- package/dist/ui/assets/{1c-HTPXddJd.js → 1c-DAu68mP4.js} +1 -1
- package/dist/ui/assets/{abnf-bINSkl_m.js → abnf-Cu8RHCHK.js} +1 -1
- package/dist/ui/assets/{abnfDiagram-VRR7QNED-ClDzCbvw.js → abnfDiagram-VRR7QNED-BUBToPXF.js} +1 -1
- package/dist/ui/assets/{accesslog-BAnIWzpe.js → accesslog-BG-34XOy.js} +1 -1
- package/dist/ui/assets/{actionscript-DVcm6F_C.js → actionscript-iw0HHMGM.js} +1 -1
- package/dist/ui/assets/{ada-Cxn-QX4j.js → ada-qRqj6VGQ.js} +1 -1
- package/dist/ui/assets/{angelscript-BAwAPvBQ.js → angelscript-BeaXyx_P.js} +1 -1
- package/dist/ui/assets/{apache-CjjovgUx.js → apache-CU8d-z9X.js} +1 -1
- package/dist/ui/assets/{applescript-VUcyXoVh.js → applescript-d1Wxkqz1.js} +1 -1
- package/dist/ui/assets/{arc-3Nou_aku.js → arc-BMsPIm3j.js} +1 -1
- package/dist/ui/assets/{arcade-Dz2VAk7O.js → arcade-CtbgrWTM.js} +1 -1
- package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-DhwSsCdN.js → architectureDiagram-ZJ3FMSHR-CVjC5TrS.js} +1 -1
- package/dist/ui/assets/{arduino-B-Ptb1K1.js → arduino-Bc9L39Hr.js} +1 -1
- package/dist/ui/assets/{armasm-DU_6qZlW.js → armasm-DuWmpjWR.js} +1 -1
- package/dist/ui/assets/{asciidoc-DYbYiWKT.js → asciidoc-CDIhFTnx.js} +1 -1
- package/dist/ui/assets/{aspectj-CmdNkqAs.js → aspectj-SYj-57Es.js} +1 -1
- package/dist/ui/assets/{autohotkey-if9QUvYo.js → autohotkey-hBi5dq37.js} +1 -1
- package/dist/ui/assets/{autoit-DGU3G1s6.js → autoit-BSawXzhg.js} +1 -1
- package/dist/ui/assets/{avrasm-1zsEtPJ6.js → avrasm-CwYom8Np.js} +1 -1
- package/dist/ui/assets/{awk-CvmeshSq.js → awk-BvBRfGo2.js} +1 -1
- package/dist/ui/assets/{axapta-CbJGb5cN.js → axapta-CqUavA8k.js} +1 -1
- package/dist/ui/assets/{bash-CFXg_i2e.js → bash-BS_ZnmEu.js} +1 -1
- package/dist/ui/assets/{basic-6atic5cT.js → basic-xbP4IXrN.js} +1 -1
- package/dist/ui/assets/{blockDiagram-677ZJIJ3-BKXinDkB.js → blockDiagram-677ZJIJ3-CmpI3f5p.js} +1 -1
- package/dist/ui/assets/{bnf-DydAtPHV.js → bnf-BECwu6uW.js} +1 -1
- package/dist/ui/assets/{brainfuck-CnHx1vO0.js → brainfuck-QQgu4j4N.js} +1 -1
- package/dist/ui/assets/{coq-BShzwzh7.js → c-BRJEPYra.js} +1 -1
- package/dist/ui/assets/{c-like-XpQV9S6j.js → c-like-DYrFOtXy.js} +1 -1
- package/dist/ui/assets/{c4Diagram-LMCZKHZV-D5EmWl5d.js → c4Diagram-LMCZKHZV-B6Hgngz9.js} +1 -1
- package/dist/ui/assets/{cal-D-orUuBW.js → cal-CNMrJ6v5.js} +1 -1
- package/dist/ui/assets/{capnproto-TdI6NT8O.js → capnproto-DYCKl6oY.js} +1 -1
- package/dist/ui/assets/{ceylon-Dji8eqtG.js → ceylon-mb8tRPl0.js} +1 -1
- package/dist/ui/assets/channel-Bc4Td8eZ.js +1 -0
- package/dist/ui/assets/{chunk-2Q5K7J3B-CaIvwVWl.js → chunk-2Q5K7J3B-LxvQ-G67.js} +1 -1
- package/dist/ui/assets/{chunk-32BRIVSS-C7oMpoeu.js → chunk-32BRIVSS-DxzKK6Aw.js} +1 -1
- package/dist/ui/assets/{chunk-5VM5RSS4-BQ0aVGl-.js → chunk-5VM5RSS4-CZEoYJ2W.js} +1 -1
- package/dist/ui/assets/{chunk-EX3LRPZG-D-_EqojZ.js → chunk-EX3LRPZG-DS2PytrN.js} +1 -1
- package/dist/ui/assets/{chunk-JWPE2WC7-B0OLx2rk.js → chunk-JWPE2WC7-UX0Sr1Ie.js} +1 -1
- package/dist/ui/assets/{chunk-MOJQB5TN-Be8IXTUE.js → chunk-MOJQB5TN-YbJgT9t4.js} +1 -1
- package/dist/ui/assets/{chunk-RYQCIY6F-DceCW2mS.js → chunk-RYQCIY6F-DS2VH_U9.js} +1 -1
- package/dist/ui/assets/{chunk-V7JOEXUC-Cbhq5qgO.js → chunk-V7JOEXUC-CZr0pkI1.js} +1 -1
- package/dist/ui/assets/{chunk-VR4S4FIN-D6WJuaS1.js → chunk-VR4S4FIN-50opPAD3.js} +1 -1
- package/dist/ui/assets/{chunk-XXDRQBXY-CKrih4pC.js → chunk-XXDRQBXY-DAAX9l7U.js} +1 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-BicxhZFq.js +1 -0
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-BicxhZFq.js +1 -0
- package/dist/ui/assets/{clean-0frlVN_A.js → clean-C4X7dSkh.js} +1 -1
- package/dist/ui/assets/{clojure-D0q_yQDf.js → clojure-DSg9gUa7.js} +1 -1
- package/dist/ui/assets/{clojure-repl-DgYhEzOe.js → clojure-repl-CagRYx7h.js} +1 -1
- package/dist/ui/assets/{cmake-WF5tF5xU.js → cmake-CFdBn53c.js} +1 -1
- package/dist/ui/assets/{coffeescript-CyWYgeyv.js → coffeescript-CJZtMOPx.js} +1 -1
- package/dist/ui/assets/{c-DarYnPBd.js → coq-IDMIFfem.js} +1 -1
- package/dist/ui/assets/{cos-C5i3_TIB.js → cos-Bx2VJuzG.js} +1 -1
- package/dist/ui/assets/{cose-bilkent-JH36ORCC-BCwilS6I.js → cose-bilkent-JH36ORCC-zWRLsZpZ.js} +1 -1
- package/dist/ui/assets/{cpp-F1mRQFyw.js → cpp-CsG6DlC4.js} +1 -1
- package/dist/ui/assets/{crmsh-BAkHUu-B.js → crmsh-DTy9MnmJ.js} +1 -1
- package/dist/ui/assets/{crystal-CwUaomfj.js → crystal-BwgrLrZ1.js} +1 -1
- package/dist/ui/assets/{csharp-B1gHIdjK.js → csharp-B2VeTPAF.js} +1 -1
- package/dist/ui/assets/{csp-CblCTMvV.js → csp-CTpydNhH.js} +1 -1
- package/dist/ui/assets/{css-CXg7kJV3.js → css-B0mMUbpY.js} +1 -1
- package/dist/ui/assets/{cynefin-VYW2F7L2-BdgMlR5e.js → cynefin-VYW2F7L2-BmjQEj6q.js} +1 -1
- package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-Bozdux8p.js → cynefinDiagram-TSTJHNR4-Dr0Zrke0.js} +1 -1
- package/dist/ui/assets/{d-Cs5yNCaM.js → d-DjuDZnbI.js} +1 -1
- package/dist/ui/assets/{dagre-VKFMJZFB-tI_mjNMn.js → dagre-VKFMJZFB-xoTPT2Uu.js} +1 -1
- package/dist/ui/assets/{dart-BqgylVkh.js → dart-xR3GU9TJ.js} +1 -1
- package/dist/ui/assets/{delphi-CbnfHpIi.js → delphi-bJas5QnG.js} +1 -1
- package/dist/ui/assets/{diagram-FQU43EPY-DmyL3OJT.js → diagram-FQU43EPY-rL_IU7gU.js} +1 -1
- package/dist/ui/assets/{diagram-G47NLZAW-BEi9GZlZ.js → diagram-G47NLZAW-EcDiCVGj.js} +1 -1
- package/dist/ui/assets/{diagram-NH7WQ7WH-Bct44Oh1.js → diagram-NH7WQ7WH-CGGXOjev.js} +1 -1
- package/dist/ui/assets/{diagram-OA4YK3LP-VWAgZxPK.js → diagram-OA4YK3LP-DnE7hDjD.js} +1 -1
- package/dist/ui/assets/{diagram-WEI45ONY-CxcHsE6q.js → diagram-WEI45ONY-CTJH5eD8.js} +1 -1
- package/dist/ui/assets/{diff-CMJ2hGQW.js → diff-doJFF3fv.js} +1 -1
- package/dist/ui/assets/{django-Cq_XIhVZ.js → django-D3b-owa_.js} +1 -1
- package/dist/ui/assets/{dns-CJs3z6-E.js → dns-C42KYV-Z.js} +1 -1
- package/dist/ui/assets/{dockerfile-ehs0ogry.js → dockerfile-9KUINc2j.js} +1 -1
- package/dist/ui/assets/{dos-DXOYESf1.js → dos-CxnlJ6qp.js} +1 -1
- package/dist/ui/assets/{dsconfig-Cs2hs3Bl.js → dsconfig-6CMMCwmY.js} +1 -1
- package/dist/ui/assets/{dts-Dk8yoweb.js → dts-D78rdUIB.js} +1 -1
- package/dist/ui/assets/{dust-BMK9e-Ss.js → dust-Dv1uTfJU.js} +1 -1
- package/dist/ui/assets/{ebnf-DlyBI5m6.js → ebnf-BGbG1cFK.js} +1 -1
- package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-DBp9JHEq.js → ebnfDiagram-CCIWWBDH-z2VgRSUV.js} +1 -1
- package/dist/ui/assets/{elixir-BThlsblT.js → elixir-ZgAQVY1J.js} +1 -1
- package/dist/ui/assets/{elm-DrmZwmcc.js → elm-CudiFuNu.js} +1 -1
- package/dist/ui/assets/{erDiagram-Q63AITRT-BhK4NKvx.js → erDiagram-Q63AITRT-X1TODuRv.js} +1 -1
- package/dist/ui/assets/{erb-BQM7j3K9.js → erb-Bz_NZh6W.js} +1 -1
- package/dist/ui/assets/{erlang-CuUaWEXv.js → erlang-DNuj1nb2.js} +1 -1
- package/dist/ui/assets/{erlang-repl-DB0uphao.js → erlang-repl-SP1Gan9W.js} +1 -1
- package/dist/ui/assets/{excel-DmsuWUss.js → excel-0K77uECF.js} +1 -1
- package/dist/ui/assets/{fix-D-Uzxpz_.js → fix-CalJq7JD.js} +1 -1
- package/dist/ui/assets/{flix-B_7EHWiA.js → flix-BlIs11_w.js} +1 -1
- package/dist/ui/assets/{flowDiagram-23GEKE2U-DtMG1G-h.js → flowDiagram-23GEKE2U-DA2dnmc0.js} +1 -1
- package/dist/ui/assets/{fortran-Djp5tH9W.js → fortran-ZCobXY2R.js} +1 -1
- package/dist/ui/assets/{fsharp-Pj_2ZEa4.js → fsharp-Be8rwUtc.js} +1 -1
- package/dist/ui/assets/{gams-B2i3v2ec.js → gams-DUat8frQ.js} +1 -1
- package/dist/ui/assets/{ganttDiagram-NO4QXBWP-C7M-JA0W.js → ganttDiagram-NO4QXBWP-DdFwaIGZ.js} +1 -1
- package/dist/ui/assets/{gauss-DaV8sHLU.js → gauss-BB4U88dy.js} +1 -1
- package/dist/ui/assets/{gcode-0Jvrh6HY.js → gcode-DzeUZuZg.js} +1 -1
- package/dist/ui/assets/{gherkin-DoOl28D6.js → gherkin-B_8vW_BO.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-D3HB5mow.js → gitGraphDiagram-IHSO6WYX-B-Dn8x6I.js} +1 -1
- package/dist/ui/assets/{glsl-DEbk7rH5.js → glsl-DGHGjPC1.js} +1 -1
- package/dist/ui/assets/{gml-CBcqXBNV.js → gml-BYEku8Yh.js} +1 -1
- package/dist/ui/assets/{go-DqesmqF8.js → go-D8aSgQMc.js} +1 -1
- package/dist/ui/assets/{golo-9U1oO0b5.js → golo-CDjCU_jh.js} +1 -1
- package/dist/ui/assets/{gradle-DZliBXTY.js → gradle-BeUw7tl_.js} +1 -1
- package/dist/ui/assets/{groovy-Dys3GQwv.js → groovy-5iCQOtR3.js} +1 -1
- package/dist/ui/assets/{haml-CrtAODl1.js → haml-BEdL8FJi.js} +1 -1
- package/dist/ui/assets/{handlebars-CueXuqSj.js → handlebars-BuYQNzoK.js} +1 -1
- package/dist/ui/assets/{haskell-CRungOQt.js → haskell-I4FCBcW0.js} +1 -1
- package/dist/ui/assets/{haxe-aMz7L4gD.js → haxe-yigyKfFr.js} +1 -1
- package/dist/ui/assets/{hsp-Cw75yqGb.js → hsp-ZUk4j7d1.js} +1 -1
- package/dist/ui/assets/{htmlbars-e_mpUZNH.js → htmlbars-QYP3lT3u.js} +1 -1
- package/dist/ui/assets/{http-Di7E_m1o.js → http-BJpD1O71.js} +1 -1
- package/dist/ui/assets/{hy-CwlvsNj6.js → hy-CIJ1bP6S.js} +1 -1
- package/dist/ui/assets/{index-BdSumlU0.js → index-BDXWttnT.js} +3 -3
- package/dist/ui/assets/index-C0fxlU9d.css +10 -0
- package/dist/ui/assets/{index-BVM6YOjH.js → index-COAgrx1J.js} +256 -256
- package/dist/ui/assets/{infoDiagram-FWYZ7A6U-_r-6eAzx.js → infoDiagram-FWYZ7A6U-fTg9eLNt.js} +1 -1
- package/dist/ui/assets/{inform7-dwg1imm1.js → inform7-DAsu-lC2.js} +1 -1
- package/dist/ui/assets/{ini-DEXL1rCA.js → ini-Bhz-zHCg.js} +1 -1
- package/dist/ui/assets/{irpf90-Ccs_8Sp-.js → irpf90-BunhbwBl.js} +1 -1
- package/dist/ui/assets/{isbl-B9d1nYmL.js → isbl-q9L6hOhP.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-lNCezpU4.js → ishikawaDiagram-FXEZZL3T-B8G0sdgd.js} +1 -1
- package/dist/ui/assets/{java-5fv2smM6.js → java-Iks5Pkau.js} +1 -1
- package/dist/ui/assets/{javascript-TAWm0NK8.js → javascript-C4vltXPw.js} +1 -1
- package/dist/ui/assets/{jboss-cli-dM1kcsbR.js → jboss-cli-BQBvd2X2.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-5HDEW3XC-CBYHux8i.js → journeyDiagram-5HDEW3XC-Crbzgrum.js} +1 -1
- package/dist/ui/assets/{json-CtCzm6jF.js → json-DXK0_jUK.js} +1 -1
- package/dist/ui/assets/{julia-Co7H3kzk.js → julia-CCYoBiYK.js} +1 -1
- package/dist/ui/assets/{julia-repl-BT1ar5VS.js → julia-repl-y8v2Oorl.js} +1 -1
- package/dist/ui/assets/{kanban-definition-HUTT4EX6-B8x8eQyo.js → kanban-definition-HUTT4EX6-C8sCOsBX.js} +1 -1
- package/dist/ui/assets/{kotlin-W6mVKIj9.js → kotlin-Bnjk7_fw.js} +1 -1
- package/dist/ui/assets/{lasso-DJG4luGz.js → lasso-B-al6x63.js} +1 -1
- package/dist/ui/assets/{latex-DbBOxO7u.js → latex-BUmqlb9r.js} +1 -1
- package/dist/ui/assets/{ldif-CVS189JA.js → ldif-D42RWj6Q.js} +1 -1
- package/dist/ui/assets/{leaf-eYNiXTKP.js → leaf-CrH4BZ0m.js} +1 -1
- package/dist/ui/assets/{less-DxhvWM95.js → less-upmRlQQW.js} +1 -1
- package/dist/ui/assets/{lisp-SC7AwnXC.js → lisp-DHYS22SA.js} +1 -1
- package/dist/ui/assets/{livecodeserver-CR2eHihF.js → livecodeserver-CeQNmFP3.js} +1 -1
- package/dist/ui/assets/{livescript-DBZ-GaVK.js → livescript-PJWpY1JI.js} +1 -1
- package/dist/ui/assets/{llvm-BzURO4tt.js → llvm-BKtKWwCt.js} +1 -1
- package/dist/ui/assets/{lsl-DGoJxEUu.js → lsl-RWRLRjk7.js} +1 -1
- package/dist/ui/assets/{lua-qgG9gdiw.js → lua-BFUDiPGm.js} +1 -1
- package/dist/ui/assets/{makefile-D0kZ6SOe.js → makefile-CUDyOz5D.js} +1 -1
- package/dist/ui/assets/{markdown-DRQWgMxk.js → markdown-zZCLypc6.js} +1 -1
- package/dist/ui/assets/{mathematica-DIBvZyEZ.js → mathematica-BHbxKxnq.js} +1 -1
- package/dist/ui/assets/{matlab-BNg0BR0b.js → matlab-DlGtg--p.js} +1 -1
- package/dist/ui/assets/{maxima-Bpga3G1G.js → maxima-BBBeS3Ra.js} +1 -1
- package/dist/ui/assets/{mel-CMOJa9Mg.js → mel-nh8j7W_6.js} +1 -1
- package/dist/ui/assets/{mercury-uvrRzupw.js → mercury-DyyD-pqr.js} +1 -1
- package/dist/ui/assets/{mindmap-definition-LN4V7U3C-DK8j_8Ap.js → mindmap-definition-LN4V7U3C-CJlhDHqM.js} +1 -1
- package/dist/ui/assets/{mipsasm-p1gWpDuw.js → mipsasm-hiEhRRiq.js} +1 -1
- package/dist/ui/assets/{mizar-DV1ENOOU.js → mizar-BZa3iAAL.js} +1 -1
- package/dist/ui/assets/{mojolicious-tg5XQSro.js → mojolicious-BCIm2V_y.js} +1 -1
- package/dist/ui/assets/{monkey-D8mYa31Q.js → monkey-zmK-7N8b.js} +1 -1
- package/dist/ui/assets/{moonscript-1d_rtlyv.js → moonscript-BsS_Mn3D.js} +1 -1
- package/dist/ui/assets/{n1ql-C5srRxme.js → n1ql-D7xVgDP0.js} +1 -1
- package/dist/ui/assets/{nginx-xS1muaWm.js → nginx-ct2q4dtd.js} +1 -1
- package/dist/ui/assets/{nim-CGGiMQfp.js → nim-RO0UOmW3.js} +1 -1
- package/dist/ui/assets/{nix-C77HsR7m.js → nix-BcRJxPKH.js} +1 -1
- package/dist/ui/assets/{node-repl-CSeYusSM.js → node-repl-DgIefwxW.js} +1 -1
- package/dist/ui/assets/{nsis-BffC7mSW.js → nsis-DqHs9QhB.js} +1 -1
- package/dist/ui/assets/{objectivec-WpjnmlJB.js → objectivec-BBcWqc7Y.js} +1 -1
- package/dist/ui/assets/{ocaml-CHUkJkjB.js → ocaml-BExfw7D6.js} +1 -1
- package/dist/ui/assets/{openscad-BvImqFT0.js → openscad-CHPRELQb.js} +1 -1
- package/dist/ui/assets/{oxygene-BMBykbf5.js → oxygene-DpS9uMJW.js} +1 -1
- package/dist/ui/assets/{parser3-lRbuZW0M.js → parser3-CjJ_QdBp.js} +1 -1
- package/dist/ui/assets/{pegDiagram-2B236MQR-C4DWmrja.js → pegDiagram-2B236MQR-GM70woGy.js} +1 -1
- package/dist/ui/assets/{perl-B0DjfKoO.js → perl-BSNM2Kt8.js} +1 -1
- package/dist/ui/assets/{pf-Aor6NyYJ.js → pf-Z-hKf_88.js} +1 -1
- package/dist/ui/assets/{pgsql-CVKcjjNR.js → pgsql-DDgznxBg.js} +1 -1
- package/dist/ui/assets/{php-CZ7geHZt.js → php-BzAhxF-l.js} +1 -1
- package/dist/ui/assets/{php-template-DiFuW2dF.js → php-template-DkgcKHRc.js} +1 -1
- package/dist/ui/assets/{pieDiagram-ENE6RG2P-BO7AmF5j.js → pieDiagram-ENE6RG2P-Bst7mPyz.js} +1 -1
- package/dist/ui/assets/{plaintext-DcvmOuNc.js → plaintext-BYEppD0R.js} +1 -1
- package/dist/ui/assets/{pony-DGPeAcOc.js → pony-BT_kQd1K.js} +1 -1
- package/dist/ui/assets/{powershell-DsrPyJdK.js → powershell-BfRsuSsf.js} +1 -1
- package/dist/ui/assets/{processing-Co2VRXN1.js → processing-DpzWe5Iu.js} +1 -1
- package/dist/ui/assets/{profile-D4PjpLUf.js → profile-BCOhS5cM.js} +1 -1
- package/dist/ui/assets/{prolog-DEbkeg9r.js → prolog-OxaCCaW8.js} +1 -1
- package/dist/ui/assets/{properties-Cxqcuj1s.js → properties-DMFlA2Ca.js} +1 -1
- package/dist/ui/assets/{protobuf-C-zdlrww.js → protobuf-CRDFkXvZ.js} +1 -1
- package/dist/ui/assets/{puppet-BPX3SrOx.js → puppet-DnrVyLzx.js} +1 -1
- package/dist/ui/assets/{purebasic-BdQnNJS3.js → purebasic-Dht4Hniv.js} +1 -1
- package/dist/ui/assets/{python-D067_Gj8.js → python-B0aMirWu.js} +1 -1
- package/dist/ui/assets/{python-repl-DCqNVlc0.js → python-repl-BlYDBGa7.js} +1 -1
- package/dist/ui/assets/{q-kABXYW-8.js → q-DzrtW9kT.js} +1 -1
- package/dist/ui/assets/{qml-Iao-Whg7.js → qml-DnfQsR3i.js} +1 -1
- package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-DetQn-0l.js → quadrantDiagram-ABIIQ3AL-DNRYurBT.js} +1 -1
- package/dist/ui/assets/{r-BnwpapnO.js → r-DGI_ZuTD.js} +1 -1
- package/dist/ui/assets/{railroadDiagram-RFXS5EU6-DFaFKHAH.js → railroadDiagram-RFXS5EU6-CmbC3Vz4.js} +1 -1
- package/dist/ui/assets/{reasonml-Cn_Y03uT.js → reasonml-3SohMgh2.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-TGXJPOKE-Dg1LrT-T.js → requirementDiagram-TGXJPOKE-8CxrXHco.js} +1 -1
- package/dist/ui/assets/{rib-ByAqQn0v.js → rib-DfRSd4Qa.js} +1 -1
- package/dist/ui/assets/{roboconf-BJPu6NC5.js → roboconf-CQczGdGW.js} +1 -1
- package/dist/ui/assets/{routeros-CL3Jm0Zq.js → routeros-DCka-T2i.js} +1 -1
- package/dist/ui/assets/{rsl-DaXy7KaD.js → rsl-Dr8MOwMo.js} +1 -1
- package/dist/ui/assets/{ruby-DI6awte_.js → ruby-C2zFSkh_.js} +1 -1
- package/dist/ui/assets/{ruleslanguage-DoTVEZE9.js → ruleslanguage-C97YsgQq.js} +1 -1
- package/dist/ui/assets/{rust-ULEd75wO.js → rust-H3h8kd9A.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-DQtFl110.js → sankeyDiagram-HTMAVEWB-DBXLWjEq.js} +1 -1
- package/dist/ui/assets/{sas-f7ATFuJk.js → sas-04z0Xu8P.js} +1 -1
- package/dist/ui/assets/{scala-Dha1zro2.js → scala-DyB9Aoiv.js} +1 -1
- package/dist/ui/assets/{scheme-BcaFHKeF.js → scheme-DBj6nxUi.js} +1 -1
- package/dist/ui/assets/{scilab-CIiiyD4z.js → scilab-Btj7AD9s.js} +1 -1
- package/dist/ui/assets/{scss-CkBomL0n.js → scss-BXZJyXt7.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-DIbNQtCn.js → sequenceDiagram-DBY2YBRQ-DXIkBFKC.js} +1 -1
- package/dist/ui/assets/{shell-Cxu8Py1z.js → shell-BsreQR1Z.js} +1 -1
- package/dist/ui/assets/{sizeCapture-X5ZJPWSS-Cj7PglQv.js → sizeCapture-X5ZJPWSS-ocS9jxAQ.js} +1 -1
- package/dist/ui/assets/{smali-C4EYyWYz.js → smali-D9wQw9zm.js} +1 -1
- package/dist/ui/assets/{smalltalk-BlPTprP4.js → smalltalk-Dku6G_H3.js} +1 -1
- package/dist/ui/assets/{sml-DEPzhlr4.js → sml-BknyU6ya.js} +1 -1
- package/dist/ui/assets/{sqf-CRu3asu9.js → sqf-DRYMaOg8.js} +1 -1
- package/dist/ui/assets/{sql-DK-YfQqg.js → sql-Cw3Ax4KA.js} +1 -1
- package/dist/ui/assets/{sql_more-BuMEOcjj.js → sql_more-vWdslLE0.js} +1 -1
- package/dist/ui/assets/{stan-DMr13kyD.js → stan-8XH5bDS6.js} +1 -1
- package/dist/ui/assets/{stata-Bt6E2zQi.js → stata-4e77wgfe.js} +1 -1
- package/dist/ui/assets/{stateDiagram-2N3HPSRC-Bk-gF72D.js → stateDiagram-2N3HPSRC-RMmL9jMG.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-QvaEO5U6.js +1 -0
- package/dist/ui/assets/{step21-Bi954ur4.js → step21-ByIeDMY3.js} +1 -1
- package/dist/ui/assets/{stylus-CQwwMaLm.js → stylus-ZAhJyWsw.js} +1 -1
- package/dist/ui/assets/{subunit-BkixDEMH.js → subunit-pPW2UGkj.js} +1 -1
- package/dist/ui/assets/{swift-DS1DWNAE.js → swift-CX3BB5az.js} +1 -1
- package/dist/ui/assets/{swimlanes-5IMT3BWC-C-AZKO5z.js → swimlanes-5IMT3BWC-C2zAuJ56.js} +2 -2
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-DPgCOY0D.js +8 -0
- package/dist/ui/assets/{taggerscript-DZHi1hoc.js → taggerscript-BHcjbWIC.js} +1 -1
- package/dist/ui/assets/{tap-CXxSD8bM.js → tap-BOl1lBlS.js} +1 -1
- package/dist/ui/assets/{tcl-CdoAAMbn.js → tcl-DZjeOBDh.js} +1 -1
- package/dist/ui/assets/{thrift-DM086HVt.js → thrift-BxboWg4x.js} +1 -1
- package/dist/ui/assets/{timeline-definition-FHXFAJF6-DcrcjFwq.js → timeline-definition-FHXFAJF6-BOxsxyq_.js} +1 -1
- package/dist/ui/assets/{tp-Y-w3S3ES.js → tp-BNM6ql3J.js} +1 -1
- package/dist/ui/assets/{twig-C5c_nAus.js → twig-Dj9ZiXD4.js} +1 -1
- package/dist/ui/assets/{typescript-fc7SMhJu.js → typescript-7MEJlu_6.js} +1 -1
- package/dist/ui/assets/{vala-BV-GlwLI.js → vala-DNqOAgHJ.js} +1 -1
- package/dist/ui/assets/{vbnet-BIqQmnKr.js → vbnet-T0mNKVc_.js} +1 -1
- package/dist/ui/assets/{vbscript-h186Lnrz.js → vbscript-CeuwVMAI.js} +1 -1
- package/dist/ui/assets/{vbscript-html-DcuP7lTb.js → vbscript-html-BbJSt2w6.js} +1 -1
- package/dist/ui/assets/{vennDiagram-L72KCM5P-Dnh11y2e.js → vennDiagram-L72KCM5P-BX9mWeiT.js} +1 -1
- package/dist/ui/assets/{verilog-Cbgb_XnR.js → verilog-DYuhYfkX.js} +1 -1
- package/dist/ui/assets/{vhdl-COP7w5IC.js → vhdl-Cf9aT-t7.js} +1 -1
- package/dist/ui/assets/{vim-COGwKzgS.js → vim-DciP44K1.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-EHGQE667-BeiD8fPz.js → wardleyDiagram-EHGQE667-CDj2rOzu.js} +1 -1
- package/dist/ui/assets/{x86asm-BdBqPPf4.js → x86asm-E-AN_LXO.js} +1 -1
- package/dist/ui/assets/{xl-BmCQT7Vj.js → xl-CxYLJelN.js} +1 -1
- package/dist/ui/assets/{xml-DM0NxGiJ.js → xml-yz1SRLuU.js} +1 -1
- package/dist/ui/assets/{xquery-BUaYHDJM.js → xquery-BLzBF3tV.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-FW5EYKEG-CnwvTrkm.js → xychartDiagram-FW5EYKEG-Czapk9-Z.js} +1 -1
- package/dist/ui/assets/{yaml-DMs8lGDt.js → yaml-Cv4Y7iN_.js} +1 -1
- package/dist/ui/assets/{zephir-BvjoPdmg.js → zephir-KRcdQfEX.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/utils/__tests__/knowledge-store.test.js +86 -5
- package/dist/utils/__tests__/pi-browser-tools.test.d.ts +1 -0
- package/dist/utils/__tests__/pi-browser-tools.test.js +30 -0
- package/dist/utils/__tests__/pi-crawl-tools.test.d.ts +1 -0
- package/dist/utils/__tests__/pi-crawl-tools.test.js +315 -0
- package/dist/utils/__tests__/pi-dedup-reconcile.test.d.ts +1 -0
- package/dist/utils/__tests__/pi-dedup-reconcile.test.js +89 -0
- package/dist/utils/__tests__/pi-dedup.test.d.ts +1 -0
- package/dist/utils/__tests__/pi-dedup.test.js +106 -0
- package/dist/utils/__tests__/pi-learn-orchestrator.test.d.ts +1 -0
- package/dist/utils/__tests__/pi-learn-orchestrator.test.js +885 -0
- package/dist/utils/__tests__/pi-runtime-json.test.d.ts +1 -0
- package/dist/utils/__tests__/pi-runtime-json.test.js +11 -0
- package/dist/utils/__tests__/web-crawler.test.d.ts +1 -0
- package/dist/utils/__tests__/web-crawler.test.js +69 -0
- package/dist/utils/db.d.ts +1 -0
- package/dist/utils/db.js +18 -0
- package/dist/utils/knowledge-store.d.ts +9 -0
- package/dist/utils/knowledge-store.js +85 -11
- package/dist/utils/pi-browser-tools.d.ts +2 -0
- package/dist/utils/pi-browser-tools.js +9 -2
- package/dist/utils/pi-crawl-tools.d.ts +62 -0
- package/dist/utils/pi-crawl-tools.js +298 -0
- package/dist/utils/pi-dedup.d.ts +62 -0
- package/dist/utils/pi-dedup.js +218 -0
- package/dist/utils/pi-learn-orchestrator.d.ts +44 -0
- package/dist/utils/pi-learn-orchestrator.js +431 -0
- package/dist/utils/pi-runtime.d.ts +23 -1
- package/dist/utils/pi-runtime.js +255 -68
- package/dist/utils/request-writer.d.ts +1 -0
- package/dist/utils/request-writer.js +5 -4
- package/dist/utils/web-crawler.d.ts +13 -0
- package/dist/utils/web-crawler.js +64 -0
- package/package.json +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.CHyuB7c8.js +0 -1
- package/dist/ui/assets/channel-BdcV3Ykv.js +0 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-CAZR5rAv.js +0 -1
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-CAZR5rAv.js +0 -1
- package/dist/ui/assets/index-WPLwx8h5.css +0 -10
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BFJCYsLY.js +0 -1
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-BZd1Gt4_.js +0 -8
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// crawl 阶段工具:LLM Agent 在 outline 阶段内自己驱动渐进抓取。
|
|
2
|
+
// - CrawlGuard:同站/深度/页数硬校验的有状态抓取器,抓取过的原文存内存缓存,
|
|
3
|
+
// saveSource 落盘到 <slug>/sources/source-NNN.md
|
|
4
|
+
// - createCrawlTools:挂给 pi session 的 4 个工具(crawl_open/crawl_visit/
|
|
5
|
+
// save_source/crawl_finish),错误以文本返回,LLM 可读可恢复
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { Type } from 'typebox';
|
|
9
|
+
import { runEgoBrowser } from './pi-browser-tools.js';
|
|
10
|
+
import { CRAWL_MAX_PAGES, CRAWL_MAX_DEPTH, isSameSite, normalizeCandidate } from './web-crawler.js';
|
|
11
|
+
/** 单页浏览器脚本:task space 取 tab → goto → networkidle 缓冲 → 稳定性轮询 → 提取标题/正文/链接 */
|
|
12
|
+
function buildCrawlScript(url) {
|
|
13
|
+
return `const pages = await task.pages()
|
|
14
|
+
const page = pages.find(p => p.label === 'p1') ?? pages[0] ?? await task.newPage()
|
|
15
|
+
await page.goto(${JSON.stringify(url)}, { waitUntil: 'load', timeout: 30000 })
|
|
16
|
+
try { await page.waitForLoadState('networkidle', { timeout: 5000 }) } catch {}
|
|
17
|
+
// 稳定性:500ms 采一次 innerText.length,连续 2 次相同且 >0,最多 10 次
|
|
18
|
+
await page.evaluate(() => new Promise((resolve) => {
|
|
19
|
+
let last = -1, same = 0, n = 0
|
|
20
|
+
const tick = () => {
|
|
21
|
+
const len = document.body ? document.body.innerText.length : 0
|
|
22
|
+
if (len > 0 && len === last) {
|
|
23
|
+
same += 1
|
|
24
|
+
if (same >= 2) return resolve()
|
|
25
|
+
} else {
|
|
26
|
+
same = 0
|
|
27
|
+
}
|
|
28
|
+
last = len
|
|
29
|
+
if (++n >= 10) return resolve()
|
|
30
|
+
setTimeout(tick, 500)
|
|
31
|
+
}
|
|
32
|
+
tick()
|
|
33
|
+
}))
|
|
34
|
+
const data = await page.evaluate(() => ({
|
|
35
|
+
title: document.title,
|
|
36
|
+
text: document.body ? document.body.innerText : '',
|
|
37
|
+
links: Array.from(document.querySelectorAll('a[href]')).map(a => a.href),
|
|
38
|
+
}))
|
|
39
|
+
cliLog(JSON.stringify(data))
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
export class CrawlGuard {
|
|
43
|
+
constructor(opts) {
|
|
44
|
+
Object.defineProperty(this, "opts", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: opts
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, "maxPages", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true,
|
|
54
|
+
value: void 0
|
|
55
|
+
});
|
|
56
|
+
Object.defineProperty(this, "maxDepth", {
|
|
57
|
+
enumerable: true,
|
|
58
|
+
configurable: true,
|
|
59
|
+
writable: true,
|
|
60
|
+
value: void 0
|
|
61
|
+
});
|
|
62
|
+
Object.defineProperty(this, "navigate", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
writable: true,
|
|
66
|
+
value: void 0
|
|
67
|
+
});
|
|
68
|
+
Object.defineProperty(this, "entry", {
|
|
69
|
+
enumerable: true,
|
|
70
|
+
configurable: true,
|
|
71
|
+
writable: true,
|
|
72
|
+
value: void 0
|
|
73
|
+
});
|
|
74
|
+
Object.defineProperty(this, "seen", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
value: new Set()
|
|
79
|
+
});
|
|
80
|
+
Object.defineProperty(this, "depthByUrl", {
|
|
81
|
+
enumerable: true,
|
|
82
|
+
configurable: true,
|
|
83
|
+
writable: true,
|
|
84
|
+
value: new Map()
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(this, "rawCache", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
configurable: true,
|
|
89
|
+
writable: true,
|
|
90
|
+
value: new Map()
|
|
91
|
+
});
|
|
92
|
+
// 已落盘过的 URL(防重复原料)
|
|
93
|
+
Object.defineProperty(this, "savedUrls", {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
configurable: true,
|
|
96
|
+
writable: true,
|
|
97
|
+
value: new Set()
|
|
98
|
+
});
|
|
99
|
+
Object.defineProperty(this, "_savedCount", {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
writable: true,
|
|
103
|
+
value: 0
|
|
104
|
+
});
|
|
105
|
+
Object.defineProperty(this, "currentDepth", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
configurable: true,
|
|
108
|
+
writable: true,
|
|
109
|
+
value: 0
|
|
110
|
+
});
|
|
111
|
+
this.maxPages = opts.maxPages ?? CRAWL_MAX_PAGES;
|
|
112
|
+
this.maxDepth = opts.maxDepth ?? CRAWL_MAX_DEPTH;
|
|
113
|
+
this.navigate = opts.navigate ?? ((url, signal) => this.defaultNavigate(url, signal));
|
|
114
|
+
}
|
|
115
|
+
/** 默认单页抓取:跑 ego 脚本,JSON parse 失败硬抛错;signal 透传中断在途进程 */
|
|
116
|
+
async defaultNavigate(url, signal) {
|
|
117
|
+
const raw = await runEgoBrowser(buildCrawlScript(url), { timeoutMs: 60000, signal });
|
|
118
|
+
let data;
|
|
119
|
+
try {
|
|
120
|
+
data = JSON.parse(raw);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
throw new Error(`crawl: failed to parse result from ${url}`);
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
title: typeof data.title === 'string' ? data.title : '',
|
|
127
|
+
text: typeof data.text === 'string' ? data.text : '',
|
|
128
|
+
links: Array.isArray(data.links) ? data.links.filter((l) => typeof l === 'string') : [],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/** 打开入口页:URL 校验 + 初始状态;signal 用于中断在途抓取 */
|
|
132
|
+
async open(signal) {
|
|
133
|
+
const entry = new URL(this.opts.entryUrl);
|
|
134
|
+
entry.hash = '';
|
|
135
|
+
this.entry = entry;
|
|
136
|
+
this.seen.add(entry.href);
|
|
137
|
+
this.depthByUrl.set(entry.href, 0);
|
|
138
|
+
this.currentDepth = 0;
|
|
139
|
+
const page = await this.navigate(entry.href, signal);
|
|
140
|
+
this.rawCache.set(entry.href, page);
|
|
141
|
+
return { url: entry.href, ...page };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 解析候选页的 BFS 最短深度:扫描每个已抓来源页的 links,
|
|
145
|
+
* 凡归一后命中候选页的来源,候选深度 = 来源深度 + 1,取所有命中的最小值。
|
|
146
|
+
* 一个来源都没查到(幻觉 URL)时硬抛错,绝不放行。
|
|
147
|
+
*/
|
|
148
|
+
resolveDepth(candidate) {
|
|
149
|
+
let resolved = null;
|
|
150
|
+
for (const [sourceHref, page] of this.rawCache) {
|
|
151
|
+
for (const link of page.links) {
|
|
152
|
+
const linked = normalizeCandidate(link, this.entry);
|
|
153
|
+
if (linked && linked.href === candidate.href) {
|
|
154
|
+
const next = this.depthByUrl.get(sourceHref) + 1;
|
|
155
|
+
if (resolved === null || next < resolved)
|
|
156
|
+
resolved = next;
|
|
157
|
+
break; // 本来源页已命中,不必再看它其余 links
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (resolved === null) {
|
|
162
|
+
throw new Error(`crawl visit reject: ${candidate.href} not linked from any crawled page`);
|
|
163
|
+
}
|
|
164
|
+
return resolved;
|
|
165
|
+
}
|
|
166
|
+
/** 访问子页:同站/seen/链接来源/深度/页数硬校验(原因 cross-site/seen/not linked/max-depth/max-pages) */
|
|
167
|
+
async visit(rawUrl, signal) {
|
|
168
|
+
const candidate = normalizeCandidate(rawUrl, this.entry);
|
|
169
|
+
if (!candidate)
|
|
170
|
+
throw new Error(`crawl visit reject: invalid or binary url: ${rawUrl}`);
|
|
171
|
+
if (!isSameSite(candidate.hostname, this.entry.hostname)) {
|
|
172
|
+
throw new Error(`crawl visit reject cross-site: ${candidate.href}`);
|
|
173
|
+
}
|
|
174
|
+
if (this.seen.has(candidate.href)) {
|
|
175
|
+
throw new Error(`crawl visit reject seen: ${candidate.href}`);
|
|
176
|
+
}
|
|
177
|
+
// BFS 最短深度(候选必须由某个已抓页链接;未链接直接 throw)
|
|
178
|
+
const nextDepth = this.resolveDepth(candidate);
|
|
179
|
+
if (nextDepth > this.maxDepth) {
|
|
180
|
+
throw new Error(`crawl visit reject max-depth: ${candidate.href}`);
|
|
181
|
+
}
|
|
182
|
+
if (this.seen.size + 1 > this.maxPages) {
|
|
183
|
+
throw new Error(`crawl visit reject max-pages: ${candidate.href}`);
|
|
184
|
+
}
|
|
185
|
+
const page = await this.navigate(candidate.href, signal);
|
|
186
|
+
this.seen.add(candidate.href);
|
|
187
|
+
this.depthByUrl.set(candidate.href, nextDepth);
|
|
188
|
+
this.currentDepth = nextDepth;
|
|
189
|
+
this.rawCache.set(candidate.href, page);
|
|
190
|
+
return { url: candidate.href, ...page };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* 保存已抓取页原文到 <slug>/sources/source-NNN.md;必须先 open/visit 过该 URL。
|
|
194
|
+
* 同页重复保存不写新文件,返回已有编号 + reused=true;空正文页判失败。
|
|
195
|
+
*/
|
|
196
|
+
saveSource(rawUrl) {
|
|
197
|
+
let key = rawUrl;
|
|
198
|
+
const candidate = normalizeCandidate(rawUrl, this.entry);
|
|
199
|
+
if (candidate)
|
|
200
|
+
key = candidate.href;
|
|
201
|
+
const page = this.rawCache.get(key);
|
|
202
|
+
if (!page)
|
|
203
|
+
throw new Error(`save_source reject: url not crawled: ${rawUrl}`);
|
|
204
|
+
// 已存过:不重复落盘,返回已有编号
|
|
205
|
+
if (this.savedUrls.has(key)) {
|
|
206
|
+
return { savedCount: this._savedCount, reused: true };
|
|
207
|
+
}
|
|
208
|
+
// 对齐旧 crawlSite:trim 后为空的页面判失败,不产生空原料
|
|
209
|
+
if (page.text.trim() === '')
|
|
210
|
+
throw new Error(`save_source reject empty page: ${key}`);
|
|
211
|
+
const sourcesDir = path.join(this.opts.docsDir, this.opts.slug, 'sources');
|
|
212
|
+
fs.mkdirSync(sourcesDir, { recursive: true });
|
|
213
|
+
const name = `source-${String(this._savedCount + 1).padStart(3, '0')}.md`;
|
|
214
|
+
fs.writeFileSync(path.join(sourcesDir, name), `Source: ${key}\n\n${page.text}`, 'utf8');
|
|
215
|
+
this.savedUrls.add(key);
|
|
216
|
+
this._savedCount += 1;
|
|
217
|
+
return { savedCount: this._savedCount, reused: false };
|
|
218
|
+
}
|
|
219
|
+
get savedCount() {
|
|
220
|
+
return this._savedCount;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* 抓取结束清理:no-op。
|
|
224
|
+
* 不能调 task.finish()——它会关闭全部 page 并把 space 所有权交还 user,
|
|
225
|
+
* 导致下一次 learn 的 taskSpace() resume 失败;持久 space 与 tab 留给后续复用。
|
|
226
|
+
*/
|
|
227
|
+
async close() { }
|
|
228
|
+
}
|
|
229
|
+
// ============================================================
|
|
230
|
+
// ToolDefinition 构造(写法对齐 pi-runtime,ok/err 返回)
|
|
231
|
+
// ============================================================
|
|
232
|
+
const ok = (text) => ({
|
|
233
|
+
content: [{ type: 'text', text }],
|
|
234
|
+
details: undefined,
|
|
235
|
+
});
|
|
236
|
+
const errAsText = (e) => ok(`error: ${e instanceof Error ? e.message : String(e)}`);
|
|
237
|
+
export function createCrawlTools(guard) {
|
|
238
|
+
return [
|
|
239
|
+
{
|
|
240
|
+
name: 'crawl_open',
|
|
241
|
+
label: 'crawl_open',
|
|
242
|
+
description: '打开本次任务的入口 URL,返回标题、正文与同站链接。抓取第一步调用。',
|
|
243
|
+
parameters: Type.Object({}),
|
|
244
|
+
async execute(_id, _params, signal) {
|
|
245
|
+
try {
|
|
246
|
+
return ok(JSON.stringify(await guard.open(signal)));
|
|
247
|
+
}
|
|
248
|
+
catch (e) {
|
|
249
|
+
return errAsText(e);
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'crawl_visit',
|
|
255
|
+
label: 'crawl_visit',
|
|
256
|
+
description: '访问入口同站的子页面(必须是 crawl_open/上一次 crawl_visit 返回链接中的 http(s) 页面)。',
|
|
257
|
+
parameters: Type.Object({ url: Type.String({ description: '要访问的同站完整 URL' }) }),
|
|
258
|
+
async execute(_id, params, signal) {
|
|
259
|
+
try {
|
|
260
|
+
return ok(JSON.stringify(await guard.visit(params.url, signal)));
|
|
261
|
+
}
|
|
262
|
+
catch (e) {
|
|
263
|
+
return errAsText(e);
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'save_source',
|
|
269
|
+
label: 'save_source',
|
|
270
|
+
description: '把当前已抓取页面的原文保存到本主题 sources/ 目录。每打开一页后调用一次;同页重复保存不写新文件。',
|
|
271
|
+
parameters: Type.Object({ url: Type.String({ description: '刚抓取的页面 URL' }) }),
|
|
272
|
+
async execute(_id, params) {
|
|
273
|
+
try {
|
|
274
|
+
// 直接返回 { savedCount, reused }
|
|
275
|
+
return ok(JSON.stringify(guard.saveSource(params.url)));
|
|
276
|
+
}
|
|
277
|
+
catch (e) {
|
|
278
|
+
return errAsText(e);
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: 'crawl_finish',
|
|
284
|
+
label: 'crawl_finish',
|
|
285
|
+
description: '结束抓取:清理浏览器并返回已保存页数。无更多有价值链接或到达上限时调用。',
|
|
286
|
+
parameters: Type.Object({}),
|
|
287
|
+
async execute() {
|
|
288
|
+
try {
|
|
289
|
+
await guard.close();
|
|
290
|
+
return ok(JSON.stringify({ finished: true, savedCount: guard.savedCount }));
|
|
291
|
+
}
|
|
292
|
+
catch (e) {
|
|
293
|
+
return errAsText(e);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
];
|
|
298
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface TopicSummary {
|
|
2
|
+
slug: string;
|
|
3
|
+
title: string;
|
|
4
|
+
summary: string;
|
|
5
|
+
tags: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeText(s: string): string;
|
|
8
|
+
export declare function findCandidates(cand: {
|
|
9
|
+
title: string;
|
|
10
|
+
tags: string[];
|
|
11
|
+
}, topics: TopicSummary[]): TopicSummary[];
|
|
12
|
+
export interface OutlineItem {
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
oneLine: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ChunkRefLike {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
summary: string;
|
|
21
|
+
tags: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface TopicIndexLike {
|
|
24
|
+
slug: string;
|
|
25
|
+
title: string;
|
|
26
|
+
summary: string;
|
|
27
|
+
tags: string[];
|
|
28
|
+
chunks: ChunkRefLike[];
|
|
29
|
+
}
|
|
30
|
+
export interface ReconcileResult {
|
|
31
|
+
match: boolean;
|
|
32
|
+
targetSlug?: string;
|
|
33
|
+
confidence?: number;
|
|
34
|
+
mergedTitle?: string;
|
|
35
|
+
mergedSummary?: string;
|
|
36
|
+
itemsToAdd?: OutlineItem[];
|
|
37
|
+
}
|
|
38
|
+
export declare const LLM_FULL_SCAN_MAX = 20;
|
|
39
|
+
export declare function readAllTopics(docsDir: string): Promise<TopicSummary[]>;
|
|
40
|
+
export declare function readTopicDetail(docsDir: string, slug: string): Promise<TopicIndexLike | null>;
|
|
41
|
+
export declare function reconcileTopics(opts: {
|
|
42
|
+
port: number;
|
|
43
|
+
docsDir: string;
|
|
44
|
+
candidate: {
|
|
45
|
+
slug: string;
|
|
46
|
+
title: string;
|
|
47
|
+
tags: string[];
|
|
48
|
+
items?: OutlineItem[];
|
|
49
|
+
};
|
|
50
|
+
targets?: Array<TopicSummary & {
|
|
51
|
+
chunks?: ChunkRefLike[];
|
|
52
|
+
}>;
|
|
53
|
+
wantItems: boolean;
|
|
54
|
+
}): Promise<ReconcileResult>;
|
|
55
|
+
export declare function mergeTopics(docsDir: string, srcSlug: string, dstSlug: string): number;
|
|
56
|
+
export declare function readSidecarDetail(docsDir: string, slug: string): Promise<TopicIndexLike | null>;
|
|
57
|
+
export declare function mintSlug(opts: {
|
|
58
|
+
port: number;
|
|
59
|
+
title: string;
|
|
60
|
+
existing: string[];
|
|
61
|
+
}): Promise<string>;
|
|
62
|
+
export declare function assertNoOldDirs(docsDir: string): void;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// learn 主题去重:纯字符串确定性预筛(不调 LLM、无 IO)
|
|
2
|
+
import { readFile } from 'fs/promises';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { runJsonPrompt } from './pi-runtime.js';
|
|
6
|
+
import { slugFromLabel } from './web-crawler.js';
|
|
7
|
+
// 合法 slug:小写字母数字开头,仅含小写字母数字与连字符
|
|
8
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
9
|
+
// 归一化:小写;非字母数字字符(含 -、_、! 等标点)统一替换为空格;trim 并压缩连续空白
|
|
10
|
+
// 标点替换为空格而非删除,使 state-management 与 State Management 归一后一致
|
|
11
|
+
export function normalizeText(s) {
|
|
12
|
+
return s.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, ' ').trim();
|
|
13
|
+
}
|
|
14
|
+
// 命中信号强度:归一 title 相等(0) > 任一归一 tag 相等(1) > title 互为子串(2)
|
|
15
|
+
export function findCandidates(cand, topics) {
|
|
16
|
+
const candTitle = normalizeText(cand.title);
|
|
17
|
+
const candTags = new Set(cand.tags.map(normalizeText).filter(Boolean));
|
|
18
|
+
// slug -> 命中的 topic 及其最强信号;按 slug 去重
|
|
19
|
+
const hits = new Map();
|
|
20
|
+
for (const topic of topics) {
|
|
21
|
+
const topicTitle = normalizeText(topic.title);
|
|
22
|
+
let rank = -1;
|
|
23
|
+
if (candTitle && topicTitle === candTitle) {
|
|
24
|
+
rank = 0;
|
|
25
|
+
}
|
|
26
|
+
else if (topic.tags.some(t => candTags.has(normalizeText(t)))) {
|
|
27
|
+
rank = 1;
|
|
28
|
+
}
|
|
29
|
+
else if (candTitle && topicTitle && (topicTitle.includes(candTitle) || candTitle.includes(topicTitle))) {
|
|
30
|
+
rank = 2;
|
|
31
|
+
}
|
|
32
|
+
if (rank === -1)
|
|
33
|
+
continue;
|
|
34
|
+
const prev = hits.get(topic.slug);
|
|
35
|
+
if (!prev || rank < prev.rank)
|
|
36
|
+
hits.set(topic.slug, { topic, rank });
|
|
37
|
+
}
|
|
38
|
+
// sort 稳定,同强度保持 topics 原始顺序
|
|
39
|
+
return [...hits.values()].sort((a, b) => a.rank - b.rank).map(h => h.topic);
|
|
40
|
+
}
|
|
41
|
+
// 预筛无命中时允许全量送 LLM 的目标上限;超过则安全放弃
|
|
42
|
+
export const LLM_FULL_SCAN_MAX = 20;
|
|
43
|
+
// 读全部 topic 摘要;index.json 缺失/损坏等任何异常一律返回 []
|
|
44
|
+
export async function readAllTopics(docsDir) {
|
|
45
|
+
try {
|
|
46
|
+
const raw = await readFile(path.join(docsDir, 'index.json'), 'utf8');
|
|
47
|
+
const data = JSON.parse(raw);
|
|
48
|
+
return Array.isArray(data.topics) ? data.topics : [];
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// 读单个 topic 详情;缺失/异常返回 null
|
|
55
|
+
export async function readTopicDetail(docsDir, slug) {
|
|
56
|
+
try {
|
|
57
|
+
const raw = await readFile(path.join(docsDir, slug, 'index.json'), 'utf8');
|
|
58
|
+
return JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// LLM 兜底:在确定性预筛无法排除重复时,请模型裁定候选是否应并入某已有 topic。
|
|
65
|
+
// 任何失败(IO、坏 JSON、超限)均安全降级为 { match: false }
|
|
66
|
+
export async function reconcileTopics(opts) {
|
|
67
|
+
const targets = opts.targets
|
|
68
|
+
?? (await readAllTopics(opts.docsDir)).filter(t => t.slug !== opts.candidate.slug);
|
|
69
|
+
// 先走确定性预筛;无命中且目标数在上限内才全量送 LLM,超限直接放弃
|
|
70
|
+
const hits = findCandidates({ title: opts.candidate.title, tags: opts.candidate.tags }, targets);
|
|
71
|
+
let chosen;
|
|
72
|
+
if (hits.length > 0) {
|
|
73
|
+
chosen = hits;
|
|
74
|
+
}
|
|
75
|
+
else if (targets.length > 0 && targets.length <= LLM_FULL_SCAN_MAX) {
|
|
76
|
+
chosen = targets;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
return { match: false };
|
|
80
|
+
}
|
|
81
|
+
const instructions = [
|
|
82
|
+
'你是主题去重裁定器。判断「新主题」与候选已有主题之间是否存在实质内容重叠。',
|
|
83
|
+
'判定从宽:只要主题域/核心问题实质重合就应判为重复,宁可合并,不要因措辞或粒度不同而漏判。',
|
|
84
|
+
'存在多个可能目标时,只选最匹配的一个,把它的 slug 填入 targetSlug。',
|
|
85
|
+
'判为重复时必须给出 mergedTitle(合并后的主题标题)与 mergedSummary(合并后的摘要)。',
|
|
86
|
+
opts.wantItems
|
|
87
|
+
? '同时给出 itemsToAdd:仅包含目标主题现有 chunks 尚未覆盖的、需要新增的大纲条目;已覆盖的条目不要放入。'
|
|
88
|
+
: '不要输出 itemsToAdd。',
|
|
89
|
+
'只返回一个 JSON 对象,不要输出任何解释或多余文本。',
|
|
90
|
+
'格式:{"match":boolean,"targetSlug":string,"confidence":number,"mergedTitle":string,"mergedSummary":string'
|
|
91
|
+
+ (opts.wantItems ? ',"itemsToAdd":[{"id":string,"title":string,"oneLine":string}]' : '')
|
|
92
|
+
+ '}',
|
|
93
|
+
].join('\n');
|
|
94
|
+
const prompt = `新主题:\n${JSON.stringify(opts.candidate)}\n\n候选已有主题:\n${JSON.stringify(chosen)}`;
|
|
95
|
+
try {
|
|
96
|
+
const result = await runJsonPrompt({ port: opts.port, instructions, prompt });
|
|
97
|
+
// 正载荷必须完整,且 targetSlug 必须在实际提供的 chosen 之中,否则安全降级
|
|
98
|
+
// (同时挡住候选自身 slug 回显、../ 路径穿越及任何未提供的目标)
|
|
99
|
+
const chosenSlugs = chosen.map(t => t.slug);
|
|
100
|
+
if (result && result.match === true &&
|
|
101
|
+
typeof result.targetSlug === 'string' && chosenSlugs.includes(result.targetSlug) &&
|
|
102
|
+
typeof result.mergedTitle === 'string' &&
|
|
103
|
+
typeof result.mergedSummary === 'string' &&
|
|
104
|
+
(!opts.wantItems || Array.isArray(result.itemsToAdd))) {
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
return { match: false };
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return { match: false };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// ---- 物理迁移:把 src 主题的 sources/chunks 统一并入 dst ----
|
|
114
|
+
// 3 位补零编号,与 orchestrator 落盘约定一致
|
|
115
|
+
function pad3(n) {
|
|
116
|
+
return String(n).padStart(3, '0');
|
|
117
|
+
}
|
|
118
|
+
// 列出 dir 下的 .md 文件名(排序);目录缺失视为空
|
|
119
|
+
function listMd(dir) {
|
|
120
|
+
try {
|
|
121
|
+
return fs.readdirSync(dir).filter(f => f.endsWith('.md')).sort();
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// 将 src 主题物理并入 dst:sources 续号拷贝、chunks 按 dst 现有数偏移重编号,
|
|
128
|
+
// 同步更新 dst index 与根 index,最后删除整个 src 目录。返回迁移后 dst 的 chunk 总数。
|
|
129
|
+
// srcSlug 可能是 x.old 旁挂目录(含点,路径直接拼接)。
|
|
130
|
+
export function mergeTopics(docsDir, srcSlug, dstSlug) {
|
|
131
|
+
// 防护自合并:LLM 可能回显候选自身 slug;自合并会重复 refs、移除自身根注册并删目录(数据丢失)
|
|
132
|
+
if (srcSlug === dstSlug)
|
|
133
|
+
throw new Error('mergeTopics: src 与 dst 相同');
|
|
134
|
+
const srcDir = path.join(docsDir, srcSlug);
|
|
135
|
+
const dstDir = path.join(docsDir, dstSlug);
|
|
136
|
+
// dst index 必须存在,缺失直接抛错;src index 同样读取(路径直接拼,支持 x.old)
|
|
137
|
+
const dstIndex = JSON.parse(fs.readFileSync(path.join(dstDir, 'index.json'), 'utf8'));
|
|
138
|
+
const srcIndex = JSON.parse(fs.readFileSync(path.join(srcDir, 'index.json'), 'utf8'));
|
|
139
|
+
// sources:按 dst 现有数量续号,逐个读→写 dst→删 src 原件(copy→unlink,避免跨设备 rename 失败)
|
|
140
|
+
const srcSources = listMd(path.join(srcDir, 'sources'));
|
|
141
|
+
const s0 = listMd(path.join(dstDir, 'sources')).length;
|
|
142
|
+
fs.mkdirSync(path.join(dstDir, 'sources'), { recursive: true });
|
|
143
|
+
srcSources.forEach((file, i) => {
|
|
144
|
+
const body = fs.readFileSync(path.join(srcDir, 'sources', file));
|
|
145
|
+
fs.writeFileSync(path.join(dstDir, 'sources', `source-${pad3(s0 + i + 1)}.md`), body);
|
|
146
|
+
fs.unlinkSync(path.join(srcDir, 'sources', file));
|
|
147
|
+
});
|
|
148
|
+
// chunks:src refs 按 id 排序,按 dst 现有 chunk 数偏移重编号;正文逐字拷贝不改
|
|
149
|
+
const srcRefs = [...srcIndex.chunks].sort((a, b) => a.id.localeCompare(b.id));
|
|
150
|
+
const k = dstIndex.chunks.length;
|
|
151
|
+
fs.mkdirSync(path.join(dstDir, 'chunks'), { recursive: true });
|
|
152
|
+
srcRefs.forEach((ref, i) => {
|
|
153
|
+
const newId = `chunk-${pad3(k + i + 1)}`;
|
|
154
|
+
const body = fs.readFileSync(path.join(srcDir, 'chunks', `${ref.id}.md`));
|
|
155
|
+
fs.writeFileSync(path.join(dstDir, 'chunks', `${newId}.md`), body);
|
|
156
|
+
fs.unlinkSync(path.join(srcDir, 'chunks', `${ref.id}.md`));
|
|
157
|
+
dstIndex.chunks.push({ ...ref, id: newId });
|
|
158
|
+
});
|
|
159
|
+
// 根 index:移除 slug===srcSlug 的条目(srcSlug 为 x.old 时不命中即 no-op)
|
|
160
|
+
try {
|
|
161
|
+
const rootPath = path.join(docsDir, 'index.json');
|
|
162
|
+
const root = JSON.parse(fs.readFileSync(rootPath, 'utf8'));
|
|
163
|
+
if (Array.isArray(root.topics)) {
|
|
164
|
+
root.topics = root.topics.filter(t => t.slug !== srcSlug);
|
|
165
|
+
fs.writeFileSync(rootPath, JSON.stringify(root, null, 2));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// 根 index 缺失/损坏:无条目可移除,跳过
|
|
170
|
+
}
|
|
171
|
+
// 删除整个 src 目录,写回 dst index
|
|
172
|
+
fs.rmSync(srcDir, { recursive: true, force: true });
|
|
173
|
+
fs.writeFileSync(path.join(dstDir, 'index.json'), JSON.stringify(dstIndex, null, 2));
|
|
174
|
+
return dstIndex.chunks.length;
|
|
175
|
+
}
|
|
176
|
+
// 读旁挂目录 <slug>.old 的 index.json;缺失/坏 → null
|
|
177
|
+
export async function readSidecarDetail(docsDir, slug) {
|
|
178
|
+
try {
|
|
179
|
+
const raw = await readFile(path.join(docsDir, `${slug}.old`, 'index.json'), 'utf8');
|
|
180
|
+
return JSON.parse(raw);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// 据 title 让 LLM 铸一个小写连字符 slug。失败/非法/已占 → 降级 slugFromLabel(title),
|
|
187
|
+
// 仍被占则追加 -2/-3…。返回保证合法且不落在 existing 内的 slug(除非编号也耗尽,实践不会)。
|
|
188
|
+
export async function mintSlug(opts) {
|
|
189
|
+
try {
|
|
190
|
+
const result = await runJsonPrompt({
|
|
191
|
+
port: opts.port,
|
|
192
|
+
instructions: 'Return ONLY JSON {"slug":"<lowercase-hyphen-slug>"} derived faithfully from the title.',
|
|
193
|
+
prompt: `Title: ${opts.title}`,
|
|
194
|
+
});
|
|
195
|
+
if (typeof result.slug === 'string' && SLUG_RE.test(result.slug) && !opts.existing.includes(result.slug)) {
|
|
196
|
+
return result.slug;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// LLM 调用/解析失败:走确定性降级
|
|
201
|
+
}
|
|
202
|
+
const base = slugFromLabel(opts.title) || 'topic';
|
|
203
|
+
if (!opts.existing.includes(base))
|
|
204
|
+
return base;
|
|
205
|
+
for (let n = 2;; n++) {
|
|
206
|
+
const candidate = `${base}-${n}`;
|
|
207
|
+
if (!opts.existing.includes(candidate))
|
|
208
|
+
return candidate;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// 阻断:docsDir 下存在任何 .old 旁挂目录时抛错,要求人工先处理。
|
|
212
|
+
// docsDir 本身缺失时直接让 readdirSync 抛错(调用方本就应在已初始化的库上学习)。
|
|
213
|
+
export function assertNoOldDirs(docsDir) {
|
|
214
|
+
const oldDir = fs.readdirSync(docsDir).find(name => name.endsWith('.old'));
|
|
215
|
+
if (oldDir) {
|
|
216
|
+
throw new Error(`检测到未清理的旁挂目录 ${oldDir},请手工处理后再学习`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface OutlineItem {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
oneLine: string;
|
|
5
|
+
}
|
|
6
|
+
export interface LearnPipelineEvents {
|
|
7
|
+
stageStart(stage: 'outline' | 'refine' | 'tag', totalItems?: number): void;
|
|
8
|
+
stageItemStart(index: number, total: number, title: string): void;
|
|
9
|
+
stageItemEnd(index: number, chunkId: string): void;
|
|
10
|
+
stageItemFailed(index: number, title: string, reason: string): void;
|
|
11
|
+
stageEnd(stage: 'outline' | 'refine' | 'tag'): void;
|
|
12
|
+
roundStart(roundIndex: number): void;
|
|
13
|
+
roundEnd(roundIndex: number): void;
|
|
14
|
+
textDelta(delta: string): void;
|
|
15
|
+
thinkingDelta(delta: string): void;
|
|
16
|
+
toolStart(e: {
|
|
17
|
+
toolCallId: string;
|
|
18
|
+
toolName: string;
|
|
19
|
+
args: unknown;
|
|
20
|
+
}): void;
|
|
21
|
+
toolEnd(e: {
|
|
22
|
+
toolCallId: string;
|
|
23
|
+
toolName: string;
|
|
24
|
+
isError: boolean;
|
|
25
|
+
durationMs: number;
|
|
26
|
+
result: string;
|
|
27
|
+
}): void;
|
|
28
|
+
}
|
|
29
|
+
export interface RunLearnPipelineOptions {
|
|
30
|
+
sourceType: 'url' | 'file';
|
|
31
|
+
/** url 模式=入口 URL;file 模式=上传得到的 markdown 正文 */
|
|
32
|
+
input: string;
|
|
33
|
+
/** file 模式文件名(生成 slug 用);url 可省略 */
|
|
34
|
+
label?: string;
|
|
35
|
+
port: number;
|
|
36
|
+
events: LearnPipelineEvents;
|
|
37
|
+
/** 注入式 docsDir(测试用);默认 ~/.cc-monitoring/docs */
|
|
38
|
+
docsDir?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function runLearnPipeline(opts: RunLearnPipelineOptions): Promise<{
|
|
41
|
+
slug: string;
|
|
42
|
+
chunksWritten: number;
|
|
43
|
+
itemsFailed: number;
|
|
44
|
+
}>;
|