@cc-monitoring/proxy-core 0.1.8 → 0.1.9
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/cli/commands/mcp.d.ts +1 -0
- package/dist/cli/commands/mcp.js +5 -0
- package/dist/cli/index.js +12 -0
- package/dist/docs/404.html +1 -1
- package/dist/docs/assets/{app.CLpmq4Gv.js → app.Dc5qjt2Z.js} +1 -1
- package/dist/docs/assets/chunks/{VPLocalSearchBox.C43HQ5tU.js → VPLocalSearchBox.DNn4HwDn.js} +1 -1
- package/dist/docs/assets/chunks/{abnfDiagram-VRR7QNED.RG1C5NpS.js → abnfDiagram-VRR7QNED.CO3oJlfv.js} +1 -1
- package/dist/docs/assets/chunks/{arc.C9NMazfV.js → arc.D6Q1WZEU.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-ZJ3FMSHR.u2IZtOa6.js → architectureDiagram-ZJ3FMSHR.vHAxAkhu.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-677ZJIJ3.DdHVir7t.js → blockDiagram-677ZJIJ3.C0el4zil.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-LMCZKHZV.gSbgoaJo.js → c4Diagram-LMCZKHZV.WD7qpLTf.js} +1 -1
- package/dist/docs/assets/chunks/channel.nWTiHmYA.js +1 -0
- package/dist/docs/assets/chunks/{chunk-2Q5K7J3B.HRSdtksv.js → chunk-2Q5K7J3B.Bgt7N_Co.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-32BRIVSS.BYzKapof.js → chunk-32BRIVSS.CbP8heQ0.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-5VM5RSS4.c3oeF0uS.js → chunk-5VM5RSS4.Dlc2iAaG.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EX3LRPZG.Cz5AKl7t.js → chunk-EX3LRPZG.Cr0sQbRc.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-JWPE2WC7.DtJxsA7-.js → chunk-JWPE2WC7.B52h3S9L.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-MOJQB5TN.h5kO0Dtu.js → chunk-MOJQB5TN.CphhXnWQ.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-RYQCIY6F.Ch_NfMTR.js → chunk-RYQCIY6F.CZafA9pg.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-V7JOEXUC.CHrHyPoW.js → chunk-V7JOEXUC.DMlMAq_a.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-VR4S4FIN.DG8DIrH3.js → chunk-VR4S4FIN.DA1An2TL.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-XXDRQBXY.CSXBN12Y.js → chunk-XXDRQBXY.Dwra-T5p.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-OUVF2IWQ.RsrQkeM_.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-EOCWNBFH.RsrQkeM_.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-JH36ORCC.BeFuOTgi.js → cose-bilkent-JH36ORCC.Ddhn5b9l.js} +1 -1
- package/dist/docs/assets/chunks/{cynefinDiagram-TSTJHNR4.BrJcHEEe.js → cynefinDiagram-TSTJHNR4.BlUCFIAV.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-VKFMJZFB.D4vaA23X.js → dagre-VKFMJZFB.erCsZJb8.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-FQU43EPY.uwRFLKRx.js → diagram-FQU43EPY.B0zbjZsr.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G47NLZAW.Byfc9d0H.js → diagram-G47NLZAW.B4S_wuz1.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-NH7WQ7WH.CxjBEGZX.js → diagram-NH7WQ7WH.BRv6nOgk.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-OA4YK3LP.CU1jGXMi.js → diagram-OA4YK3LP.DBS8iZPq.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-WEI45ONY.yXgVkURA.js → diagram-WEI45ONY.CDZlR-fM.js} +1 -1
- package/dist/docs/assets/chunks/{ebnfDiagram-CCIWWBDH.UucqGQ_d.js → ebnfDiagram-CCIWWBDH.z_nUDDWm.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-Q63AITRT.C6qmOrvh.js → erDiagram-Q63AITRT.BOAH1mBM.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-23GEKE2U.BZLu-WUl.js → flowDiagram-23GEKE2U.cnCU0na-.js} +1 -1
- package/dist/docs/assets/chunks/{ganttDiagram-NO4QXBWP.DUzsw4Yr.js → ganttDiagram-NO4QXBWP.CzSToCFq.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-IHSO6WYX.BqLfYTI7.js → gitGraphDiagram-IHSO6WYX.WUBTiDD1.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-FWYZ7A6U.CiKWveW9.js → infoDiagram-FWYZ7A6U.Bz5y9qpB.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-FXEZZL3T.jerUXEXA.js → ishikawaDiagram-FXEZZL3T.DX9mwIpB.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-5HDEW3XC.Cqzvo6I_.js → journeyDiagram-5HDEW3XC.BclISEWC.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-HUTT4EX6.BzJ4OPe5.js → kanban-definition-HUTT4EX6.CMwsG4gj.js} +1 -1
- package/dist/docs/assets/chunks/{linear.hFjgYGMN.js → linear.zokB3L6J.js} +1 -1
- package/dist/docs/assets/chunks/{mermaid-client.D3gEaJ5e.js → mermaid-client.DIhzjS3B.js} +2 -2
- package/dist/docs/assets/chunks/{mermaid.core.CEHdFh45.js → mermaid.core.CJEoCnVo.js} +102 -98
- package/dist/docs/assets/chunks/{mindmap-definition-LN4V7U3C.ChC5FJW6.js → mindmap-definition-LN4V7U3C.DeNvpAwd.js} +1 -1
- package/dist/docs/assets/chunks/{pegDiagram-2B236MQR.ClnjsRYs.js → pegDiagram-2B236MQR.D5O5vyDS.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-ENE6RG2P.Bb0MqerK.js → pieDiagram-ENE6RG2P.CDpZrox4.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-ABIIQ3AL.Do6HK_yb.js → quadrantDiagram-ABIIQ3AL.Bz0dhK1l.js} +1 -1
- package/dist/docs/assets/chunks/{railroadDiagram-RFXS5EU6.D35m6hQn.js → railroadDiagram-RFXS5EU6.C2h0Mxo5.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-TGXJPOKE.DMtjRYUg.js → requirementDiagram-TGXJPOKE.YLD-NuJw.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-HTMAVEWB.dfXDu62B.js → sankeyDiagram-HTMAVEWB.R2uEIhmV.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-DBY2YBRQ.CLZ0rZTY.js → sequenceDiagram-DBY2YBRQ.D6E2oY7U.js} +1 -1
- package/dist/docs/assets/chunks/{sizeCapture-X5ZJPWSS.DWvGYLUT.js → sizeCapture-X5ZJPWSS.C65Lzwwi.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-2N3HPSRC.DY8sDkI0.js → stateDiagram-2N3HPSRC.Cqc4HEHT.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-6OUMAXLB.D8rYKDmp.js +1 -0
- package/dist/docs/assets/chunks/{swimlanes-5IMT3BWC.Dy9SffeT.js → swimlanes-5IMT3BWC.dfhQuNQg.js} +2 -2
- package/dist/docs/assets/chunks/swimlanesDiagram-G3AALYLV.CdD0ADbF.js +8 -0
- package/dist/docs/assets/chunks/{theme.CSw9Whd5.js → theme.DCDU4HCI.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-FHXFAJF6.CH6uzgIu.js → timeline-definition-FHXFAJF6.SOgdni8I.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-L72KCM5P.7EBCJmyP.js → vennDiagram-L72KCM5P.BvlXlHJf.js} +1 -1
- package/dist/docs/assets/chunks/{wardleyDiagram-EHGQE667.DPHAQssL.js → wardleyDiagram-EHGQE667.t3t8sFvo.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-FW5EYKEG.aKgxZVbK.js → xychartDiagram-FW5EYKEG.DDT1UX32.js} +1 -1
- 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.d.ts +3 -0
- package/dist/mcp-server/index.js +16 -0
- package/dist/mcp-server/run.d.ts +1 -0
- package/dist/mcp-server/run.js +14 -0
- package/dist/mcp-server/tools.d.ts +11 -0
- package/dist/mcp-server/tools.js +219 -0
- package/dist/server/docs-route.js +42 -13
- package/dist/server/index.js +3 -2
- package/dist/server/ui-route.js +161 -103
- package/dist/ui/assets/{1c-DPsrzNHI.js → 1c-CK-kMhtR.js} +1 -1
- package/dist/ui/assets/{abnf-DNkBIQRO.js → abnf-1lQ1Uzrr.js} +1 -1
- package/dist/ui/assets/{abnfDiagram-VRR7QNED-BqvHvzR8.js → abnfDiagram-VRR7QNED-BqMOdnuh.js} +1 -1
- package/dist/ui/assets/{accesslog-D5NxQ43Q.js → accesslog-BGadK9Fx.js} +1 -1
- package/dist/ui/assets/{actionscript-DLr-LB2m.js → actionscript-4t1vDHvB.js} +1 -1
- package/dist/ui/assets/{ada-BRSz3tHX.js → ada-CTSY_kbf.js} +1 -1
- package/dist/ui/assets/{angelscript-DMtEGgIa.js → angelscript-BX_1_lW7.js} +1 -1
- package/dist/ui/assets/{apache-C4gn4cSd.js → apache-DeUUxSLd.js} +1 -1
- package/dist/ui/assets/{applescript-DoodcTwg.js → applescript-BUfqUe12.js} +1 -1
- package/dist/ui/assets/{arc-HmnzaGf9.js → arc-D-xOtktL.js} +1 -1
- package/dist/ui/assets/{arcade-RJZZSHSl.js → arcade-BlZbrfiI.js} +1 -1
- package/dist/ui/assets/{architectureDiagram-ZJ3FMSHR-BUfDpSIw.js → architectureDiagram-ZJ3FMSHR-KN5x3Oxc.js} +1 -1
- package/dist/ui/assets/{arduino-n6Dpx6Ig.js → arduino-CmMMxhu0.js} +1 -1
- package/dist/ui/assets/{armasm-DzCVITGB.js → armasm-If0W0ZTH.js} +1 -1
- package/dist/ui/assets/{asciidoc-CaqMsApq.js → asciidoc-DD6e-k3f.js} +1 -1
- package/dist/ui/assets/{aspectj-B0kIcV0v.js → aspectj-MxQxriHk.js} +1 -1
- package/dist/ui/assets/{autohotkey-xUEXewap.js → autohotkey-Ahz4SejW.js} +1 -1
- package/dist/ui/assets/{autoit-D3OfN2VX.js → autoit-DwDj3imC.js} +1 -1
- package/dist/ui/assets/{avrasm-Cbf0F4Kf.js → avrasm-97KvbVpn.js} +1 -1
- package/dist/ui/assets/{awk-Cc0rWEwe.js → awk-Bo_-wZyZ.js} +1 -1
- package/dist/ui/assets/{axapta-BKEeoUEe.js → axapta-DR_HV06c.js} +1 -1
- package/dist/ui/assets/{bash-D6JH6L3m.js → bash-dxvpXEou.js} +1 -1
- package/dist/ui/assets/{basic-ka6JXc9C.js → basic-Dw-3a82q.js} +1 -1
- package/dist/ui/assets/{blockDiagram-677ZJIJ3-BHXRSjnM.js → blockDiagram-677ZJIJ3-CMXz5JvW.js} +1 -1
- package/dist/ui/assets/{bnf-Bxclk5tZ.js → bnf-5ey_2QkR.js} +1 -1
- package/dist/ui/assets/{brainfuck--s_Fd8b9.js → brainfuck-CbRmZUzR.js} +1 -1
- package/dist/ui/assets/{coq-CVLui3m8.js → c-DUcxiMx7.js} +1 -1
- package/dist/ui/assets/{c-like-CNkOkbqh.js → c-like-D9kw6QEo.js} +1 -1
- package/dist/ui/assets/{c4Diagram-LMCZKHZV-Bp1uSrW8.js → c4Diagram-LMCZKHZV-DU4C988i.js} +1 -1
- package/dist/ui/assets/{cal-LVlIOy9W.js → cal-BXDKT54m.js} +1 -1
- package/dist/ui/assets/{capnproto-r9DiQ1H8.js → capnproto-DXByvzkB.js} +1 -1
- package/dist/ui/assets/{ceylon-CTNzyZJX.js → ceylon-CNMAc9bK.js} +1 -1
- package/dist/ui/assets/channel-limbQkil.js +1 -0
- package/dist/ui/assets/{chunk-2Q5K7J3B-nnLVtUW3.js → chunk-2Q5K7J3B-Cm-SVU-u.js} +1 -1
- package/dist/ui/assets/{chunk-32BRIVSS-BDNS6igp.js → chunk-32BRIVSS-oz0KK3YS.js} +1 -1
- package/dist/ui/assets/{chunk-5VM5RSS4-D713xBhI.js → chunk-5VM5RSS4-CbHdtlYp.js} +1 -1
- package/dist/ui/assets/{chunk-EX3LRPZG-DExsU6Rd.js → chunk-EX3LRPZG-DhhuYakR.js} +1 -1
- package/dist/ui/assets/{chunk-JWPE2WC7-DcpW5RnW.js → chunk-JWPE2WC7-CYkjHxPj.js} +1 -1
- package/dist/ui/assets/{chunk-MOJQB5TN-BQiSZNTn.js → chunk-MOJQB5TN-gO40CNAh.js} +1 -1
- package/dist/ui/assets/{chunk-RYQCIY6F-DfblgZPd.js → chunk-RYQCIY6F-CKedXT_Q.js} +1 -1
- package/dist/ui/assets/{chunk-V7JOEXUC-np--VgmN.js → chunk-V7JOEXUC-C_6jfVpf.js} +1 -1
- package/dist/ui/assets/{chunk-VR4S4FIN-BG0IhjO6.js → chunk-VR4S4FIN-C8NVa2Dp.js} +1 -1
- package/dist/ui/assets/{chunk-XXDRQBXY-DHuoh-RB.js → chunk-XXDRQBXY-DCaDk-GY.js} +1 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ--Q3UeFsZ.js +1 -0
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH--Q3UeFsZ.js +1 -0
- package/dist/ui/assets/{clean-CtVj0-EB.js → clean-Cno2Iol9.js} +1 -1
- package/dist/ui/assets/{clojure-CZwle60-.js → clojure-CJo86K2y.js} +1 -1
- package/dist/ui/assets/{clojure-repl-DJXWH00I.js → clojure-repl-BDUy3x0z.js} +1 -1
- package/dist/ui/assets/{cmake-Boxf0e7r.js → cmake-C3lBpnMa.js} +1 -1
- package/dist/ui/assets/{coffeescript-h85ZW4Gm.js → coffeescript-D6Gc1Iic.js} +1 -1
- package/dist/ui/assets/{c-BsgdDna0.js → coq-DK5Qpymm.js} +1 -1
- package/dist/ui/assets/{cos-CL0igafw.js → cos-C9vhICZi.js} +1 -1
- package/dist/ui/assets/{cose-bilkent-JH36ORCC-CnXyotYB.js → cose-bilkent-JH36ORCC-BsX7zIIX.js} +1 -1
- package/dist/ui/assets/{cpp-vite1NvJ.js → cpp-B2THrLw2.js} +1 -1
- package/dist/ui/assets/{crmsh-DqT9g0Iq.js → crmsh-Cidhwnbv.js} +1 -1
- package/dist/ui/assets/{crystal-Oans-K8G.js → crystal-D4UzipzS.js} +1 -1
- package/dist/ui/assets/{csharp-sCaDAzIB.js → csharp-sHzRBXom.js} +1 -1
- package/dist/ui/assets/{csp-rMcp93pK.js → csp-RR_2otDZ.js} +1 -1
- package/dist/ui/assets/{css-BwDLHi_h.js → css-CwufTY20.js} +1 -1
- package/dist/ui/assets/{cynefin-VYW2F7L2-D8Bmecdd.js → cynefin-VYW2F7L2-BdPPij9L.js} +1 -1
- package/dist/ui/assets/{cynefinDiagram-TSTJHNR4-BT2YFmPZ.js → cynefinDiagram-TSTJHNR4-Y8HasE5a.js} +1 -1
- package/dist/ui/assets/{d-BFgZm0RV.js → d-DeXSSL8w.js} +1 -1
- package/dist/ui/assets/{dagre-VKFMJZFB-BeJU73ex.js → dagre-VKFMJZFB-B_nm4MgH.js} +1 -1
- package/dist/ui/assets/{dart-rIo85iL3.js → dart-DhBp0MgA.js} +1 -1
- package/dist/ui/assets/{delphi-Bi2Rfp1o.js → delphi-B5k-wYBj.js} +1 -1
- package/dist/ui/assets/{diagram-FQU43EPY-CHQiS5Fr.js → diagram-FQU43EPY-CgBlXe2t.js} +1 -1
- package/dist/ui/assets/{diagram-G47NLZAW-EVerd4V8.js → diagram-G47NLZAW-BebzwVx5.js} +1 -1
- package/dist/ui/assets/{diagram-NH7WQ7WH-DMP0VOAs.js → diagram-NH7WQ7WH-DzWivpuq.js} +1 -1
- package/dist/ui/assets/{diagram-OA4YK3LP-CAur5jK9.js → diagram-OA4YK3LP-Cb_lMSnX.js} +1 -1
- package/dist/ui/assets/{diagram-WEI45ONY-DvmKkPH7.js → diagram-WEI45ONY-C_Y9GQ0N.js} +1 -1
- package/dist/ui/assets/{diff-CZZCIG00.js → diff-COhluegM.js} +1 -1
- package/dist/ui/assets/{django-D88PKHy-.js → django-C7XlHtBx.js} +1 -1
- package/dist/ui/assets/{dns-DX4hzjUh.js → dns-wjwUM-Uq.js} +1 -1
- package/dist/ui/assets/{dockerfile-1lgzEXn1.js → dockerfile-Bc-WqdkT.js} +1 -1
- package/dist/ui/assets/{dos-CwrC1ROy.js → dos-mEp9A4Hm.js} +1 -1
- package/dist/ui/assets/{dsconfig-tvVdBv4w.js → dsconfig-Dgs83FGD.js} +1 -1
- package/dist/ui/assets/{dts-DTgQkdRs.js → dts-C3Ds2O26.js} +1 -1
- package/dist/ui/assets/{dust-BbLlyCpf.js → dust-CyQO5OHb.js} +1 -1
- package/dist/ui/assets/{ebnf-D6Dc4oRr.js → ebnf-CNogRDO4.js} +1 -1
- package/dist/ui/assets/{ebnfDiagram-CCIWWBDH-Kvilk1RF.js → ebnfDiagram-CCIWWBDH-ZlE-AFZT.js} +1 -1
- package/dist/ui/assets/{elixir-CnMolQVs.js → elixir-3SLljiDu.js} +1 -1
- package/dist/ui/assets/{elm-BQ7VQFn7.js → elm-BPBZeCUB.js} +1 -1
- package/dist/ui/assets/{erDiagram-Q63AITRT-C-S9oHZd.js → erDiagram-Q63AITRT-CXuGvWcB.js} +1 -1
- package/dist/ui/assets/{erb-B_1g6fXE.js → erb-DqbIyjtE.js} +1 -1
- package/dist/ui/assets/{erlang-repl-Cy6Z3TdH.js → erlang-repl-e_6K45XY.js} +1 -1
- package/dist/ui/assets/{erlang-3b3ITXJu.js → erlang-y0z0xXo_.js} +1 -1
- package/dist/ui/assets/{excel-DtkATto8.js → excel-RwNCmSYM.js} +1 -1
- package/dist/ui/assets/{fix-DsEG7TDI.js → fix-DNXnlXQP.js} +1 -1
- package/dist/ui/assets/{flix-CQ-rKwGO.js → flix-rdcWVVc-.js} +1 -1
- package/dist/ui/assets/{flowDiagram-23GEKE2U-EbHDNMCC.js → flowDiagram-23GEKE2U-BuKpfhyd.js} +1 -1
- package/dist/ui/assets/{fortran-AqzaRCEt.js → fortran-CjB2gctQ.js} +1 -1
- package/dist/ui/assets/{fsharp-CCzWGasu.js → fsharp-DPGDnrod.js} +1 -1
- package/dist/ui/assets/{gams-Bqa6CB_r.js → gams-d97ChOge.js} +1 -1
- package/dist/ui/assets/{ganttDiagram-NO4QXBWP-B6jvc6O7.js → ganttDiagram-NO4QXBWP-CThfmoNX.js} +1 -1
- package/dist/ui/assets/{gauss-D4Utubeh.js → gauss-Ckbq9pov.js} +1 -1
- package/dist/ui/assets/{gcode-By3KwWjb.js → gcode-C8rxWIBi.js} +1 -1
- package/dist/ui/assets/{gherkin-PXOPjT7Y.js → gherkin-Cb88ENJ2.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-IHSO6WYX-C5l6rHvK.js → gitGraphDiagram-IHSO6WYX-Ch4mA1xX.js} +1 -1
- package/dist/ui/assets/{glsl-KmmyBk93.js → glsl-D75QPnvr.js} +1 -1
- package/dist/ui/assets/{gml-C1Qw_Nrt.js → gml-BYM-XcrL.js} +1 -1
- package/dist/ui/assets/{go-DaBQtdp1.js → go-C0q3a0K-.js} +1 -1
- package/dist/ui/assets/{golo-D7PDzNpb.js → golo-BN-kAS6i.js} +1 -1
- package/dist/ui/assets/{gradle-nXueCYH-.js → gradle-CsmhRGnx.js} +1 -1
- package/dist/ui/assets/{groovy-DFDsQDhl.js → groovy-CVvlYgLe.js} +1 -1
- package/dist/ui/assets/{haml-B_zxHzy_.js → haml-BZ1z9lT4.js} +1 -1
- package/dist/ui/assets/{handlebars-BdMY-8KA.js → handlebars-ByoXIUsU.js} +1 -1
- package/dist/ui/assets/{haskell-CftsIPps.js → haskell-bKtVloMo.js} +1 -1
- package/dist/ui/assets/{haxe-BFZb0OIE.js → haxe-7YhuN0qz.js} +1 -1
- package/dist/ui/assets/{hsp-EPTuqwtZ.js → hsp-Bgvcm6F3.js} +1 -1
- package/dist/ui/assets/{htmlbars-B7ZSC-iN.js → htmlbars-BpuFL8Dv.js} +1 -1
- package/dist/ui/assets/{http-BxSd_aa1.js → http-BdkFJc_6.js} +1 -1
- package/dist/ui/assets/{hy-D-rBN9MQ.js → hy-fLVT9AqM.js} +1 -1
- package/dist/ui/assets/{index-Dlp8uGHu.js → index-DfWIGcNl.js} +3 -3
- package/dist/ui/assets/index-DpS8gUTx.css +10 -0
- package/dist/ui/assets/{index-DSGZBcd1.js → index-Dsue7VlR.js} +302 -352
- package/dist/ui/assets/{infoDiagram-FWYZ7A6U-BOF_kBqe.js → infoDiagram-FWYZ7A6U-DBgU6pXz.js} +1 -1
- package/dist/ui/assets/{inform7-OjpbRXZf.js → inform7-CiZzJ9ba.js} +1 -1
- package/dist/ui/assets/{ini-Dc-QApXQ.js → ini-Cnt_l57a.js} +1 -1
- package/dist/ui/assets/{irpf90-C4OfYiST.js → irpf90-tpOLGqpx.js} +1 -1
- package/dist/ui/assets/{isbl-9km6K6Sf.js → isbl-CP9CH5cc.js} +1 -1
- package/dist/ui/assets/{ishikawaDiagram-FXEZZL3T-BvKSD8LY.js → ishikawaDiagram-FXEZZL3T-Cq-UEF7t.js} +1 -1
- package/dist/ui/assets/{java-C2mOf3QX.js → java-kyhtR5gA.js} +1 -1
- package/dist/ui/assets/{javascript-_i0Q5MkQ.js → javascript-Dt9hxK6y.js} +1 -1
- package/dist/ui/assets/{jboss-cli-BS5ipQOv.js → jboss-cli-BJZewHIt.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-5HDEW3XC-yKdSl63P.js → journeyDiagram-5HDEW3XC-iLTD7hUv.js} +1 -1
- package/dist/ui/assets/{json-Dci0MO4x.js → json-B784rDGN.js} +1 -1
- package/dist/ui/assets/{julia-bEqo4nlV.js → julia-BBZWRf_K.js} +1 -1
- package/dist/ui/assets/{julia-repl-Co6hf47q.js → julia-repl-ChQ_anXf.js} +1 -1
- package/dist/ui/assets/{kanban-definition-HUTT4EX6-B7BbZCd6.js → kanban-definition-HUTT4EX6-DnmU4pyp.js} +1 -1
- package/dist/ui/assets/{kotlin-krx8WewB.js → kotlin-Ca3cQqj9.js} +1 -1
- package/dist/ui/assets/{lasso-d3ZTv9Tj.js → lasso-68xMTGCI.js} +1 -1
- package/dist/ui/assets/{latex-BNWbHYxK.js → latex-BJAvHrS-.js} +1 -1
- package/dist/ui/assets/{ldif-Bs8eb63L.js → ldif-BozIkxE8.js} +1 -1
- package/dist/ui/assets/{leaf-BTbRDVWB.js → leaf-DeAYBX7h.js} +1 -1
- package/dist/ui/assets/{less-DH5cqJTD.js → less-Bc0jcew8.js} +1 -1
- package/dist/ui/assets/{lisp-CBUvBYtR.js → lisp-ffZdTilE.js} +1 -1
- package/dist/ui/assets/{livecodeserver-CkM7-E4a.js → livecodeserver-DKyXE2lg.js} +1 -1
- package/dist/ui/assets/{livescript-DomXyXUO.js → livescript-CeVSdP5j.js} +1 -1
- package/dist/ui/assets/{llvm-e_-ff59-.js → llvm-CA19rs9e.js} +1 -1
- package/dist/ui/assets/{lsl-BNDsGOmv.js → lsl-De1V90GL.js} +1 -1
- package/dist/ui/assets/{lua-_ZmkXwc_.js → lua-Ckc_sOAg.js} +1 -1
- package/dist/ui/assets/{makefile-BhG7cThe.js → makefile-BlkvlESW.js} +1 -1
- package/dist/ui/assets/{markdown-ClW2SRy6.js → markdown-BsHfdULh.js} +1 -1
- package/dist/ui/assets/{mathematica-kqoCR611.js → mathematica-BdVzKfdF.js} +1 -1
- package/dist/ui/assets/{matlab-DqawyK3q.js → matlab-BE1b3EYS.js} +1 -1
- package/dist/ui/assets/{maxima-B0qzCXe1.js → maxima-C7hoTDGn.js} +1 -1
- package/dist/ui/assets/{mel-BZaSas3B.js → mel-DNZ4AX0h.js} +1 -1
- package/dist/ui/assets/{mercury-ByD0wyJH.js → mercury-DnbIrIOF.js} +1 -1
- package/dist/ui/assets/{mindmap-definition-LN4V7U3C-Ce6QsaH5.js → mindmap-definition-LN4V7U3C-Df0J4YS6.js} +1 -1
- package/dist/ui/assets/{mipsasm-B08lqZSo.js → mipsasm-vRzAjdOa.js} +1 -1
- package/dist/ui/assets/{mizar-7iaUqWPq.js → mizar-_COCUpjs.js} +1 -1
- package/dist/ui/assets/{mojolicious-CbH-d8Wh.js → mojolicious-BXSqEUhN.js} +1 -1
- package/dist/ui/assets/{monkey-D5z6-hFH.js → monkey-DdaFErmE.js} +1 -1
- package/dist/ui/assets/{moonscript-DuLd7pdm.js → moonscript-ylkEnmhz.js} +1 -1
- package/dist/ui/assets/{n1ql-EbVfQMfD.js → n1ql-CmU80AjO.js} +1 -1
- package/dist/ui/assets/{nginx-D-4AxpHP.js → nginx-Xq7ZP4_a.js} +1 -1
- package/dist/ui/assets/{nim-wPHQEX5v.js → nim-9UGxbeVX.js} +1 -1
- package/dist/ui/assets/{nix-6SVkxAXi.js → nix-DF4g-5JC.js} +1 -1
- package/dist/ui/assets/{node-repl-CaFKEOyj.js → node-repl-Cuy9El0l.js} +1 -1
- package/dist/ui/assets/{nsis-BmqbwVv_.js → nsis-O_u_AJ8R.js} +1 -1
- package/dist/ui/assets/{objectivec-BX0R-sI2.js → objectivec-CGRDK5jQ.js} +1 -1
- package/dist/ui/assets/{ocaml-CyfdrIqo.js → ocaml-CbQcAD-R.js} +1 -1
- package/dist/ui/assets/{openscad-B5qfaF1E.js → openscad-DT2CMIqE.js} +1 -1
- package/dist/ui/assets/{oxygene-CmlCgXLr.js → oxygene-B9Ei-fnj.js} +1 -1
- package/dist/ui/assets/{parser3-DdpPyZkn.js → parser3-CuVObcEZ.js} +1 -1
- package/dist/ui/assets/{pegDiagram-2B236MQR-ByyVqaXh.js → pegDiagram-2B236MQR-k8i-gID4.js} +1 -1
- package/dist/ui/assets/{perl-D3qc2wEe.js → perl-dVGJ8bE1.js} +1 -1
- package/dist/ui/assets/{pf-Bv3zza37.js → pf-X2PQAhR-.js} +1 -1
- package/dist/ui/assets/{pgsql-BZIppw1a.js → pgsql-DVzCzD92.js} +1 -1
- package/dist/ui/assets/{php-D1ScecZC.js → php-DocTOgNe.js} +1 -1
- package/dist/ui/assets/{php-template-sEqzzKWJ.js → php-template-dP8srdEx.js} +1 -1
- package/dist/ui/assets/{pieDiagram-ENE6RG2P-T1OgWN3l.js → pieDiagram-ENE6RG2P-C76s3Fdz.js} +1 -1
- package/dist/ui/assets/{plaintext-DO7Jy_T2.js → plaintext-vjpxtrpz.js} +1 -1
- package/dist/ui/assets/{pony-CTXTp2Tb.js → pony-z-bq7AaS.js} +1 -1
- package/dist/ui/assets/{powershell-C9lzZsbj.js → powershell-DW0_Tsne.js} +1 -1
- package/dist/ui/assets/{processing-hzJAP_Li.js → processing-bDmnj3oy.js} +1 -1
- package/dist/ui/assets/{profile-bFiAkh7e.js → profile-DJ-L-V1f.js} +1 -1
- package/dist/ui/assets/{prolog-CE0trHSn.js → prolog-InNU9tFQ.js} +1 -1
- package/dist/ui/assets/{properties-MeANnTVc.js → properties-EkF7cZTJ.js} +1 -1
- package/dist/ui/assets/{protobuf-S-rp7SK0.js → protobuf-BBRUbDYu.js} +1 -1
- package/dist/ui/assets/{puppet-B5YT8Ct1.js → puppet-fnCmZBIC.js} +1 -1
- package/dist/ui/assets/{purebasic-DO-5HeDl.js → purebasic-CgWDuH3f.js} +1 -1
- package/dist/ui/assets/{python-DVGTQbwU.js → python-CYT42SmK.js} +1 -1
- package/dist/ui/assets/{python-repl-CQ4VlKLC.js → python-repl-Wc3MvYdm.js} +1 -1
- package/dist/ui/assets/{q-nS96imov.js → q-C0agAWLY.js} +1 -1
- package/dist/ui/assets/{qml-BkzkCgUU.js → qml-BiFendDb.js} +1 -1
- package/dist/ui/assets/{quadrantDiagram-ABIIQ3AL-BkaCzlXD.js → quadrantDiagram-ABIIQ3AL-B0fDeX13.js} +1 -1
- package/dist/ui/assets/{r-y4Q5t85r.js → r-CcAL_gsb.js} +1 -1
- package/dist/ui/assets/{railroadDiagram-RFXS5EU6-C1lbwk19.js → railroadDiagram-RFXS5EU6-DOciFfD8.js} +1 -1
- package/dist/ui/assets/{reasonml-Bzhzc5Ao.js → reasonml-DnTQ-jkN.js} +1 -1
- package/dist/ui/assets/{requirementDiagram-TGXJPOKE-C8Rw6N2I.js → requirementDiagram-TGXJPOKE-BhpERBEw.js} +1 -1
- package/dist/ui/assets/{rib-BP3Y9dW3.js → rib-DRQBJUku.js} +1 -1
- package/dist/ui/assets/{roboconf-87QE7cIh.js → roboconf-Dt4hxDSc.js} +1 -1
- package/dist/ui/assets/{routeros-BV3nt8wW.js → routeros-DrysyAvp.js} +1 -1
- package/dist/ui/assets/{rsl-DfQf4CW_.js → rsl-BhobC4bl.js} +1 -1
- package/dist/ui/assets/{ruby-DQxFKbgX.js → ruby-B0gNTjSn.js} +1 -1
- package/dist/ui/assets/{ruleslanguage-B8oCm_aw.js → ruleslanguage-BJHWtkQf.js} +1 -1
- package/dist/ui/assets/{rust-DzZgPf9W.js → rust-bxFjTZl9.js} +1 -1
- package/dist/ui/assets/{sankeyDiagram-HTMAVEWB-Dxiuo8Hz.js → sankeyDiagram-HTMAVEWB-BJGvRvK8.js} +1 -1
- package/dist/ui/assets/{sas-CFh-Rsrv.js → sas-C1h9GlCk.js} +1 -1
- package/dist/ui/assets/{scala-3UDyJBiS.js → scala-GaqOsYzZ.js} +1 -1
- package/dist/ui/assets/{scheme-KaUTge9W.js → scheme-BgOgLp78.js} +1 -1
- package/dist/ui/assets/{scilab-CLSBZzuh.js → scilab-Dn2TX-KQ.js} +1 -1
- package/dist/ui/assets/{scss-DaEkfHWX.js → scss-CCOm-PWq.js} +1 -1
- package/dist/ui/assets/{sequenceDiagram-DBY2YBRQ-Cv__zR2v.js → sequenceDiagram-DBY2YBRQ-69vZi4Ut.js} +1 -1
- package/dist/ui/assets/{shell-B0d4cZTk.js → shell-C3U6YWrg.js} +1 -1
- package/dist/ui/assets/{sizeCapture-X5ZJPWSS-C4nD-ShQ.js → sizeCapture-X5ZJPWSS-D27KIrz7.js} +1 -1
- package/dist/ui/assets/{smali-CLhfky4R.js → smali-CvsTVdr_.js} +1 -1
- package/dist/ui/assets/{smalltalk-B4aaTMO5.js → smalltalk-kAQkohW_.js} +1 -1
- package/dist/ui/assets/{sml-x4CTxWEZ.js → sml-ve8o4sD9.js} +1 -1
- package/dist/ui/assets/{sqf-G_0vdVVs.js → sqf-BEX8EUHQ.js} +1 -1
- package/dist/ui/assets/{sql-C--WH0Fo.js → sql-BnvvIWzM.js} +1 -1
- package/dist/ui/assets/{sql_more-B4LrzCtd.js → sql_more-BiYWeUQi.js} +1 -1
- package/dist/ui/assets/{stan-CACDFOA0.js → stan-CL8TzbqV.js} +1 -1
- package/dist/ui/assets/{stata-BP9M7sZt.js → stata-9Ttgn33g.js} +1 -1
- package/dist/ui/assets/{stateDiagram-2N3HPSRC-z3-31Cr2.js → stateDiagram-2N3HPSRC-DUQdHUod.js} +1 -1
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-DahROKNQ.js +1 -0
- package/dist/ui/assets/{step21-MAOu4dNb.js → step21-LuiZBROI.js} +1 -1
- package/dist/ui/assets/{stylus-CpuP3pvE.js → stylus-DMxCDGKP.js} +1 -1
- package/dist/ui/assets/{subunit-NWzuqFhT.js → subunit-BqTiWQgg.js} +1 -1
- package/dist/ui/assets/{swift-DuFKNmKv.js → swift-Vgcl7epB.js} +1 -1
- package/dist/ui/assets/{swimlanes-5IMT3BWC-E463-rXd.js → swimlanes-5IMT3BWC-BYUDE9bR.js} +2 -2
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-B5Lf8M0k.js +8 -0
- package/dist/ui/assets/{taggerscript-BDnv2jvg.js → taggerscript-CQct0uSB.js} +1 -1
- package/dist/ui/assets/{tap-aB2cLXdf.js → tap-C3D-iaMR.js} +1 -1
- package/dist/ui/assets/{tcl-7WepIaIa.js → tcl-pAGWRV8F.js} +1 -1
- package/dist/ui/assets/{thrift-BLh6pdjc.js → thrift-BMf3WY_-.js} +1 -1
- package/dist/ui/assets/{timeline-definition-FHXFAJF6-FA_RNhFQ.js → timeline-definition-FHXFAJF6-CUxhbtkg.js} +1 -1
- package/dist/ui/assets/{tp-D1rt5u_j.js → tp-CWlQ8HXb.js} +1 -1
- package/dist/ui/assets/{twig-DgfeYg4W.js → twig-D49EnTd7.js} +1 -1
- package/dist/ui/assets/{typescript-oU560Q8V.js → typescript-O1NhTsg4.js} +1 -1
- package/dist/ui/assets/{vala-DlXsaz2B.js → vala-ChgJAi6T.js} +1 -1
- package/dist/ui/assets/{vbnet-BjpxjeMZ.js → vbnet-DoMTvpOU.js} +1 -1
- package/dist/ui/assets/{vbscript-DfNdtdO3.js → vbscript-COqQ-XLI.js} +1 -1
- package/dist/ui/assets/{vbscript-html-D09WPsgK.js → vbscript-html-C6hlND5y.js} +1 -1
- package/dist/ui/assets/{vennDiagram-L72KCM5P-zaCDWwTs.js → vennDiagram-L72KCM5P-zdR45Fxo.js} +1 -1
- package/dist/ui/assets/{verilog-B9vENtLK.js → verilog-D_vJtQo2.js} +1 -1
- package/dist/ui/assets/{vhdl-CJLTZOu1.js → vhdl-P1OS5AdC.js} +1 -1
- package/dist/ui/assets/{vim-FuPhupu9.js → vim-Dta1cE1i.js} +1 -1
- package/dist/ui/assets/{wardleyDiagram-EHGQE667-BS8ApwmV.js → wardleyDiagram-EHGQE667-DGVhZURT.js} +1 -1
- package/dist/ui/assets/{x86asm-kX_Cp6wB.js → x86asm-0uxjBhIR.js} +1 -1
- package/dist/ui/assets/{xl-MuHNmLUj.js → xl-A4qrusE8.js} +1 -1
- package/dist/ui/assets/{xml-Mbn2z12n.js → xml-BWIS8Du3.js} +1 -1
- package/dist/ui/assets/{xquery-Dy4lt-m-.js → xquery-DteVIK7u.js} +1 -1
- package/dist/ui/assets/{xychartDiagram-FW5EYKEG-DoNZtZus.js → xychartDiagram-FW5EYKEG-Bi0bMVkV.js} +1 -1
- package/dist/ui/assets/{yaml-CxxAisfE.js → yaml-Sfd5lnBk.js} +1 -1
- package/dist/ui/assets/{zephir-WWG8qyld.js → zephir-DN0VT2-6.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/utils/__tests__/knowledge-store.test.d.ts +1 -0
- package/dist/utils/__tests__/knowledge-store.test.js +53 -0
- package/dist/utils/knowledge-store.d.ts +29 -0
- package/dist/utils/knowledge-store.js +144 -0
- package/dist/utils/pi-browser-tools.d.ts +10 -0
- package/dist/utils/pi-browser-tools.js +246 -0
- package/dist/utils/pi-runtime.d.ts +8 -0
- package/dist/utils/pi-runtime.js +236 -0
- package/dist/utils/pi-sandbox-ops.d.ts +40 -0
- package/dist/utils/pi-sandbox-ops.js +205 -0
- package/package.json +4 -2
- package/dist/docs/assets/chunks/channel.Cc6zpfFP.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-OUVF2IWQ.DV5B4KLJ.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-EOCWNBFH.DV5B4KLJ.js +0 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-6OUMAXLB.B9v-Vq5L.js +0 -1
- package/dist/docs/assets/chunks/swimlanesDiagram-G3AALYLV.Kb9LnCTH.js +0 -8
- package/dist/ui/assets/channel-_rFUXR2i.js +0 -1
- package/dist/ui/assets/classDiagram-OUVF2IWQ-DqgbMzM1.js +0 -1
- package/dist/ui/assets/classDiagram-v2-EOCWNBFH-DqgbMzM1.js +0 -1
- package/dist/ui/assets/index-CWFn1h-J.css +0 -10
- package/dist/ui/assets/stateDiagram-v2-6OUMAXLB-BKIXFHzO.js +0 -1
- package/dist/ui/assets/swimlanesDiagram-G3AALYLV-CkQvBOYs.js +0 -8
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { dataDir } from './paths.js';
|
|
4
|
+
const docsDir = path.join(dataDir, 'docs');
|
|
5
|
+
const TOPIC_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
6
|
+
const CHUNK_RE = /^chunk-\d{3}$/;
|
|
7
|
+
function assertTopic(topic) {
|
|
8
|
+
if (!TOPIC_RE.test(topic)) {
|
|
9
|
+
throw new Error(`invalid topic slug: ${topic}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function assertChunkId(chunkId) {
|
|
13
|
+
if (!CHUNK_RE.test(chunkId)) {
|
|
14
|
+
throw new Error(`invalid chunk id: ${chunkId} (expect chunk-NNN)`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** 解析 "- <slug>: <摘要>" 行(自然 markdown 列表) */
|
|
18
|
+
function parseRootIndex(text) {
|
|
19
|
+
const out = [];
|
|
20
|
+
const re = /^- ([a-z0-9][a-z0-9-]*):\s*(.+?)\s*$/m;
|
|
21
|
+
for (const line of text.split('\n')) {
|
|
22
|
+
const m = line.match(re);
|
|
23
|
+
if (m)
|
|
24
|
+
out.push({ slug: m[1], title: m[1], summary: m[2].trim() });
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/** 解析主题 INDEX.md 的 "## 元数据" 区块:`- 名称: xxx` / `- 标签: a, b, c` */
|
|
29
|
+
function parseTopicMeta(text) {
|
|
30
|
+
let title = '';
|
|
31
|
+
let tags = [];
|
|
32
|
+
const nameRe = /^- 名称:\s*(.+?)\s*$/m;
|
|
33
|
+
const tagsRe = /^- 标签:\s*(.+?)\s*$/m;
|
|
34
|
+
const nameM = text.match(nameRe);
|
|
35
|
+
if (nameM)
|
|
36
|
+
title = nameM[1].trim();
|
|
37
|
+
const tagsM = text.match(tagsRe);
|
|
38
|
+
if (tagsM) {
|
|
39
|
+
tags = tagsM[1].split(',').map(s => s.trim()).filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
return { title, tags };
|
|
42
|
+
}
|
|
43
|
+
/** 解析片段清单行 "- chunk-NNN: <标题> — <描述>" 或 "- chunk-NNN: <描述>" */
|
|
44
|
+
function parseChunkList(text) {
|
|
45
|
+
const out = [];
|
|
46
|
+
const re = /^- (chunk-\d{3}):\s*(.+?)\s*$/m;
|
|
47
|
+
for (const line of text.split('\n')) {
|
|
48
|
+
const m = line.match(re);
|
|
49
|
+
if (!m)
|
|
50
|
+
continue;
|
|
51
|
+
const rest = m[2].trim();
|
|
52
|
+
const dashIdx = rest.indexOf(' — ');
|
|
53
|
+
let title;
|
|
54
|
+
let summary;
|
|
55
|
+
if (dashIdx >= 0) {
|
|
56
|
+
title = rest.slice(0, dashIdx).trim();
|
|
57
|
+
summary = rest.slice(dashIdx + 3).trim();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
title = rest;
|
|
61
|
+
summary = rest;
|
|
62
|
+
}
|
|
63
|
+
out.push({ id: m[1], title, summary });
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/** 从 chunk 正文首行 `# xxx` 提取 title(用于 searchChunks) */
|
|
68
|
+
function parseChunkTitle(text) {
|
|
69
|
+
const m = text.match(/^#\s+(.+?)\s*$/m);
|
|
70
|
+
return m ? m[1].trim() : '';
|
|
71
|
+
}
|
|
72
|
+
export function createKnowledgeStore(root) {
|
|
73
|
+
async function listTopics() {
|
|
74
|
+
const indexPath = path.join(root, 'INDEX.md');
|
|
75
|
+
try {
|
|
76
|
+
const text = await fs.readFile(indexPath, 'utf8');
|
|
77
|
+
return parseRootIndex(text);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function getTopic(topic) {
|
|
84
|
+
assertTopic(topic);
|
|
85
|
+
const indexPath = path.join(root, topic, 'INDEX.md');
|
|
86
|
+
const text = await fs.readFile(indexPath, 'utf8');
|
|
87
|
+
const meta = parseTopicMeta(text);
|
|
88
|
+
return {
|
|
89
|
+
title: meta.title || topic,
|
|
90
|
+
tags: meta.tags,
|
|
91
|
+
sources: [],
|
|
92
|
+
chunks: parseChunkList(text),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
async function searchChunks(query) {
|
|
96
|
+
if (!query.trim())
|
|
97
|
+
return [];
|
|
98
|
+
const hits = [];
|
|
99
|
+
const q = query.toLowerCase();
|
|
100
|
+
let entries;
|
|
101
|
+
try {
|
|
102
|
+
entries = await fs.readdir(root);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
for (const topic of entries) {
|
|
108
|
+
if (!TOPIC_RE.test(topic))
|
|
109
|
+
continue;
|
|
110
|
+
const chunksDir = path.join(root, topic, 'chunks');
|
|
111
|
+
let files;
|
|
112
|
+
try {
|
|
113
|
+
files = await fs.readdir(chunksDir);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
for (const file of files) {
|
|
119
|
+
if (!CHUNK_RE.test(file.replace(/\.md$/, '')))
|
|
120
|
+
continue;
|
|
121
|
+
const text = await fs.readFile(path.join(chunksDir, file), 'utf8');
|
|
122
|
+
if (text.toLowerCase().includes(q)) {
|
|
123
|
+
hits.push({ topic, chunkId: file.replace(/\.md$/, ''), title: parseChunkTitle(text) });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return hits;
|
|
128
|
+
}
|
|
129
|
+
async function readChunk(topic, chunkId) {
|
|
130
|
+
assertTopic(topic);
|
|
131
|
+
assertChunkId(chunkId);
|
|
132
|
+
const filePath = path.join(root, topic, 'chunks', `${chunkId}.md`);
|
|
133
|
+
// 二次校验:解析后路径必须在 root/<topic>/chunks/ 内
|
|
134
|
+
const resolved = path.resolve(filePath);
|
|
135
|
+
const expectedDir = path.resolve(root, topic, 'chunks');
|
|
136
|
+
if (!resolved.startsWith(expectedDir + path.sep)) {
|
|
137
|
+
throw new Error('access denied: chunk path escapes chunks dir');
|
|
138
|
+
}
|
|
139
|
+
return fs.readFile(resolved, 'utf8');
|
|
140
|
+
}
|
|
141
|
+
return { listTopics, getTopic, searchChunks, readChunk };
|
|
142
|
+
}
|
|
143
|
+
// 默认单例:绑生产 docsDir
|
|
144
|
+
export const knowledgeStore = createKnowledgeStore(docsDir);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ToolDefinition } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
/**
|
|
3
|
+
* 统一封装 ego-browser CLI:spawn 子进程 + 写入 Node 脚本 stdin,返回 cliLog 文本。
|
|
4
|
+
* 每次调用独立进程,靠 useOrCreateTaskSpace 在同一 task space 复用 tab。
|
|
5
|
+
*/
|
|
6
|
+
export declare function runEgoBrowser(scriptBody: string, opts?: {
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
}): Promise<string>;
|
|
10
|
+
export declare const browserTools: ToolDefinition[];
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { Type } from 'typebox';
|
|
3
|
+
/**
|
|
4
|
+
* 统一封装 ego-browser CLI:spawn 子进程 + 写入 Node 脚本 stdin,返回 cliLog 文本。
|
|
5
|
+
* 每次调用独立进程,靠 useOrCreateTaskSpace 在同一 task space 复用 tab。
|
|
6
|
+
*/
|
|
7
|
+
export function runEgoBrowser(scriptBody, opts = {}) {
|
|
8
|
+
const timeoutMs = opts.timeoutMs ?? 30000;
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
// 头部自动注入 task space 复用调用
|
|
11
|
+
const script = `const task = await useOrCreateTaskSpace('knowledge-learn')\n${scriptBody}`;
|
|
12
|
+
const child = spawn('ego-browser', ['nodejs'], {
|
|
13
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
14
|
+
});
|
|
15
|
+
let stdout = '';
|
|
16
|
+
let stderr = '';
|
|
17
|
+
let settled = false;
|
|
18
|
+
const finish = (err, out) => {
|
|
19
|
+
if (settled)
|
|
20
|
+
return;
|
|
21
|
+
settled = true;
|
|
22
|
+
cleanup();
|
|
23
|
+
if (err) {
|
|
24
|
+
// 把 stderr 附加到错误里,帮助排查
|
|
25
|
+
const detail = stderr.trim() ? `\n--- stderr ---\n${stderr.trim()}` : '';
|
|
26
|
+
reject(new Error(`${err.message}${detail}`));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
resolve(out ?? stdout);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const timer = setTimeout(() => {
|
|
33
|
+
finish(new Error(`ego-browser timed out after ${timeoutMs}ms`));
|
|
34
|
+
child.kill('SIGKILL');
|
|
35
|
+
}, timeoutMs);
|
|
36
|
+
const onAbort = () => {
|
|
37
|
+
finish(new Error('ego-browser aborted'));
|
|
38
|
+
child.kill('SIGKILL');
|
|
39
|
+
};
|
|
40
|
+
opts.signal?.addEventListener('abort', onAbort, { once: true });
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
opts.signal?.removeEventListener('abort', onAbort);
|
|
44
|
+
};
|
|
45
|
+
child.stdout.on('data', (chunk) => {
|
|
46
|
+
stdout += chunk.toString('utf-8');
|
|
47
|
+
});
|
|
48
|
+
child.stderr.on('data', (chunk) => {
|
|
49
|
+
stderr += chunk.toString('utf-8');
|
|
50
|
+
});
|
|
51
|
+
child.on('error', (err) => {
|
|
52
|
+
if (err.code === 'ENOENT') {
|
|
53
|
+
finish(new Error('ego-browser CLI not found. Please install ego-browser first.'));
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
finish(err instanceof Error ? err : new Error(String(err)));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
child.on('close', (code) => {
|
|
60
|
+
if (settled)
|
|
61
|
+
return;
|
|
62
|
+
if (code === 0) {
|
|
63
|
+
finish(null, stdout);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// 非 0 退出:stderr 可能含错误;stdout 仍作为错误消息的一部分返回
|
|
67
|
+
const detail = stdout.trim() ? `\n--- stdout ---\n${stdout.trim()}` : '';
|
|
68
|
+
finish(new Error(`ego-browser exited with code ${code}${detail}`));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
child.stdin.end(script, 'utf-8');
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// ---------- 工具实现辅助 ----------
|
|
75
|
+
/** 把字符串参数安全注入脚本:JSON.stringify 自动处理引号 / 反斜杠 / 换行 */
|
|
76
|
+
const jsLit = (v) => JSON.stringify(v);
|
|
77
|
+
/** 构造 pi AgentToolResult(content + details 字段) */
|
|
78
|
+
const ok = (text) => ({
|
|
79
|
+
content: [{ type: 'text', text }],
|
|
80
|
+
details: undefined,
|
|
81
|
+
});
|
|
82
|
+
const navigateSchema = Type.Object({
|
|
83
|
+
url: Type.String({ description: '目标 URL,必须是 http(s) 完整地址' }),
|
|
84
|
+
wait: Type.Optional(Type.Boolean({ description: '是否等待页面加载完成,默认 true' })),
|
|
85
|
+
});
|
|
86
|
+
const snapshotSchema = Type.Object({
|
|
87
|
+
scope: Type.Optional(Type.String({
|
|
88
|
+
description: "snapshotText 的 scope:'full_page'(默认)或 'only_within_viewport'",
|
|
89
|
+
})),
|
|
90
|
+
});
|
|
91
|
+
const screenshotSchema = Type.Object({});
|
|
92
|
+
const clickSchema = Type.Object({
|
|
93
|
+
target: Type.String({
|
|
94
|
+
description: "点击目标:@N / CSS / 'xpath=...' / 'loc=...',或 [x,y] 视口坐标数组",
|
|
95
|
+
}),
|
|
96
|
+
label: Type.Optional(Type.String({ description: '可选 3-6 字动作描述,用于高亮' })),
|
|
97
|
+
});
|
|
98
|
+
const typeSchema = Type.Object({
|
|
99
|
+
target: Type.String({ description: '输入框定位:@N / CSS / xpath=... / loc=...' }),
|
|
100
|
+
text: Type.String({ description: '要填入的文本内容' }),
|
|
101
|
+
submit: Type.Optional(Type.Boolean({ description: 'true 则填完后按 Enter,默认 false' })),
|
|
102
|
+
});
|
|
103
|
+
const scrollSchema = Type.Object({
|
|
104
|
+
direction: Type.String({
|
|
105
|
+
enum: ['down', 'up', 'bottom'],
|
|
106
|
+
description: "滚动方向:'down' / 'up' / 'bottom'(滚到底并触发懒加载)",
|
|
107
|
+
}),
|
|
108
|
+
amount: Type.Optional(Type.Number({ description: 'down/up 时的滚动像素量,默认 900' })),
|
|
109
|
+
});
|
|
110
|
+
const evaluateSchema = Type.Object({
|
|
111
|
+
expression: Type.String({
|
|
112
|
+
description: '页面内 JS 字符串。复杂逻辑用 IIFE:(() => { ... })()',
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
const fetchSchema = Type.Object({
|
|
116
|
+
url: Type.String({ description: '要抓取的 URL' }),
|
|
117
|
+
});
|
|
118
|
+
const pressKeySchema = Type.Object({
|
|
119
|
+
key: Type.String({ description: "CDP 键名,如 'Enter' / 'Escape' / 'ArrowDown'" }),
|
|
120
|
+
});
|
|
121
|
+
export const browserTools = [
|
|
122
|
+
{
|
|
123
|
+
name: 'browser_navigate',
|
|
124
|
+
label: 'browser_navigate',
|
|
125
|
+
description: '在 ego-browser 的 knowledge-learn task space 中打开或复用 tab 到给定 URL。wait=true(默认)会等页面加载,timeout 20s。',
|
|
126
|
+
parameters: navigateSchema,
|
|
127
|
+
async execute(_id, params, signal) {
|
|
128
|
+
const url = jsLit(params.url);
|
|
129
|
+
const wait = params.wait ?? true;
|
|
130
|
+
const body = `
|
|
131
|
+
await openOrReuseTab(${url}, { wait: ${wait}, timeout: 20 })
|
|
132
|
+
const info = await pageInfo()
|
|
133
|
+
cliLog(JSON.stringify(info))
|
|
134
|
+
`;
|
|
135
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'browser_snapshot',
|
|
140
|
+
label: 'browser_snapshot',
|
|
141
|
+
description: '获取当前页面的可访问性语义树(含 @N / loc= 引用),是后续 click/fillInput 定位元素的依据。默认 scope=full_page 覆盖整页。',
|
|
142
|
+
parameters: snapshotSchema,
|
|
143
|
+
async execute(_id, params, signal) {
|
|
144
|
+
const scope = params.scope ?? 'full_page';
|
|
145
|
+
const body = `cliLog(await snapshotText({ scope: ${jsLit(scope)} }))`;
|
|
146
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'browser_screenshot',
|
|
151
|
+
label: 'browser_screenshot',
|
|
152
|
+
description: '对当前页面视口截图。返回 ego 输出的图片说明 / 路径文本。',
|
|
153
|
+
parameters: screenshotSchema,
|
|
154
|
+
async execute(_id, _params, signal) {
|
|
155
|
+
return ok(await runEgoBrowser('cliLog(await captureScreenshot())', { signal }));
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: 'browser_click',
|
|
160
|
+
label: 'browser_click',
|
|
161
|
+
description: '点击元素。target 支持 @N(来自最近一次 snapshotText)、CSS 选择器、xpath=...、loc=...(推荐长期稳定引用)。label 是 3-6 字动作描述,会触发高亮动画。',
|
|
162
|
+
parameters: clickSchema,
|
|
163
|
+
async execute(_id, params, signal) {
|
|
164
|
+
const target = jsLit(params.target);
|
|
165
|
+
const label = params.label ? `, { label: ${jsLit(params.label)} }` : '';
|
|
166
|
+
const body = `await click(${target}${label})\ncliLog('clicked: ${params.target}')`;
|
|
167
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'browser_type',
|
|
172
|
+
label: 'browser_type',
|
|
173
|
+
description: '向输入框填充文本。target 同 browser_click(@N / CSS / xpath / loc)。submit=true 时填完后按 Enter(常用于搜索框)。',
|
|
174
|
+
parameters: typeSchema,
|
|
175
|
+
async execute(_id, params, signal) {
|
|
176
|
+
const target = jsLit(params.target);
|
|
177
|
+
const text = jsLit(params.text);
|
|
178
|
+
const submitBlock = params.submit ? `\nawait pressKey('Enter')` : '';
|
|
179
|
+
const body = `
|
|
180
|
+
await fillInput(${target}, ${text})${submitBlock}
|
|
181
|
+
cliLog('filled: ${params.target}')
|
|
182
|
+
`;
|
|
183
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'browser_scroll',
|
|
188
|
+
label: 'browser_scroll',
|
|
189
|
+
description: '滚动页面。direction=down/up 按 amount 像素滚动;direction=bottom 自动滚到底并尝试触发懒加载(最多 20 步)。',
|
|
190
|
+
parameters: scrollSchema,
|
|
191
|
+
async execute(_id, params, signal) {
|
|
192
|
+
let body;
|
|
193
|
+
if (params.direction === 'bottom') {
|
|
194
|
+
body = `
|
|
195
|
+
await scrollToBottomUntil(
|
|
196
|
+
async () => false,
|
|
197
|
+
{ step: 900, wait: 1, maxSteps: 20 }
|
|
198
|
+
)
|
|
199
|
+
cliLog('scrolled to bottom')
|
|
200
|
+
`;
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
const amount = params.amount ?? 900;
|
|
204
|
+
const signed = params.direction === 'down' ? amount : -amount;
|
|
205
|
+
body = `
|
|
206
|
+
await scrollBy(${signed})
|
|
207
|
+
cliLog('scrolled ${params.direction} ${amount}px')
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: 'browser_evaluate',
|
|
215
|
+
label: 'browser_evaluate',
|
|
216
|
+
description: '在页面上下文执行 JS 字符串(等价于 Runtime.evaluate),返回序列化结果。多步逻辑请包成 IIFE:(() => { ... })()。不要把它当 Puppeteer page.evaluate(fn, ...args) 用。',
|
|
217
|
+
parameters: evaluateSchema,
|
|
218
|
+
async execute(_id, params, signal) {
|
|
219
|
+
const expr = jsLit(params.expression);
|
|
220
|
+
const body = `cliLog(JSON.stringify(await js(${expr})))`;
|
|
221
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'browser_fetch',
|
|
226
|
+
label: 'browser_fetch',
|
|
227
|
+
description: '在当前浏览器页面上下文发起 fetch(复用登录态 / Cookie),返回响应正文文本。适合抓取需要鉴权的页面 JSON 或 HTML。',
|
|
228
|
+
parameters: fetchSchema,
|
|
229
|
+
async execute(_id, params, signal) {
|
|
230
|
+
const url = jsLit(params.url);
|
|
231
|
+
const body = `cliLog(await browserFetch(${url}))`;
|
|
232
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: 'browser_press_key',
|
|
237
|
+
label: 'browser_press_key',
|
|
238
|
+
description: '在当前焦点元素按下键盘按键。key 用 CDP 键名,如 "Enter" / "Escape" / "Tab" / "ArrowDown" / "Control+A"。',
|
|
239
|
+
parameters: pressKeySchema,
|
|
240
|
+
async execute(_id, params, signal) {
|
|
241
|
+
const key = jsLit(params.key);
|
|
242
|
+
const body = `await pressKey(${key})\ncliLog('pressed: ${params.key}')`;
|
|
243
|
+
return ok(await runEgoBrowser(body, { signal }));
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type AgentSession } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
export type PiSessionMode = 'chat' | 'learn';
|
|
3
|
+
export interface CreatePiSessionOptions {
|
|
4
|
+
cwd?: string;
|
|
5
|
+
port: number;
|
|
6
|
+
mode: PiSessionMode;
|
|
7
|
+
}
|
|
8
|
+
export declare function createPiSession(options: CreatePiSessionOptions): Promise<AgentSession>;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// pi SDK 单例工厂:把 pi coding-agent 接到本地 ccm proxy 上。
|
|
2
|
+
// - ModelRuntime 懒加载,全局单例
|
|
3
|
+
// - registerProvider 注册一个 "ccm" provider,走 anthropic-messages 协议到本地 proxy
|
|
4
|
+
// - createPiSession() 返回一个新 AgentSession,cwd 钉死在 docsDir
|
|
5
|
+
// - 按 chat / learn 两种模式挂载不同工具集
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
import { Type } from 'typebox';
|
|
10
|
+
import { createAgentSession, DefaultResourceLoader, ModelRuntime, createWriteToolDefinition, createEditToolDefinition, } from '@earendil-works/pi-coding-agent';
|
|
11
|
+
import { dataDir } from './paths.js';
|
|
12
|
+
import { sandboxWriteOps, sandboxEditOps, } from './pi-sandbox-ops.js';
|
|
13
|
+
import { browserTools } from './pi-browser-tools.js';
|
|
14
|
+
import { knowledgeStore } from './knowledge-store.js';
|
|
15
|
+
// 知识文档目录:所有文件工具的 cwd 和沙箱白名单根
|
|
16
|
+
const docsDir = path.join(dataDir, 'docs');
|
|
17
|
+
// pi agent 目录(auth / models / system.md)
|
|
18
|
+
const agentDir = path.join(os.homedir(), '.cc-monitoring', 'pi');
|
|
19
|
+
let runtimePromise = null;
|
|
20
|
+
let runtimePort = 0;
|
|
21
|
+
async function getRuntime(port) {
|
|
22
|
+
if (!runtimePromise || runtimePort !== port) {
|
|
23
|
+
runtimePort = port;
|
|
24
|
+
runtimePromise = (async () => {
|
|
25
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
26
|
+
const runtime = await ModelRuntime.create({
|
|
27
|
+
authPath: path.join(agentDir, 'auth.json'),
|
|
28
|
+
modelsPath: path.join(agentDir, 'models.json'),
|
|
29
|
+
refreshOnCreate: false,
|
|
30
|
+
allowModelNetwork: false,
|
|
31
|
+
});
|
|
32
|
+
const baseUrl = `http://localhost:${port}`;
|
|
33
|
+
runtime.registerProvider('ccm', {
|
|
34
|
+
name: 'ccm',
|
|
35
|
+
baseUrl,
|
|
36
|
+
apiKey: 'unused',
|
|
37
|
+
api: 'anthropic-messages',
|
|
38
|
+
models: [
|
|
39
|
+
{
|
|
40
|
+
id: 'placeholder',
|
|
41
|
+
name: 'ccm placeholder',
|
|
42
|
+
api: 'anthropic-messages',
|
|
43
|
+
baseUrl,
|
|
44
|
+
input: ['text'],
|
|
45
|
+
cost: {
|
|
46
|
+
input: 0,
|
|
47
|
+
output: 0,
|
|
48
|
+
cacheRead: 0,
|
|
49
|
+
cacheWrite: 0,
|
|
50
|
+
},
|
|
51
|
+
reasoning: true,
|
|
52
|
+
contextWindow: 200000,
|
|
53
|
+
maxTokens: 8192,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
return runtime;
|
|
58
|
+
})();
|
|
59
|
+
}
|
|
60
|
+
return runtimePromise;
|
|
61
|
+
}
|
|
62
|
+
// 默认 system prompt 兜底(system.md 不存在时使用)
|
|
63
|
+
const DEFAULT_SYSTEM_PROMPT = `You are a knowledge management AI operating inside a sandbox.
|
|
64
|
+
Your knowledge directory (~/.cc-monitoring/docs) stores structured knowledge.
|
|
65
|
+
|
|
66
|
+
STRUCTURE:
|
|
67
|
+
- Each topic is a subfolder: docs/<topic-slug>/
|
|
68
|
+
- Each topic has INDEX.md (metadata + chunk list, NO body)
|
|
69
|
+
- Bodies live in docs/<topic-slug>/chunks/chunk-NNN.md (300-500 words each)
|
|
70
|
+
- Root INDEX.md lists all topics with one-line summaries
|
|
71
|
+
|
|
72
|
+
CHAT MODE (answer questions):
|
|
73
|
+
1. Call list_topics to see available topics
|
|
74
|
+
2. If topic is unclear, call search_chunks(query) to find relevant chunks across topics
|
|
75
|
+
3. Call get_topic(topic) to see that topic's chunk list
|
|
76
|
+
4. Call read_chunk(topic, chunk_id) for relevant chunks — only read chunks you need
|
|
77
|
+
5. Prefer answering from knowledge base chunks when relevant content exists; cite which chunks you used
|
|
78
|
+
6. If no relevant chunk exists, answer from your general knowledge; if you truly don't know, say so
|
|
79
|
+
|
|
80
|
+
LEARN MODE (distill web pages into knowledge):
|
|
81
|
+
1. Call list_topics first to check for existing similar topics — reuse, don't duplicate
|
|
82
|
+
2. Use browser tools to read web pages
|
|
83
|
+
3. Distill into 300-500 word chunks, one point per chunk
|
|
84
|
+
4. Write chunks to docs/<topic-slug>/chunks/chunk-NNN.md (include source URL + quote)
|
|
85
|
+
5. Update docs/<topic-slug>/INDEX.md chunk list + metadata
|
|
86
|
+
6. Update root INDEX.md topic line if new topic
|
|
87
|
+
`;
|
|
88
|
+
/** 从 ~/.cc-monitoring/pi/system.md 读取自定义 system prompt,不存在则用兜底文本 */
|
|
89
|
+
function loadSystemPrompt() {
|
|
90
|
+
const mdPath = path.join(agentDir, 'system.md');
|
|
91
|
+
try {
|
|
92
|
+
return fs.readFileSync(mdPath, 'utf8');
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return DEFAULT_SYSTEM_PROMPT;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** 构造知识检索领域工具(chat / learn 共用) */
|
|
99
|
+
function buildKnowledgeTools() {
|
|
100
|
+
const ok = (text) => ({ content: [{ type: 'text', text }], details: undefined });
|
|
101
|
+
const err = (e) => ({ content: [{ type: 'text', text: `error: ${e instanceof Error ? e.message : String(e)}` }], details: undefined });
|
|
102
|
+
return [
|
|
103
|
+
{
|
|
104
|
+
name: 'list_topics',
|
|
105
|
+
label: 'list_topics',
|
|
106
|
+
description: '列出所有知识主题及一句话摘要。检索知识时第一步调用,发现有哪些主题可用。',
|
|
107
|
+
parameters: Type.Object({}),
|
|
108
|
+
async execute() {
|
|
109
|
+
try {
|
|
110
|
+
return ok(JSON.stringify(await knowledgeStore.listTopics(), null, 2));
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
return err(e);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'get_topic',
|
|
119
|
+
label: 'get_topic',
|
|
120
|
+
description: '获取某主题的元数据与片段清单(描述级,不含正文)。读正文前先调用,看有哪些 chunk。',
|
|
121
|
+
parameters: Type.Object({ topic: Type.String({ description: '主题 slug,如 react-hooks' }) }),
|
|
122
|
+
async execute(_id, params) {
|
|
123
|
+
try {
|
|
124
|
+
return ok(JSON.stringify(await knowledgeStore.getTopic(params.topic), null, 2));
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
return err(e);
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'search_chunks',
|
|
133
|
+
label: 'search_chunks',
|
|
134
|
+
description: '跨主题关键词检索片段,返回命中清单(不含正文)。主题不明时用。',
|
|
135
|
+
parameters: Type.Object({ query: Type.String({ description: '搜索关键词' }) }),
|
|
136
|
+
async execute(_id, params) {
|
|
137
|
+
try {
|
|
138
|
+
return ok(JSON.stringify(await knowledgeStore.searchChunks(params.query), null, 2));
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
return err(e);
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'read_chunk',
|
|
147
|
+
label: 'read_chunk',
|
|
148
|
+
description: '读取单个知识片段正文。一次只读一片。读前先 get_topic 发现 chunk id。',
|
|
149
|
+
parameters: Type.Object({
|
|
150
|
+
topic: Type.String({ description: '主题 slug' }),
|
|
151
|
+
chunk_id: Type.String({ description: 'chunk id,如 chunk-001' }),
|
|
152
|
+
}),
|
|
153
|
+
async execute(_id, params) {
|
|
154
|
+
try {
|
|
155
|
+
return ok(await knowledgeStore.readChunk(params.topic, params.chunk_id));
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
return err(e);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
/** 按模式构建工具集(ToolDefinition 数组,用于 customTools) */
|
|
165
|
+
function buildModeTools(mode) {
|
|
166
|
+
const knowledgeTools = buildKnowledgeTools();
|
|
167
|
+
if (mode === 'chat') {
|
|
168
|
+
// chat:只用领域工具,移除通用 read/grep/find/ls(防全量灌入)
|
|
169
|
+
return knowledgeTools;
|
|
170
|
+
}
|
|
171
|
+
// learn:领域工具(查重/读现有)+ write/edit + browser
|
|
172
|
+
// 注意:createXxxToolDefinition 返回带具体 schema 的 ToolDefinition<TParams, ...>,
|
|
173
|
+
// 与无泛型的 ToolDefinition 在 renderCall 上不协变,需要 as ToolDefinition 抹平。
|
|
174
|
+
return [
|
|
175
|
+
...knowledgeTools,
|
|
176
|
+
createWriteToolDefinition(docsDir, { operations: sandboxWriteOps }),
|
|
177
|
+
createEditToolDefinition(docsDir, { operations: sandboxEditOps }),
|
|
178
|
+
...browserTools,
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
/** 按模式构建工具白名单(tools 字段,全小写) */
|
|
182
|
+
function buildToolAllowlist(mode) {
|
|
183
|
+
const base = ['list_topics', 'get_topic', 'search_chunks', 'read_chunk'];
|
|
184
|
+
if (mode === 'chat') {
|
|
185
|
+
return base;
|
|
186
|
+
}
|
|
187
|
+
return [...base, 'write', 'edit', ...browserTools.map((t) => t.name)];
|
|
188
|
+
}
|
|
189
|
+
export async function createPiSession(options) {
|
|
190
|
+
const runtime = await getRuntime(options.port);
|
|
191
|
+
const model = runtime.getModel('ccm', 'placeholder');
|
|
192
|
+
if (!model) {
|
|
193
|
+
throw new Error('pi runtime: ccm/placeholder model not registered');
|
|
194
|
+
}
|
|
195
|
+
// cwd 钉死 docsDir,忽略传入的 process.cwd()
|
|
196
|
+
const cwd = options.cwd ?? docsDir;
|
|
197
|
+
// 闭包捕获:pi 的 sessionId 在 createAgentSession 返回后才知道,
|
|
198
|
+
// 但 before_provider_headers handler 是每次上游请求时才触发,
|
|
199
|
+
// 所以先放一个可变变量,返回 session 后再填值。
|
|
200
|
+
let currentSessionId = '';
|
|
201
|
+
const systemPrompt = loadSystemPrompt();
|
|
202
|
+
const modeTools = buildModeTools(options.mode);
|
|
203
|
+
const toolAllowlist = buildToolAllowlist(options.mode);
|
|
204
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
205
|
+
cwd,
|
|
206
|
+
agentDir,
|
|
207
|
+
extensionFactories: [
|
|
208
|
+
(pi) => {
|
|
209
|
+
// 注入 x-claude-code-session-id header(保留原有逻辑)
|
|
210
|
+
pi.on('before_provider_headers', (ev) => {
|
|
211
|
+
if (currentSessionId) {
|
|
212
|
+
ev.headers['x-claude-code-session-id'] = currentSessionId;
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
// 通过 before_agent_start 事件注入 system prompt
|
|
216
|
+
pi.on('before_agent_start', () => {
|
|
217
|
+
return { systemPrompt };
|
|
218
|
+
});
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
});
|
|
222
|
+
await resourceLoader.reload();
|
|
223
|
+
const { session } = await createAgentSession({
|
|
224
|
+
cwd,
|
|
225
|
+
agentDir,
|
|
226
|
+
modelRuntime: runtime,
|
|
227
|
+
model,
|
|
228
|
+
noTools: 'builtin', // 禁用 pi 默认 read/bash/edit/write,保留 customTools
|
|
229
|
+
customTools: modeTools,
|
|
230
|
+
tools: toolAllowlist, // 全小写工具名白名单
|
|
231
|
+
resourceLoader,
|
|
232
|
+
});
|
|
233
|
+
// 在 session.prompt() 之前填入真实 sessionId
|
|
234
|
+
currentSessionId = session.sessionId;
|
|
235
|
+
return session;
|
|
236
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 校验传入路径必须在 docsDir 内,并返回归一化后的绝对路径。
|
|
3
|
+
* 越界则抛错,阻断 fs 调用。
|
|
4
|
+
*/
|
|
5
|
+
export declare function assertInside(absPath: string): string;
|
|
6
|
+
declare function access(absolutePath: string): Promise<void>;
|
|
7
|
+
export declare const sandboxReadOps: {
|
|
8
|
+
readFile(absolutePath: string): Promise<Buffer>;
|
|
9
|
+
access: typeof access;
|
|
10
|
+
detectImageMimeType: () => Promise<string | null | undefined>;
|
|
11
|
+
};
|
|
12
|
+
export declare const sandboxWriteOps: {
|
|
13
|
+
writeFile(absolutePath: string, content: string): Promise<void>;
|
|
14
|
+
mkdir(dir: string): Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
export declare const sandboxEditOps: {
|
|
17
|
+
readFile(absolutePath: string): Promise<Buffer>;
|
|
18
|
+
writeFile(absolutePath: string, content: string): Promise<void>;
|
|
19
|
+
access: typeof access;
|
|
20
|
+
};
|
|
21
|
+
export declare const sandboxGrepOps: {
|
|
22
|
+
isDirectory(absolutePath: string): Promise<boolean>;
|
|
23
|
+
readFile(absolutePath: string): Promise<string>;
|
|
24
|
+
};
|
|
25
|
+
export declare const sandboxFindOps: {
|
|
26
|
+
exists(absolutePath: string): Promise<boolean>;
|
|
27
|
+
glob(pattern: string, cwd: string, options: {
|
|
28
|
+
ignore: string[];
|
|
29
|
+
limit: number;
|
|
30
|
+
}): Promise<string[]>;
|
|
31
|
+
};
|
|
32
|
+
export declare function globMatch(relPosixPath: string, pattern: string): boolean;
|
|
33
|
+
export declare const sandboxLsOps: {
|
|
34
|
+
exists(absolutePath: string): Promise<boolean>;
|
|
35
|
+
stat(absolutePath: string): Promise<{
|
|
36
|
+
isDirectory: () => boolean;
|
|
37
|
+
}>;
|
|
38
|
+
readdir(absolutePath: string): Promise<string[]>;
|
|
39
|
+
};
|
|
40
|
+
export {};
|