onbuzz 4.8.3 → 4.9.0
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/bin/cli.js +27 -1
- package/bin/composio-cli.js +431 -0
- package/package.json +1 -1
- package/scripts/build-onboarding-doc.cjs +805 -0
- package/scripts/composio-bench/README.md +151 -0
- package/scripts/memory-bench/bench.mjs +576 -0
- package/scripts/memory-bench/live-after-2026-05-21T16-20-52-767Z.json +150 -0
- package/scripts/memory-bench/live-after-2026-05-21T16-37-17-147Z.json +795 -0
- package/scripts/memory-bench/live-after-final-2026-05-21T17-16-02-947Z.json +766 -0
- package/scripts/memory-bench/live-after-v2-2026-05-21T16-52-26-833Z.json +890 -0
- package/scripts/memory-bench/live-after-v3-2026-05-21T17-05-40-622Z.json +955 -0
- package/scripts/memory-bench/live-probe-v2.mjs +412 -0
- package/scripts/memory-bench/live-probe.mjs +387 -0
- package/scripts/memory-bench/live-smoke-2026-05-21T16-22-35-945Z.json +36 -0
- package/scripts/memory-bench/live-smoke2-2026-05-21T16-24-14-095Z.json +36 -0
- package/scripts/memory-bench/live-smoke3-2026-05-21T16-26-54-093Z.json +123 -0
- package/scripts/memory-bench/live-v2-baseline-2026-05-23T22-43-20-757Z.json +628 -0
- package/scripts/memory-bench/live-v2-directive-2026-05-23T21-32-41-369Z.json +628 -0
- package/scripts/memory-bench/live-v2-smoke-2026-05-23T20-06-37-325Z.json +34 -0
- package/scripts/memory-bench/live-v2-smoke-2026-05-23T20-12-48-199Z.json +38 -0
- package/scripts/memory-bench/results-baseline-2026-05-19T11-23-12-245Z.json +39 -0
- package/scripts/memory-bench/results-baseline-2026-05-19T11-30-28-763Z.json +1024 -0
- package/scripts/memory-bench/results-baseline-2026-05-19T11-34-19-299Z.json +1007 -0
- package/scripts/memory-bench/results-baseline-2026-05-19T11-44-18-054Z.json +1432 -0
- package/scripts/memory-bench/results-nudge-combined-2026-05-19T12-00-37-465Z.json +1413 -0
- package/scripts/memory-bench/results-nudge-directive-2026-05-19T11-36-52-963Z.json +210 -0
- package/scripts/memory-bench/results-nudge-directive-2026-05-19T11-49-55-790Z.json +1464 -0
- package/scripts/memory-bench/results-nudge-echo-catalog-2026-05-19T11-39-01-829Z.json +232 -0
- package/scripts/memory-bench/results-nudge-echo-catalog-2026-05-19T11-55-12-705Z.json +1397 -0
- package/scripts/memory-bench/scenarios-v2.mjs +123 -0
- package/scripts/memory-bench/scenarios.mjs +178 -0
- package/scripts/office-bench/generate-samples.mjs +180 -0
- package/scripts/op-posture-bench/bench.mjs +397 -0
- package/scripts/op-posture-bench/probe.mjs +87 -0
- package/scripts/op-posture-bench/results-2026-05-18T20-29-13-941Z.json +57 -0
- package/scripts/op-posture-bench/results-2026-05-18T20-38-36-400Z.json +3071 -0
- package/scripts/op-posture-bench/scenarios.mjs +60 -0
- package/scripts/op-posture-bench/variants.mjs +68 -0
- package/scripts/stub-bench/bench.mjs +439 -0
- package/scripts/stub-bench/fixture/auth.js +41 -0
- package/scripts/stub-bench/results-2026-05-19T10-33-27-045Z.json +99 -0
- package/scripts/stub-bench/results-2026-05-19T10-35-08-240Z.json +920 -0
- package/scripts/stub-bench/results-2026-05-19T10-40-12-166Z.json +463 -0
- package/src/__tests__/composioCliFlags.test.js +239 -0
- package/src/core/__tests__/agentScheduler.codebaseKnowledge.test.js +65 -0
- package/src/core/__tests__/agentScheduler.memoryInjection.test.js +78 -0
- package/src/core/agentPool.js +10 -0
- package/src/core/agentScheduler.js +91 -0
- package/src/index.js +19 -3
- package/src/interfaces/__tests__/bulkAgentRoute.test.js +290 -0
- package/src/interfaces/__tests__/composioRoutes.test.js +318 -0
- package/src/interfaces/webServer.js +346 -2
- package/src/interfaces/webServer.js.bak +7047 -0
- package/src/services/__tests__/codeMapStubRenderer.test.js +207 -0
- package/src/services/__tests__/codebaseKnowledgeService.test.js +427 -0
- package/src/services/__tests__/composioService.test.js +332 -0
- package/src/services/__tests__/memoryService.appendAndCatalog.test.js +139 -0
- package/src/services/apiKeyManager.js +33 -0
- package/src/services/codeMapStubRenderer.js +142 -0
- package/src/services/codebaseKnowledgeService.js +430 -0
- package/src/services/composioService.js +378 -0
- package/src/services/memoryService.js +98 -0
- package/src/tools/__tests__/baseTool.test.js +62 -0
- package/src/tools/__tests__/codeMapTool.pluralCanonical.test.js +83 -0
- package/src/tools/__tests__/composioTool.test.js +268 -0
- package/src/tools/__tests__/memoryTool.pluralCanonical.test.js +189 -0
- package/src/tools/__tests__/memoryTool.test.js +1 -1
- package/src/tools/__tests__/officeTool.test.js +403 -0
- package/src/tools/__tests__/openaiFunctionSchemas.memoryReminisce.test.js +24 -25
- package/src/tools/__tests__/singularToolReverseForgive.test.js +97 -0
- package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -0
- package/src/tools/__tests__/taskManagerTool.transition.test.js +236 -0
- package/src/tools/__tests__/toolShapeForgiveness.test.js +260 -0
- package/src/tools/baseTool.js +28 -1
- package/src/tools/codeMapTool.js +1673 -1521
- package/src/tools/composioTool.js +307 -0
- package/src/tools/fileContentReplaceTool.js +893 -840
- package/src/tools/fileSystemTool.js +1372 -1314
- package/src/tools/fileTreeTool.js +7 -0
- package/src/tools/memoryTool.js +217 -81
- package/src/tools/office/officeDoc.js +425 -0
- package/src/tools/office/officePres.js +360 -0
- package/src/tools/office/officeSheet.js +350 -0
- package/src/tools/officeTool.js +313 -0
- package/src/tools/openaiFunctionSchemas.js +40 -50
- package/src/tools/platformControlTool.js +5 -0
- package/src/tools/seekTool.js +36 -1
- package/src/tools/skillsTool.js +10 -0
- package/src/tools/taskManagerTool.js +149 -14
- package/src/tools/terminalTool.js +23 -1
- package/src/tools/visionTool.js +7 -0
- package/src/tools/visualEditorTool.js +7 -0
- package/src/tools/whatsappTool.js +7 -0
- package/src/utilities/authCache.js +47 -6
- package/src/utilities/authCache.js.backup-1779570472481 +121 -0
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/1c-BoCdC5pC.js +1 -0
- package/web-ui/build/static/abap-D7A92M1K.js +1 -0
- package/web-ui/build/static/abnf-DIcpJ99N.js +1 -0
- package/web-ui/build/static/abnf-d4I9yABN.js +1 -0
- package/web-ui/build/static/accesslog-D_Ksv5Fi.js +1 -0
- package/web-ui/build/static/actionscript-CMJI1an7.js +1 -0
- package/web-ui/build/static/actionscript-CNcWu4a1.js +1 -0
- package/web-ui/build/static/ada-BIqOBKro.js +1 -0
- package/web-ui/build/static/ada-BaTkJMdz.js +1 -0
- package/web-ui/build/static/agda-DmRdGgvt.js +1 -0
- package/web-ui/build/static/al-g8BvIfOt.js +1 -0
- package/web-ui/build/static/angelscript-BGxc0B7l.js +1 -0
- package/web-ui/build/static/antlr4-Da7ff6-m.js +1 -0
- package/web-ui/build/static/apache-Bibp-dVJ.js +1 -0
- package/web-ui/build/static/apacheconf-VzeL8tYb.js +1 -0
- package/web-ui/build/static/apex-DUaOCea3.js +1 -0
- package/web-ui/build/static/apl-BpwvFE2V.js +1 -0
- package/web-ui/build/static/applescript-5YKSWwV1.js +1 -0
- package/web-ui/build/static/applescript-BHqj5bpe.js +1 -0
- package/web-ui/build/static/aql-B0Wx_3hH.js +1 -0
- package/web-ui/build/static/arcade-CR8KkII1.js +1 -0
- package/web-ui/build/static/arduino-CYx5u85C.js +1 -0
- package/web-ui/build/static/arduino-ClVU2zro.js +1 -0
- package/web-ui/build/static/arff-kutIH4CC.js +1 -0
- package/web-ui/build/static/armasm-DBm1lGrc.js +1 -0
- package/web-ui/build/static/asciidoc-Cl02VMGf.js +1 -0
- package/web-ui/build/static/asciidoc-MMFYRqre.js +1 -0
- package/web-ui/build/static/asm6502-DPVMGaHn.js +1 -0
- package/web-ui/build/static/asmatmel-Dz4vtZ11.js +1 -0
- package/web-ui/build/static/aspectj-BZidGBlr.js +1 -0
- package/web-ui/build/static/aspnet-C2mo9iee.js +1 -0
- package/web-ui/build/static/autohotkey-Bx83oFMW.js +1 -0
- package/web-ui/build/static/autohotkey-DciFl6K5.js +1 -0
- package/web-ui/build/static/autoit-TVKWI5bu.js +1 -0
- package/web-ui/build/static/autoit-oORW7mrd.js +1 -0
- package/web-ui/build/static/avisynth-D_5uOtxP.js +1 -0
- package/web-ui/build/static/avrasm-D22JmbLm.js +1 -0
- package/web-ui/build/static/avro-idl-CtTuANGZ.js +1 -0
- package/web-ui/build/static/awk-Bnez22eR.js +1 -0
- package/web-ui/build/static/axapta-eqcr7C2-.js +1 -0
- package/web-ui/build/static/bash-D3XWHCZZ.js +1 -0
- package/web-ui/build/static/bash-px0MqVxE.js +1 -0
- package/web-ui/build/static/basic-BWOdgKLg.js +1 -0
- package/web-ui/build/static/basic-C7PK4wVg.js +1 -0
- package/web-ui/build/static/batch-CFeuSY9D.js +1 -0
- package/web-ui/build/static/bbcode-CRC0UNOS.js +1 -0
- package/web-ui/build/static/bicep-C18w8d6Z.js +1 -0
- package/web-ui/build/static/birb-DPiF4fwX.js +1 -0
- package/web-ui/build/static/bison-C1RWPaLl.js +1 -0
- package/web-ui/build/static/bnf-BelSXhsr.js +1 -0
- package/web-ui/build/static/bnf-D_m4SZuc.js +1 -0
- package/web-ui/build/static/brainfuck-Ci7P0POq.js +1 -0
- package/web-ui/build/static/brainfuck-DIrW6_96.js +1 -0
- package/web-ui/build/static/brightscript-4XgpA0OQ.js +1 -0
- package/web-ui/build/static/bro-4kAMStb2.js +1 -0
- package/web-ui/build/static/bsl-CleVjH1I.js +1 -0
- package/web-ui/build/static/c-Ct3AAwH6.js +1 -0
- package/web-ui/build/static/c-EiJrAzIQ.js +1 -0
- package/web-ui/build/static/c-like-B361rHmz.js +1 -0
- package/web-ui/build/static/cal-BZ3Pr4JI.js +1 -0
- package/web-ui/build/static/capnproto-LmwOdJJp.js +1 -0
- package/web-ui/build/static/ceylon-CKAfIFzx.js +1 -0
- package/web-ui/build/static/cfscript-Cms4z16U.js +1 -0
- package/web-ui/build/static/chaiscript-DKxRiUyN.js +1 -0
- package/web-ui/build/static/cil-C6rGhwce.js +1 -0
- package/web-ui/build/static/clean-DmpXs6RN.js +1 -0
- package/web-ui/build/static/clojure-DRYxiF9s.js +1 -0
- package/web-ui/build/static/clojure-DTjXEJCq.js +1 -0
- package/web-ui/build/static/clojure-repl-C1qlAUnK.js +1 -0
- package/web-ui/build/static/cmake-DtUokafC.js +1 -0
- package/web-ui/build/static/cmake-_WqF1fG8.js +1 -0
- package/web-ui/build/static/cobol-D2Q0IMuT.js +1 -0
- package/web-ui/build/static/coffeescript-MRThzdTU.js +1 -0
- package/web-ui/build/static/coffeescript-OHOpkJvb.js +1 -0
- package/web-ui/build/static/concurnas-CVGat9IA.js +1 -0
- package/web-ui/build/static/coq-CB_bM4lt.js +1 -0
- package/web-ui/build/static/coq-WNK38Cqz.js +1 -0
- package/web-ui/build/static/cos-CNa5GVxa.js +1 -0
- package/web-ui/build/static/cpp-D-9lHx0_.js +1 -0
- package/web-ui/build/static/cpp-DRvL1yaA.js +1 -0
- package/web-ui/build/static/crmsh-evnPMxnd.js +1 -0
- package/web-ui/build/static/crystal-RGhNrgnC.js +1 -0
- package/web-ui/build/static/crystal-yrBjXjEh.js +1 -0
- package/web-ui/build/static/csharp-Dr7sLtl1.js +1 -0
- package/web-ui/build/static/csharp-zNVQxjuC.js +1 -0
- package/web-ui/build/static/cshtml-CoiK-7Bu.js +1 -0
- package/web-ui/build/static/csp-Bhgq86EB.js +1 -0
- package/web-ui/build/static/csp-C20UcGAL.js +1 -0
- package/web-ui/build/static/css-D1vlrRV2.js +1 -0
- package/web-ui/build/static/css-extras-DVSAYMbv.js +1 -0
- package/web-ui/build/static/csv-BgR9D8jG.js +1 -0
- package/web-ui/build/static/cypher-Dxehyj6Y.js +1 -0
- package/web-ui/build/static/d-B-Se39n2.js +1 -0
- package/web-ui/build/static/d-Cr4d56op.js +1 -0
- package/web-ui/build/static/dart-BBqlOFkR.js +1 -0
- package/web-ui/build/static/dart-GRD7MWem.js +1 -0
- package/web-ui/build/static/dataweave-BK-Tahkw.js +1 -0
- package/web-ui/build/static/dax-pTr9GVoe.js +1 -0
- package/web-ui/build/static/delphi-CbwSNmp4.js +1 -0
- package/web-ui/build/static/dhall-CuFqRXr6.js +1 -0
- package/web-ui/build/static/diff-CK8Fq88e.js +1 -0
- package/web-ui/build/static/diff-CWbUTU-C.js +1 -0
- package/web-ui/build/static/django-DWaEPdP6.js +1 -0
- package/web-ui/build/static/django-TkEFpAOO.js +1 -0
- package/web-ui/build/static/dns-DKpFJlA0.js +1 -0
- package/web-ui/build/static/dns-zone-file-BIsmZEMf.js +1 -0
- package/web-ui/build/static/docker-DUavAYf7.js +1 -0
- package/web-ui/build/static/dockerfile-YnavjTIo.js +1 -0
- package/web-ui/build/static/dos-Dv3Qr-Oo.js +1 -0
- package/web-ui/build/static/dot-BtIPbx7t.js +1 -0
- package/web-ui/build/static/dsconfig-CEgd9-kI.js +1 -0
- package/web-ui/build/static/dts-BztZn8T6.js +1 -0
- package/web-ui/build/static/dust-B-527Hc0.js +1 -0
- package/web-ui/build/static/ebnf-CH_nnNi5.js +1 -0
- package/web-ui/build/static/ebnf-CuBjcj0j.js +1 -0
- package/web-ui/build/static/editorconfig-CA9KaQ0w.js +1 -0
- package/web-ui/build/static/eiffel-DVYJwwQw.js +1 -0
- package/web-ui/build/static/ejs-C2LKgDYE.js +1 -0
- package/web-ui/build/static/elixir-DVXGkbnw.js +1 -0
- package/web-ui/build/static/elixir-meJ_qqx4.js +1 -0
- package/web-ui/build/static/elm-C5sYS5Cb.js +1 -0
- package/web-ui/build/static/elm-Dj443pWY.js +1 -0
- package/web-ui/build/static/erb-CAj5yksQ.js +1 -0
- package/web-ui/build/static/erb-CcUB2tMd.js +1 -0
- package/web-ui/build/static/erlang-JusKooAX.js +1 -0
- package/web-ui/build/static/erlang-repl-wYgxDX5h.js +1 -0
- package/web-ui/build/static/erlang-sn-PsrSf.js +1 -0
- package/web-ui/build/static/etlua-ChDwUxz6.js +1 -0
- package/web-ui/build/static/excel-BJux1m2h.js +1 -0
- package/web-ui/build/static/excel-formula-i5ByFxAu.js +1 -0
- package/web-ui/build/static/factor-CTutAp6r.js +1 -0
- package/web-ui/build/static/false-DQz_zYVV.js +1 -0
- package/web-ui/build/static/firestore-security-rules-DRGBNXh2.js +1 -0
- package/web-ui/build/static/fix-DeSUhixI.js +1 -0
- package/web-ui/build/static/flix-BKTJVua_.js +1 -0
- package/web-ui/build/static/flow-BpcZsNuo.js +1 -0
- package/web-ui/build/static/fortran-BZIKfBPW.js +1 -0
- package/web-ui/build/static/fortran-BdezWEh5.js +1 -0
- package/web-ui/build/static/fsharp-1Gpt8wZo.js +1 -0
- package/web-ui/build/static/fsharp-CMyiqXUW.js +1 -0
- package/web-ui/build/static/ftl-D9bBJMhV.js +1 -0
- package/web-ui/build/static/gams-DL57wTHN.js +1 -0
- package/web-ui/build/static/gap-DN4Uo9cF.js +1 -0
- package/web-ui/build/static/gauss-DTa1H0QR.js +1 -0
- package/web-ui/build/static/gcode-U5GhqE37.js +1 -0
- package/web-ui/build/static/gcode-s-E37fb4.js +1 -0
- package/web-ui/build/static/gdscript-DkjgGcDv.js +1 -0
- package/web-ui/build/static/gedcom-BbjSSId3.js +1 -0
- package/web-ui/build/static/gherkin-BwIzGx7J.js +1 -0
- package/web-ui/build/static/gherkin-C97W_9I9.js +1 -0
- package/web-ui/build/static/git-DO8dnOip.js +1 -0
- package/web-ui/build/static/glsl-B_4UD4-O.js +1 -0
- package/web-ui/build/static/glsl-CGSjLy2x.js +1 -0
- package/web-ui/build/static/gml-BiITg8HI.js +1 -0
- package/web-ui/build/static/gml-DInGU66p.js +1 -0
- package/web-ui/build/static/gn--m2IH4i3.js +1 -0
- package/web-ui/build/static/go-DOK7GAd-.js +1 -0
- package/web-ui/build/static/go-bof0B9jK.js +1 -0
- package/web-ui/build/static/go-module-CPIVqmnL.js +1 -0
- package/web-ui/build/static/golo-jgy07E43.js +1 -0
- package/web-ui/build/static/gradle-BISOF0nH.js +1 -0
- package/web-ui/build/static/graphql-FqlbDLTL.js +1 -0
- package/web-ui/build/static/groovy-BM0ZyW4a.js +1 -0
- package/web-ui/build/static/groovy-oUdbfbZY.js +1 -0
- package/web-ui/build/static/haml-C8Qg-VO5.js +1 -0
- package/web-ui/build/static/haml-Dse28pB_.js +1 -0
- package/web-ui/build/static/handlebars-CWT7WazY.js +1 -0
- package/web-ui/build/static/handlebars-Ow3joqOm.js +1 -0
- package/web-ui/build/static/haskell-BfraeRhd.js +1 -0
- package/web-ui/build/static/haskell-EhcU7sbn.js +1 -0
- package/web-ui/build/static/haxe-B8tUoExu.js +1 -0
- package/web-ui/build/static/haxe-D9WQHhTh.js +1 -0
- package/web-ui/build/static/hcl-CG3GCouf.js +1 -0
- package/web-ui/build/static/hlsl-CSWRMQ3m.js +1 -0
- package/web-ui/build/static/hoon-Cj0JdbFY.js +1 -0
- package/web-ui/build/static/hpkp-CmjdXbgl.js +1 -0
- package/web-ui/build/static/hsp-VaFZ7Rlv.js +1 -0
- package/web-ui/build/static/hsts-CkJ6UPzY.js +1 -0
- package/web-ui/build/static/htmlbars-pfHjYqd2.js +1 -0
- package/web-ui/build/static/http-2LA-qivJ.js +1 -0
- package/web-ui/build/static/http-CQ_5JSsj.js +1 -0
- package/web-ui/build/static/hy-C-Dll2MQ.js +1 -0
- package/web-ui/build/static/ichigojam-DecRewwq.js +1 -0
- package/web-ui/build/static/icon-CdnU9zPA.js +1 -0
- package/web-ui/build/static/icu-message-format-CUQtjk6Q.js +1 -0
- package/web-ui/build/static/idris-CRMftLq6.js +1 -0
- package/web-ui/build/static/iecst-CXhHqz1P.js +1 -0
- package/web-ui/build/static/ignore-_emqIx7v.js +1 -0
- package/web-ui/build/static/index-BBHrMvg7.js +1216 -0
- package/web-ui/build/static/index-ChkZR_aE.js +13 -0
- package/web-ui/build/static/index-DU4GNSOf.js +1 -0
- package/web-ui/build/static/index-_z8JjNrI.css +1 -0
- package/web-ui/build/static/inform7-CbqlFoFE.js +1 -0
- package/web-ui/build/static/inform7-TxZViMJ9.js +1 -0
- package/web-ui/build/static/ini-D1sHtm5e.js +1 -0
- package/web-ui/build/static/ini-DnqB7pfX.js +1 -0
- package/web-ui/build/static/io-MnQK1mM-.js +1 -0
- package/web-ui/build/static/irpf90-BRaAenqx.js +1 -0
- package/web-ui/build/static/isbl-kubGT4rM.js +1 -0
- package/web-ui/build/static/j-BIz9wT9q.js +1 -0
- package/web-ui/build/static/java-CbQmsHSK.js +1 -0
- package/web-ui/build/static/java-v1B9fNL2.js +1 -0
- package/web-ui/build/static/javadoc-TB1OtWS7.js +1 -0
- package/web-ui/build/static/javadoclike-BBQPwDAU.js +1 -0
- package/web-ui/build/static/javascript-DzNVL5l_.js +1 -0
- package/web-ui/build/static/javastacktrace-BduOgG1e.js +1 -0
- package/web-ui/build/static/jboss-cli-BcqzI366.js +1 -0
- package/web-ui/build/static/jexl-Boyapidr.js +1 -0
- package/web-ui/build/static/jolie-hEbkNpsb.js +1 -0
- package/web-ui/build/static/jq-ZyEE6oGU.js +1 -0
- package/web-ui/build/static/js-extras-CXOzvlL7.js +1 -0
- package/web-ui/build/static/js-templates-CkHsm5px.js +1 -0
- package/web-ui/build/static/jsdoc-Uk3hj8z2.js +1 -0
- package/web-ui/build/static/json-BFi9igjd.js +1 -0
- package/web-ui/build/static/json-LI9wtNaG.js +1 -0
- package/web-ui/build/static/json5-PwjNByuN.js +1 -0
- package/web-ui/build/static/jsonp-DpfGuNSW.js +1 -0
- package/web-ui/build/static/jsstacktrace-DhOP2AhS.js +1 -0
- package/web-ui/build/static/jsx-DmWoDk8F.js +1 -0
- package/web-ui/build/static/julia-DBC5h81N.js +1 -0
- package/web-ui/build/static/julia-Dh9sV3LX.js +1 -0
- package/web-ui/build/static/julia-repl-BYyDp1f4.js +1 -0
- package/web-ui/build/static/keepalived-BTxjrZMV.js +1 -0
- package/web-ui/build/static/keyman-IYiyCDCU.js +1 -0
- package/web-ui/build/static/kotlin-C0PBuzvy.js +1 -0
- package/web-ui/build/static/kotlin-LWYZUK_T.js +1 -0
- package/web-ui/build/static/kumir-CQIbnv9I.js +1 -0
- package/web-ui/build/static/kusto-DA7pQ-Rb.js +1 -0
- package/web-ui/build/static/lasso-CrHySbnC.js +1 -0
- package/web-ui/build/static/latex-CLSOFXG4.js +1 -0
- package/web-ui/build/static/latex-DYknD4Dx.js +1 -0
- package/web-ui/build/static/latte-4QvZcKVw.js +1 -0
- package/web-ui/build/static/ldif-Dr96BfRx.js +1 -0
- package/web-ui/build/static/leaf-C9qL2Qde.js +1 -0
- package/web-ui/build/static/less-DpoID9ZJ.js +1 -0
- package/web-ui/build/static/less-wO8QO0XW.js +1 -0
- package/web-ui/build/static/lilypond-CNp4Kb1P.js +1 -0
- package/web-ui/build/static/liquid-DLULQdgV.js +1 -0
- package/web-ui/build/static/lisp-CrVo-Llt.js +1 -0
- package/web-ui/build/static/lisp-QIAoXzmW.js +1 -0
- package/web-ui/build/static/livecodeserver-DrehOgbf.js +1 -0
- package/web-ui/build/static/livescript-Cm2Yp34x.js +1 -0
- package/web-ui/build/static/livescript-mVYzlrko.js +1 -0
- package/web-ui/build/static/llvm-D6KsQJjh.js +1 -0
- package/web-ui/build/static/llvm-DhIp1o-1.js +1 -0
- package/web-ui/build/static/log-Sj3ocpgB.js +1 -0
- package/web-ui/build/static/lolcode-BSeGnWYG.js +1 -0
- package/web-ui/build/static/lsl-DwgUIp0U.js +1 -0
- package/web-ui/build/static/lua-B7Ot0Oou.js +1 -0
- package/web-ui/build/static/lua-zydwn5-S.js +1 -0
- package/web-ui/build/static/magma-Dgfy2Qny.js +1 -0
- package/web-ui/build/static/makefile-CSjtzdcw.js +1 -0
- package/web-ui/build/static/makefile-DrnEneus.js +1 -0
- package/web-ui/build/static/markdown-D9Ke3tYA.js +1 -0
- package/web-ui/build/static/markdown-DmwKuI2Y.js +1 -0
- package/web-ui/build/static/markup-templating-CikqfHT9.js +1 -0
- package/web-ui/build/static/mathematica-OC0imzI5.js +1 -0
- package/web-ui/build/static/matlab-BlPcqzRw.js +1 -0
- package/web-ui/build/static/matlab-C1iteCkE.js +1 -0
- package/web-ui/build/static/maxima-DecbOh0Y.js +1 -0
- package/web-ui/build/static/maxscript-80cPuIOA.js +1 -0
- package/web-ui/build/static/mel-NI7ysGX2.js +1 -0
- package/web-ui/build/static/mel-r03p1eJo.js +1 -0
- package/web-ui/build/static/mercury-BdNZw6ZU.js +1 -0
- package/web-ui/build/static/mermaid-C1LB7zMJ.js +1 -0
- package/web-ui/build/static/mipsasm-BnZ0cdht.js +1 -0
- package/web-ui/build/static/mizar-BGPNX3WQ.js +1 -0
- package/web-ui/build/static/mizar-CswPcmcG.js +1 -0
- package/web-ui/build/static/mojolicious-rRtgy8Or.js +1 -0
- package/web-ui/build/static/mongodb-CJU0oeix.js +1 -0
- package/web-ui/build/static/monkey-Bj0HaV5-.js +1 -0
- package/web-ui/build/static/monkey-JRYuMIYc.js +1 -0
- package/web-ui/build/static/moonscript-i7e8bkxZ.js +1 -0
- package/web-ui/build/static/moonscript-ldoM156V.js +1 -0
- package/web-ui/build/static/n1ql-C0xs8qWA.js +1 -0
- package/web-ui/build/static/n1ql-DlC-GlVq.js +1 -0
- package/web-ui/build/static/n4js-mIwtIanO.js +1 -0
- package/web-ui/build/static/nand2tetris-hdl-mfHIYPZD.js +1 -0
- package/web-ui/build/static/naniscript-DiDayxx1.js +1 -0
- package/web-ui/build/static/nasm-7uf2nfNC.js +1 -0
- package/web-ui/build/static/neon-BKgOgIAL.js +1 -0
- package/web-ui/build/static/nevod-BlujoQ5k.js +1 -0
- package/web-ui/build/static/nginx-Bb57ubp_.js +1 -0
- package/web-ui/build/static/nginx-DmLU0URp.js +1 -0
- package/web-ui/build/static/nim-CmnPRTHF.js +1 -0
- package/web-ui/build/static/nim-DOReB32c.js +1 -0
- package/web-ui/build/static/nix-BDMn1sgi.js +1 -0
- package/web-ui/build/static/nix-LTHuFEfQ.js +1 -0
- package/web-ui/build/static/node-repl-dxwu8SWp.js +1 -0
- package/web-ui/build/static/nsis-CKD0KqBT.js +1 -0
- package/web-ui/build/static/nsis-IlSwBUak.js +1 -0
- package/web-ui/build/static/objectivec-D4Lo30HV.js +1 -0
- package/web-ui/build/static/objectivec-zmGGqvoM.js +1 -0
- package/web-ui/build/static/ocaml-2uzfqAr8.js +1 -0
- package/web-ui/build/static/ocaml-wF6lV9H4.js +1 -0
- package/web-ui/build/static/opencl-B82Xjnw5.js +1 -0
- package/web-ui/build/static/openqasm-VzVaHpAP.js +1 -0
- package/web-ui/build/static/openscad-B-qK1VfW.js +1 -0
- package/web-ui/build/static/oxygene-BNTVgbsA.js +1 -0
- package/web-ui/build/static/oz-5ZfXBXQY.js +1 -0
- package/web-ui/build/static/parigp-S8JhoJoz.js +1 -0
- package/web-ui/build/static/parser-BZPtbLcv.js +1 -0
- package/web-ui/build/static/parser3-BZRLDHuv.js +1 -0
- package/web-ui/build/static/pascal-GKzqT2Ku.js +1 -0
- package/web-ui/build/static/pascaligo-DnbFz_mr.js +1 -0
- package/web-ui/build/static/pcaxis-DiRsos26.js +1 -0
- package/web-ui/build/static/peoplecode-CMDLbqGB.js +1 -0
- package/web-ui/build/static/perl-BOnBAciC.js +1 -0
- package/web-ui/build/static/perl-fMVLgVTb.js +1 -0
- package/web-ui/build/static/pf-z6xsHHPS.js +1 -0
- package/web-ui/build/static/pgsql-5jHAyGJf.js +1 -0
- package/web-ui/build/static/php-CbG6Jq36.js +1 -0
- package/web-ui/build/static/php-D9yyh70o.js +1 -0
- package/web-ui/build/static/php-extras-CQKSwnMo.js +1 -0
- package/web-ui/build/static/php-template-Ch4UQhUx.js +1 -0
- package/web-ui/build/static/phpdoc-Be7TYcGQ.js +1 -0
- package/web-ui/build/static/plaintext-BsYjBqDy.js +1 -0
- package/web-ui/build/static/plsql-Dc4ePipN.js +1 -0
- package/web-ui/build/static/pony-Cen7DtWb.js +1 -0
- package/web-ui/build/static/powerquery-BIOJ1eUE.js +1 -0
- package/web-ui/build/static/powershell-CbEjJpj7.js +1 -0
- package/web-ui/build/static/powershell-DlceT0ds.js +1 -0
- package/web-ui/build/static/processing-C9GaKPU-.js +1 -0
- package/web-ui/build/static/processing-CTPA3QIV.js +1 -0
- package/web-ui/build/static/profile-CHjz016L.js +1 -0
- package/web-ui/build/static/prolog-BK0g5F4c.js +1 -0
- package/web-ui/build/static/prolog-DrrwUODp.js +1 -0
- package/web-ui/build/static/promql-DftRCUlR.js +1 -0
- package/web-ui/build/static/properties-B122hwLT.js +1 -0
- package/web-ui/build/static/properties-C0m3XIaN.js +1 -0
- package/web-ui/build/static/protobuf-CanIoKel.js +1 -0
- package/web-ui/build/static/protobuf-WvDgzNtD.js +1 -0
- package/web-ui/build/static/psl-JsKwhg_r.js +1 -0
- package/web-ui/build/static/pug-DoQaiAyU.js +1 -0
- package/web-ui/build/static/puppet-CoRftQQB.js +1 -0
- package/web-ui/build/static/puppet-DHgjsvQ8.js +1 -0
- package/web-ui/build/static/pure-BgZIQeOr.js +1 -0
- package/web-ui/build/static/purebasic-BRYfIFBb.js +1 -0
- package/web-ui/build/static/purebasic-DxXSa8gN.js +1 -0
- package/web-ui/build/static/purescript-ChvJvUnk.js +1 -0
- package/web-ui/build/static/python-DqhW0V3z.js +1 -0
- package/web-ui/build/static/python-Dz2FyIQx.js +1 -0
- package/web-ui/build/static/python-repl-Cl3mEb2H.js +1 -0
- package/web-ui/build/static/q-Bg4mQWXp.js +1 -0
- package/web-ui/build/static/q-DwaQK_1p.js +1 -0
- package/web-ui/build/static/qml-D1-fdJvp.js +1 -0
- package/web-ui/build/static/qml-DFsoiY0T.js +1 -0
- package/web-ui/build/static/qore-DdEtFSV5.js +1 -0
- package/web-ui/build/static/qsharp-B_A0OUBX.js +1 -0
- package/web-ui/build/static/r-C3M2HrKx.js +1 -0
- package/web-ui/build/static/r-_EUAt74Q.js +1 -0
- package/web-ui/build/static/racket-B3uAs3VE.js +1 -0
- package/web-ui/build/static/reason-CyAzPvNW.js +1 -0
- package/web-ui/build/static/reasonml-iEzx6ejF.js +1 -0
- package/web-ui/build/static/regex-suWqSnRa.js +1 -0
- package/web-ui/build/static/rego-QeDW60Lx.js +1 -0
- package/web-ui/build/static/renpy-03fEqIYK.js +1 -0
- package/web-ui/build/static/rest-BRJIE-UZ.js +1 -0
- package/web-ui/build/static/rib-DOI_C8C9.js +1 -0
- package/web-ui/build/static/rip-BaEBdknp.js +1 -0
- package/web-ui/build/static/roboconf-DC8IQe4Z.js +1 -0
- package/web-ui/build/static/roboconf-jTu2wKoD.js +1 -0
- package/web-ui/build/static/robotframework-BFp2sQG2.js +1 -0
- package/web-ui/build/static/routeros-Br-GCWs7.js +1 -0
- package/web-ui/build/static/rsl-BpWeUJqw.js +1 -0
- package/web-ui/build/static/ruby-C3nnVoGq.js +1 -0
- package/web-ui/build/static/ruby-DD90V5PL.js +1 -0
- package/web-ui/build/static/ruleslanguage-BflyDdqj.js +1 -0
- package/web-ui/build/static/rust-DtiFFJtC.js +1 -0
- package/web-ui/build/static/rust-uJHZCfXQ.js +1 -0
- package/web-ui/build/static/sas-DUr8rIBf.js +1 -0
- package/web-ui/build/static/sas-POH3vAEy.js +1 -0
- package/web-ui/build/static/sass-D1oLbZQ0.js +1 -0
- package/web-ui/build/static/scala-CDtrRn0l.js +1 -0
- package/web-ui/build/static/scala-VCIKIldH.js +1 -0
- package/web-ui/build/static/scheme-CAWHx2Oj.js +1 -0
- package/web-ui/build/static/scheme-DzKv24tn.js +1 -0
- package/web-ui/build/static/scilab-DuxpEvzV.js +1 -0
- package/web-ui/build/static/scss-BKd4Y-UF.js +1 -0
- package/web-ui/build/static/scss-BpqUKxry.js +1 -0
- package/web-ui/build/static/shell-session-CglnRr2l.js +1 -0
- package/web-ui/build/static/shell-u-Y3PKLQ.js +1 -0
- package/web-ui/build/static/smali-D308KWif.js +1 -0
- package/web-ui/build/static/smali-DYT-jHPu.js +1 -0
- package/web-ui/build/static/smalltalk-BLYA-Ag1.js +1 -0
- package/web-ui/build/static/smalltalk-BdMVmgN0.js +1 -0
- package/web-ui/build/static/smarty-DUYgBrje.js +1 -0
- package/web-ui/build/static/sml-EEhIaAvM.js +1 -0
- package/web-ui/build/static/sml-bQ27koeV.js +1 -0
- package/web-ui/build/static/solidity-U7x7-dFr.js +1 -0
- package/web-ui/build/static/solution-file-Cr03jaqW.js +1 -0
- package/web-ui/build/static/soy-lnGOhaRM.js +1 -0
- package/web-ui/build/static/sparql-BRm44B1P.js +1 -0
- package/web-ui/build/static/splunk-spl-DdrdBOQJ.js +1 -0
- package/web-ui/build/static/sqf-CDtvZjid.js +1 -0
- package/web-ui/build/static/sqf-wr3PtKhW.js +1 -0
- package/web-ui/build/static/sql-B1-8AkNe.js +1 -0
- package/web-ui/build/static/sql-zWEK1lPB.js +1 -0
- package/web-ui/build/static/sql_more-Ck0DuSs3.js +1 -0
- package/web-ui/build/static/squirrel-CfQEIe5h.js +1 -0
- package/web-ui/build/static/stan-BM1Wilpj.js +1 -0
- package/web-ui/build/static/stan-DFPCSU1l.js +1 -0
- package/web-ui/build/static/stata-BJ-qKfEg.js +1 -0
- package/web-ui/build/static/step21-fPKcuR3s.js +1 -0
- package/web-ui/build/static/stylus-BhqK2C03.js +1 -0
- package/web-ui/build/static/stylus-BxloRYSO.js +1 -0
- package/web-ui/build/static/subunit-CueM7bOY.js +1 -0
- package/web-ui/build/static/swift-CPgZZ0ja.js +1 -0
- package/web-ui/build/static/swift-CsEMsJ7g.js +1 -0
- package/web-ui/build/static/systemd-B1Wwkby4.js +1 -0
- package/web-ui/build/static/t4-cs-CL3Ca0dW.js +1 -0
- package/web-ui/build/static/t4-templating-BoV5iKxA.js +1 -0
- package/web-ui/build/static/t4-vb-BKXXzk5n.js +1 -0
- package/web-ui/build/static/taggerscript-aJQMdfVb.js +1 -0
- package/web-ui/build/static/tap-BBfQFbbW.js +1 -0
- package/web-ui/build/static/tap-CmCrAtSH.js +1 -0
- package/web-ui/build/static/tcl-B8xfoxf8.js +1 -0
- package/web-ui/build/static/tcl-CPzoU-PX.js +1 -0
- package/web-ui/build/static/textile-B99mXtsV.js +1 -0
- package/web-ui/build/static/thrift-Cd40Ii7J.js +1 -0
- package/web-ui/build/static/toml-DV5wxyQS.js +1 -0
- package/web-ui/build/static/tp-o2VorAT6.js +1 -0
- package/web-ui/build/static/tremor-Cs0K_i4_.js +1 -0
- package/web-ui/build/static/tsx-KG-mQur8.js +1 -0
- package/web-ui/build/static/tt2-M3GHOvjN.js +1 -0
- package/web-ui/build/static/turtle-D6o0UODZ.js +1 -0
- package/web-ui/build/static/twig-D7LOxPkH.js +1 -0
- package/web-ui/build/static/twig-SHSTj-jA.js +1 -0
- package/web-ui/build/static/typescript-BeIk_BLV.js +1 -0
- package/web-ui/build/static/typescript-Btz-ypJW.js +1 -0
- package/web-ui/build/static/typoscript-7jDBTKMM.js +1 -0
- package/web-ui/build/static/unrealscript-f2f2MAJa.js +1 -0
- package/web-ui/build/static/uorazor-c5VZAS6K.js +1 -0
- package/web-ui/build/static/uri-DY2cDkq-.js +1 -0
- package/web-ui/build/static/v-6ffK7TKq.js +1 -0
- package/web-ui/build/static/vala-BgOkjEeg.js +1 -0
- package/web-ui/build/static/vala-BvuDZGU_.js +1 -0
- package/web-ui/build/static/vbnet-Bdh9clH3.js +1 -0
- package/web-ui/build/static/vbnet-CDpcSndL.js +1 -0
- package/web-ui/build/static/vbscript-dH3gn1bx.js +1 -0
- package/web-ui/build/static/vbscript-html-a_tIfb0-.js +1 -0
- package/web-ui/build/static/velocity-DGDKyukB.js +1 -0
- package/web-ui/build/static/verilog-CtJaE20M.js +1 -0
- package/web-ui/build/static/verilog-CvdiugJe.js +1 -0
- package/web-ui/build/static/vhdl-CN1nxPYJ.js +1 -0
- package/web-ui/build/static/vhdl-JtjHb_oM.js +1 -0
- package/web-ui/build/static/vim-DBRKYGcU.js +1 -0
- package/web-ui/build/static/vim-DQiU261H.js +1 -0
- package/web-ui/build/static/visual-basic-D_daebxW.js +1 -0
- package/web-ui/build/static/warpscript-B4PIoyZp.js +1 -0
- package/web-ui/build/static/wasm-D6_O5K2p.js +1 -0
- package/web-ui/build/static/web-idl-D7BDrII0.js +1 -0
- package/web-ui/build/static/wiki-D-bqO098.js +1 -0
- package/web-ui/build/static/wolfram-NnogXigM.js +1 -0
- package/web-ui/build/static/wren-DwgJaCDU.js +1 -0
- package/web-ui/build/static/x86asm-B9-C3MH5.js +1 -0
- package/web-ui/build/static/xeora-wudvnBkY.js +1 -0
- package/web-ui/build/static/xl-BeBZDETk.js +1 -0
- package/web-ui/build/static/xml-DgNmhWin.js +1 -0
- package/web-ui/build/static/xml-doc-B2RShOT5.js +1 -0
- package/web-ui/build/static/xojo-C0HF7CVl.js +1 -0
- package/web-ui/build/static/xquery-CMss7jIw.js +1 -0
- package/web-ui/build/static/xquery-Dy1YImWg.js +1 -0
- package/web-ui/build/static/yaml--7oDAAKr.js +1 -0
- package/web-ui/build/static/yaml-1-HThDJz.js +1 -0
- package/web-ui/build/static/yang-CxleyLxS.js +1 -0
- package/web-ui/build/static/zephir-B7LMkND2.js +1 -0
- package/web-ui/build/static/zig-DST87v3k.js +1 -0
- package/web-ui/build/static/1c-DGpIT7i5.js +0 -1
- package/web-ui/build/static/abap-5wFDdWLh.js +0 -1
- package/web-ui/build/static/abnf-BP1dpNSE.js +0 -1
- package/web-ui/build/static/abnf-DBEIAl8g.js +0 -1
- package/web-ui/build/static/accesslog-CWSM_T5E.js +0 -1
- package/web-ui/build/static/actionscript-DONkco1J.js +0 -1
- package/web-ui/build/static/actionscript-FqBYk5er.js +0 -1
- package/web-ui/build/static/ada-C2JLRIaM.js +0 -1
- package/web-ui/build/static/ada-gKiygTRK.js +0 -1
- package/web-ui/build/static/agda-CkSODqK2.js +0 -1
- package/web-ui/build/static/al-BJ_YR6p7.js +0 -1
- package/web-ui/build/static/angelscript-Dg2byMGg.js +0 -1
- package/web-ui/build/static/antlr4-BnpyaFNr.js +0 -1
- package/web-ui/build/static/apache-Dffxsd7O.js +0 -1
- package/web-ui/build/static/apacheconf-DLitjtWj.js +0 -1
- package/web-ui/build/static/apex-Drr_IvU2.js +0 -1
- package/web-ui/build/static/apl-CF6qxmXG.js +0 -1
- package/web-ui/build/static/applescript-CjOlw3b_.js +0 -1
- package/web-ui/build/static/applescript-DjkSl1Ry.js +0 -1
- package/web-ui/build/static/aql-KwVmK1gP.js +0 -1
- package/web-ui/build/static/arcade-CENSXx0R.js +0 -1
- package/web-ui/build/static/arduino-B3Ta9Fll.js +0 -1
- package/web-ui/build/static/arduino-CzcsaB9_.js +0 -1
- package/web-ui/build/static/arff-CMJSVt_O.js +0 -1
- package/web-ui/build/static/armasm-0zSgSPB4.js +0 -1
- package/web-ui/build/static/asciidoc-B8K5ctWq.js +0 -1
- package/web-ui/build/static/asciidoc-bk2Sg6b6.js +0 -1
- package/web-ui/build/static/asm6502-ji6zm4FQ.js +0 -1
- package/web-ui/build/static/asmatmel-DJqObM4Y.js +0 -1
- package/web-ui/build/static/aspectj-DqQKI7J5.js +0 -1
- package/web-ui/build/static/aspnet-9cenTxW7.js +0 -1
- package/web-ui/build/static/autohotkey-C6EhiZvl.js +0 -1
- package/web-ui/build/static/autohotkey-sTGJOvMM.js +0 -1
- package/web-ui/build/static/autoit-B0Im8iQ1.js +0 -1
- package/web-ui/build/static/autoit-CO6pUD0H.js +0 -1
- package/web-ui/build/static/avisynth-OvOHTfj5.js +0 -1
- package/web-ui/build/static/avrasm-BLWZ5Mye.js +0 -1
- package/web-ui/build/static/avro-idl-BB2ODvnw.js +0 -1
- package/web-ui/build/static/awk-_jhMabQ0.js +0 -1
- package/web-ui/build/static/axapta-DdBRgoYy.js +0 -1
- package/web-ui/build/static/bash-CsaRGXBQ.js +0 -1
- package/web-ui/build/static/bash-CxLFkwAC.js +0 -1
- package/web-ui/build/static/basic-BJyy7JJE.js +0 -1
- package/web-ui/build/static/basic-CrMb-gv0.js +0 -1
- package/web-ui/build/static/batch-BvcykMe5.js +0 -1
- package/web-ui/build/static/bbcode-EOBuY5Y6.js +0 -1
- package/web-ui/build/static/bicep-QkDJBA34.js +0 -1
- package/web-ui/build/static/birb-TAOxKurn.js +0 -1
- package/web-ui/build/static/bison-BEK6cnad.js +0 -1
- package/web-ui/build/static/bnf-DfEODxsr.js +0 -1
- package/web-ui/build/static/bnf-DhbMjsuA.js +0 -1
- package/web-ui/build/static/brainfuck-BoVocOa7.js +0 -1
- package/web-ui/build/static/brainfuck-DDC5QXPK.js +0 -1
- package/web-ui/build/static/brightscript-DNN598w2.js +0 -1
- package/web-ui/build/static/bro-Cn_jjZ8P.js +0 -1
- package/web-ui/build/static/bsl-CMCN75Gu.js +0 -1
- package/web-ui/build/static/c-DbOGQnEJ.js +0 -1
- package/web-ui/build/static/c-kggwYFsy.js +0 -1
- package/web-ui/build/static/c-like-BIsuUvof.js +0 -1
- package/web-ui/build/static/cal-DpgMsBZE.js +0 -1
- package/web-ui/build/static/capnproto-C1AHYI-M.js +0 -1
- package/web-ui/build/static/ceylon-pvJffDe1.js +0 -1
- package/web-ui/build/static/cfscript-C1qylu52.js +0 -1
- package/web-ui/build/static/chaiscript-D417WKRI.js +0 -1
- package/web-ui/build/static/cil-CjbZHbcY.js +0 -1
- package/web-ui/build/static/clean-Dvc6R-F2.js +0 -1
- package/web-ui/build/static/clojure-CSVRQPMQ.js +0 -1
- package/web-ui/build/static/clojure-ig1Vkg7X.js +0 -1
- package/web-ui/build/static/clojure-repl-C1uyEabk.js +0 -1
- package/web-ui/build/static/cmake-DSbVcAB3.js +0 -1
- package/web-ui/build/static/cmake-Zp8kPwnH.js +0 -1
- package/web-ui/build/static/cobol-OsZSiK_P.js +0 -1
- package/web-ui/build/static/coffeescript-D8r0416S.js +0 -1
- package/web-ui/build/static/coffeescript-DCpgClxh.js +0 -1
- package/web-ui/build/static/concurnas-DKnsxUOc.js +0 -1
- package/web-ui/build/static/coq-BQFlywVI.js +0 -1
- package/web-ui/build/static/coq-BvS9mQB2.js +0 -1
- package/web-ui/build/static/cos-D3ze2791.js +0 -1
- package/web-ui/build/static/cpp-Bw-cV3P1.js +0 -1
- package/web-ui/build/static/cpp-vi1p7XpB.js +0 -1
- package/web-ui/build/static/crmsh-BClnJTeQ.js +0 -1
- package/web-ui/build/static/crystal-DGzOUYZq.js +0 -1
- package/web-ui/build/static/crystal-DMzk6EvA.js +0 -1
- package/web-ui/build/static/csharp-BTom8s2X.js +0 -1
- package/web-ui/build/static/csharp-Cp2V3jfR.js +0 -1
- package/web-ui/build/static/cshtml-Dmtt9Kto.js +0 -1
- package/web-ui/build/static/csp-WPVsLe9_.js +0 -1
- package/web-ui/build/static/csp-qddj5fu_.js +0 -1
- package/web-ui/build/static/css-B0FAm7kj.js +0 -1
- package/web-ui/build/static/css-extras-Bx3pvjiG.js +0 -1
- package/web-ui/build/static/csv-CH-edgS5.js +0 -1
- package/web-ui/build/static/cypher-c3G8Leew.js +0 -1
- package/web-ui/build/static/d-BMDSy22_.js +0 -1
- package/web-ui/build/static/d-BdH4oW8-.js +0 -1
- package/web-ui/build/static/dart-C-r72q-O.js +0 -1
- package/web-ui/build/static/dart-CwpBMrKa.js +0 -1
- package/web-ui/build/static/dataweave-BPvqdt4k.js +0 -1
- package/web-ui/build/static/dax-Eyy6ixcN.js +0 -1
- package/web-ui/build/static/delphi-DhEbPj_5.js +0 -1
- package/web-ui/build/static/dhall-Ct1L8sN1.js +0 -1
- package/web-ui/build/static/diff-CSTqCgwn.js +0 -1
- package/web-ui/build/static/diff-Da97B5vW.js +0 -1
- package/web-ui/build/static/django-DGit_lCg.js +0 -1
- package/web-ui/build/static/django-DPgqFB8k.js +0 -1
- package/web-ui/build/static/dns-DUyXuZ-a.js +0 -1
- package/web-ui/build/static/dns-zone-file-D79MDxVG.js +0 -1
- package/web-ui/build/static/docker-DTiy4o38.js +0 -1
- package/web-ui/build/static/dockerfile-CvwPP8wE.js +0 -1
- package/web-ui/build/static/dos-CaIUWxvb.js +0 -1
- package/web-ui/build/static/dot-D3504w6Y.js +0 -1
- package/web-ui/build/static/dsconfig-Smy1eeX_.js +0 -1
- package/web-ui/build/static/dts-DyTYSXZj.js +0 -1
- package/web-ui/build/static/dust-CrJyi6qA.js +0 -1
- package/web-ui/build/static/ebnf-C8nqfkBH.js +0 -1
- package/web-ui/build/static/ebnf-Cuh5Vh2-.js +0 -1
- package/web-ui/build/static/editorconfig-C7pTGl6n.js +0 -1
- package/web-ui/build/static/eiffel-C75MSJCA.js +0 -1
- package/web-ui/build/static/ejs-Dyo7DF5w.js +0 -1
- package/web-ui/build/static/elixir-D4yJefOc.js +0 -1
- package/web-ui/build/static/elixir-DKRow2SJ.js +0 -1
- package/web-ui/build/static/elm-CgbdDlkT.js +0 -1
- package/web-ui/build/static/elm-D3N-UgU0.js +0 -1
- package/web-ui/build/static/erb-BsITh8qW.js +0 -1
- package/web-ui/build/static/erb-lY_LyKyS.js +0 -1
- package/web-ui/build/static/erlang-BCnPiYmB.js +0 -1
- package/web-ui/build/static/erlang-JEghiPXc.js +0 -1
- package/web-ui/build/static/erlang-repl-DzU97ugC.js +0 -1
- package/web-ui/build/static/etlua-CsBo8cJa.js +0 -1
- package/web-ui/build/static/excel-formula-C2piiCYa.js +0 -1
- package/web-ui/build/static/excel-kqNypwQD.js +0 -1
- package/web-ui/build/static/factor-DZTOhkyU.js +0 -1
- package/web-ui/build/static/false-yLjhfaSw.js +0 -1
- package/web-ui/build/static/firestore-security-rules-oaQNoH8l.js +0 -1
- package/web-ui/build/static/fix-C9IfnTuS.js +0 -1
- package/web-ui/build/static/flix-EmJ_JhPo.js +0 -1
- package/web-ui/build/static/flow-DCUl7IAQ.js +0 -1
- package/web-ui/build/static/fortran-DvyxJmFN.js +0 -1
- package/web-ui/build/static/fortran-EEP9R3S5.js +0 -1
- package/web-ui/build/static/fsharp-D_98s3RX.js +0 -1
- package/web-ui/build/static/fsharp-Dt9jOO5G.js +0 -1
- package/web-ui/build/static/ftl-C8gMHWLo.js +0 -1
- package/web-ui/build/static/gams-BHxVPb4z.js +0 -1
- package/web-ui/build/static/gap-DFtyHk-q.js +0 -1
- package/web-ui/build/static/gauss-BwhJWUcg.js +0 -1
- package/web-ui/build/static/gcode-BvmXwp09.js +0 -1
- package/web-ui/build/static/gcode-gWcD6Vc7.js +0 -1
- package/web-ui/build/static/gdscript-btHoX8RE.js +0 -1
- package/web-ui/build/static/gedcom-MgPs9iqh.js +0 -1
- package/web-ui/build/static/gherkin-B9c_Q16A.js +0 -1
- package/web-ui/build/static/gherkin-BvOgkK6h.js +0 -1
- package/web-ui/build/static/git-D9XWOVcQ.js +0 -1
- package/web-ui/build/static/glsl-CshBHxHY.js +0 -1
- package/web-ui/build/static/glsl-fNRUMTDr.js +0 -1
- package/web-ui/build/static/gml-B78deHK8.js +0 -1
- package/web-ui/build/static/gml-Cj7d2u8O.js +0 -1
- package/web-ui/build/static/gn-CJLD-mF1.js +0 -1
- package/web-ui/build/static/go-CT93BEkL.js +0 -1
- package/web-ui/build/static/go-CTTlNuQO.js +0 -1
- package/web-ui/build/static/go-module-BgnXboUE.js +0 -1
- package/web-ui/build/static/golo-2S5tXS-l.js +0 -1
- package/web-ui/build/static/gradle-8W8DCcWJ.js +0 -1
- package/web-ui/build/static/graphql-DZfp6FNU.js +0 -1
- package/web-ui/build/static/groovy-BfsyMb3X.js +0 -1
- package/web-ui/build/static/groovy-Dxov7ENz.js +0 -1
- package/web-ui/build/static/haml-BlUFsdVV.js +0 -1
- package/web-ui/build/static/haml-CjVj6vvW.js +0 -1
- package/web-ui/build/static/handlebars-DxrQFkyA.js +0 -1
- package/web-ui/build/static/handlebars-FE6fotYl.js +0 -1
- package/web-ui/build/static/haskell-B6z0RCD_.js +0 -1
- package/web-ui/build/static/haskell-JBFmJTRy.js +0 -1
- package/web-ui/build/static/haxe-BtMZMi-_.js +0 -1
- package/web-ui/build/static/haxe-C1J8n-fH.js +0 -1
- package/web-ui/build/static/hcl-DJP-bFWE.js +0 -1
- package/web-ui/build/static/hlsl-DrGjhs1b.js +0 -1
- package/web-ui/build/static/hoon-Cg-ZhqIT.js +0 -1
- package/web-ui/build/static/hpkp-D07vgmoZ.js +0 -1
- package/web-ui/build/static/hsp-CsypPWoA.js +0 -1
- package/web-ui/build/static/hsts-B6DMRxvP.js +0 -1
- package/web-ui/build/static/htmlbars-BI7_Hw4e.js +0 -1
- package/web-ui/build/static/http-90ihEi4s.js +0 -1
- package/web-ui/build/static/http-Dp4QXj9E.js +0 -1
- package/web-ui/build/static/hy-BMgKvP4K.js +0 -1
- package/web-ui/build/static/ichigojam-D6wKvJDb.js +0 -1
- package/web-ui/build/static/icon-CrgkmCwl.js +0 -1
- package/web-ui/build/static/icu-message-format-Bi2JxCXs.js +0 -1
- package/web-ui/build/static/idris-DbUsyZt5.js +0 -1
- package/web-ui/build/static/iecst-CQZ9t8fW.js +0 -1
- package/web-ui/build/static/ignore-BaFgtNMs.js +0 -1
- package/web-ui/build/static/index-DEWSWosh.css +0 -1
- package/web-ui/build/static/index-Di1bjCFA.js +0 -13
- package/web-ui/build/static/index-otR_WSsL.js +0 -1
- package/web-ui/build/static/index-whZPU4as.js +0 -1183
- package/web-ui/build/static/inform7-ClyX1Gro.js +0 -1
- package/web-ui/build/static/inform7-tZHBS5XP.js +0 -1
- package/web-ui/build/static/ini-BrP5JNYL.js +0 -1
- package/web-ui/build/static/ini-CVkrAhwV.js +0 -1
- package/web-ui/build/static/io-BJ1Y6Bdc.js +0 -1
- package/web-ui/build/static/irpf90-fjjcKS_8.js +0 -1
- package/web-ui/build/static/isbl-ClpvfUIz.js +0 -1
- package/web-ui/build/static/j-CICW77xS.js +0 -1
- package/web-ui/build/static/java-B9DFK-0E.js +0 -1
- package/web-ui/build/static/java-BL_6rYko.js +0 -1
- package/web-ui/build/static/javadoc-Cc4HKpKK.js +0 -1
- package/web-ui/build/static/javadoclike-CgNkUDOm.js +0 -1
- package/web-ui/build/static/javascript-CM40ZECq.js +0 -1
- package/web-ui/build/static/javastacktrace-BHSqXfG5.js +0 -1
- package/web-ui/build/static/jboss-cli-Bv5NhVSZ.js +0 -1
- package/web-ui/build/static/jexl--Ohk_keA.js +0 -1
- package/web-ui/build/static/jolie-DMTN5Vdf.js +0 -1
- package/web-ui/build/static/jq-nXRLldXX.js +0 -1
- package/web-ui/build/static/js-extras-eLwv3frs.js +0 -1
- package/web-ui/build/static/js-templates-Ca0owlrg.js +0 -1
- package/web-ui/build/static/jsdoc-KERXp0da.js +0 -1
- package/web-ui/build/static/json-BTjLaRsy.js +0 -1
- package/web-ui/build/static/json-p7pU0qdW.js +0 -1
- package/web-ui/build/static/json5-Cxjy1udc.js +0 -1
- package/web-ui/build/static/jsonp-CO52H7Gy.js +0 -1
- package/web-ui/build/static/jsstacktrace-8YKfoyJP.js +0 -1
- package/web-ui/build/static/jsx-Ct_05KbM.js +0 -1
- package/web-ui/build/static/julia-23I1ubCE.js +0 -1
- package/web-ui/build/static/julia-d8rVGed_.js +0 -1
- package/web-ui/build/static/julia-repl-mwnHedW_.js +0 -1
- package/web-ui/build/static/keepalived-E85Rx_fF.js +0 -1
- package/web-ui/build/static/keyman-aWd3QUDq.js +0 -1
- package/web-ui/build/static/kotlin-Cu370hQq.js +0 -1
- package/web-ui/build/static/kotlin-DoJ2WnmZ.js +0 -1
- package/web-ui/build/static/kumir-oiOgqcQO.js +0 -1
- package/web-ui/build/static/kusto-Bp-B02K5.js +0 -1
- package/web-ui/build/static/lasso-BxoQVwOO.js +0 -1
- package/web-ui/build/static/latex-CANm5vsX.js +0 -1
- package/web-ui/build/static/latex-PMroeNch.js +0 -1
- package/web-ui/build/static/latte-2ErU_2XF.js +0 -1
- package/web-ui/build/static/ldif-ChPn_F7o.js +0 -1
- package/web-ui/build/static/leaf-UkCugDgG.js +0 -1
- package/web-ui/build/static/less-CCH5RA89.js +0 -1
- package/web-ui/build/static/less-CGZbVU1g.js +0 -1
- package/web-ui/build/static/lilypond-BoyM37sv.js +0 -1
- package/web-ui/build/static/liquid-DGJVpRBi.js +0 -1
- package/web-ui/build/static/lisp-93nne61u.js +0 -1
- package/web-ui/build/static/lisp-DYjIRsXz.js +0 -1
- package/web-ui/build/static/livecodeserver-CfNaxIE4.js +0 -1
- package/web-ui/build/static/livescript-C8kDlQkz.js +0 -1
- package/web-ui/build/static/livescript-CoarnRHq.js +0 -1
- package/web-ui/build/static/llvm-CBVyNmAh.js +0 -1
- package/web-ui/build/static/llvm-DGxq8a7u.js +0 -1
- package/web-ui/build/static/log-BivgwFql.js +0 -1
- package/web-ui/build/static/lolcode-l5sK2cZz.js +0 -1
- package/web-ui/build/static/lsl-Xm44xLRQ.js +0 -1
- package/web-ui/build/static/lua-CGvrzfKp.js +0 -1
- package/web-ui/build/static/lua-nHwXeY4c.js +0 -1
- package/web-ui/build/static/magma-DmNItmna.js +0 -1
- package/web-ui/build/static/makefile-CKJNNHGb.js +0 -1
- package/web-ui/build/static/makefile-DI6y5Qml.js +0 -1
- package/web-ui/build/static/markdown-BgpbxKd-.js +0 -1
- package/web-ui/build/static/markdown-CvcxA4yk.js +0 -1
- package/web-ui/build/static/markup-templating-DijqesiA.js +0 -1
- package/web-ui/build/static/mathematica-Cxll1Q10.js +0 -1
- package/web-ui/build/static/matlab-BJo2T1A-.js +0 -1
- package/web-ui/build/static/matlab-C6DlZX4l.js +0 -1
- package/web-ui/build/static/maxima-DJXO4sbL.js +0 -1
- package/web-ui/build/static/maxscript-DdLpUYBs.js +0 -1
- package/web-ui/build/static/mel-BIpfnSyZ.js +0 -1
- package/web-ui/build/static/mel-BYcTUZJW.js +0 -1
- package/web-ui/build/static/mercury-C_LSpbD8.js +0 -1
- package/web-ui/build/static/mermaid-D9yBWnrT.js +0 -1
- package/web-ui/build/static/mipsasm-nR_K2Ue-.js +0 -1
- package/web-ui/build/static/mizar-BeLUPncD.js +0 -1
- package/web-ui/build/static/mizar-BesIbZd9.js +0 -1
- package/web-ui/build/static/mojolicious-cBx3OWa-.js +0 -1
- package/web-ui/build/static/mongodb-DTWKy9ac.js +0 -1
- package/web-ui/build/static/monkey-B72bZC3c.js +0 -1
- package/web-ui/build/static/monkey-G9XELYPQ.js +0 -1
- package/web-ui/build/static/moonscript-BXYVQiqj.js +0 -1
- package/web-ui/build/static/moonscript-sDd-5knz.js +0 -1
- package/web-ui/build/static/n1ql-0vKSfFAO.js +0 -1
- package/web-ui/build/static/n1ql-C9_BSZfz.js +0 -1
- package/web-ui/build/static/n4js-B7Ct8dds.js +0 -1
- package/web-ui/build/static/nand2tetris-hdl-p9gpphTM.js +0 -1
- package/web-ui/build/static/naniscript-6ZVr8Aug.js +0 -1
- package/web-ui/build/static/nasm-Ca73yTUt.js +0 -1
- package/web-ui/build/static/neon-DNP49oyX.js +0 -1
- package/web-ui/build/static/nevod-Qhgt7Bce.js +0 -1
- package/web-ui/build/static/nginx-D5e7lu62.js +0 -1
- package/web-ui/build/static/nginx-DobnyESB.js +0 -1
- package/web-ui/build/static/nim-BPBivUOV.js +0 -1
- package/web-ui/build/static/nim-Baoug1Wa.js +0 -1
- package/web-ui/build/static/nix-CSPTQs5y.js +0 -1
- package/web-ui/build/static/nix-Dk4eNw49.js +0 -1
- package/web-ui/build/static/node-repl-NJNL8VFR.js +0 -1
- package/web-ui/build/static/nsis-BZ0oMzEw.js +0 -1
- package/web-ui/build/static/nsis-CKPCjtCU.js +0 -1
- package/web-ui/build/static/objectivec-BkfIRhhV.js +0 -1
- package/web-ui/build/static/objectivec-CnQgqhbJ.js +0 -1
- package/web-ui/build/static/ocaml-9rGNzRrK.js +0 -1
- package/web-ui/build/static/ocaml-CTolCqxL.js +0 -1
- package/web-ui/build/static/opencl-9Q3vRDxv.js +0 -1
- package/web-ui/build/static/openqasm-D2QiuFBp.js +0 -1
- package/web-ui/build/static/openscad-C3HyuzpB.js +0 -1
- package/web-ui/build/static/oxygene-4gi-VYy_.js +0 -1
- package/web-ui/build/static/oz-BGDEB-1A.js +0 -1
- package/web-ui/build/static/parigp-CfZzp1uE.js +0 -1
- package/web-ui/build/static/parser-UbGteTcy.js +0 -1
- package/web-ui/build/static/parser3-C-Jx-fy7.js +0 -1
- package/web-ui/build/static/pascal-D1_R0gW-.js +0 -1
- package/web-ui/build/static/pascaligo-B8C-98Np.js +0 -1
- package/web-ui/build/static/pcaxis-TGnlUKNs.js +0 -1
- package/web-ui/build/static/peoplecode-C5Vf1AH0.js +0 -1
- package/web-ui/build/static/perl-CBp1N62T.js +0 -1
- package/web-ui/build/static/perl-Z59j904t.js +0 -1
- package/web-ui/build/static/pf-Cq8B_xwQ.js +0 -1
- package/web-ui/build/static/pgsql-ofJbUHkL.js +0 -1
- package/web-ui/build/static/php-OlH7HLQJ.js +0 -1
- package/web-ui/build/static/php-extras-GqtrxLuk.js +0 -1
- package/web-ui/build/static/php-r09kMDOB.js +0 -1
- package/web-ui/build/static/php-template-18uT97Qo.js +0 -1
- package/web-ui/build/static/phpdoc-9tRFvup9.js +0 -1
- package/web-ui/build/static/plaintext-DsYT6Mu-.js +0 -1
- package/web-ui/build/static/plsql-RhWQNJVb.js +0 -1
- package/web-ui/build/static/pony-DD6JMLYI.js +0 -1
- package/web-ui/build/static/powerquery-CALow-bt.js +0 -1
- package/web-ui/build/static/powershell-C2QvIuKF.js +0 -1
- package/web-ui/build/static/powershell-yrbJEhCh.js +0 -1
- package/web-ui/build/static/processing-1T5w_Q03.js +0 -1
- package/web-ui/build/static/processing-DBim_dO-.js +0 -1
- package/web-ui/build/static/profile-Cdloh8mZ.js +0 -1
- package/web-ui/build/static/prolog-DRSsNnns.js +0 -1
- package/web-ui/build/static/prolog-D_ajweDr.js +0 -1
- package/web-ui/build/static/promql-BRuwn6Bn.js +0 -1
- package/web-ui/build/static/properties-D5Wyl4X4.js +0 -1
- package/web-ui/build/static/properties-kn4fl1bl.js +0 -1
- package/web-ui/build/static/protobuf-BMO76zWi.js +0 -1
- package/web-ui/build/static/protobuf-CTUCF-U-.js +0 -1
- package/web-ui/build/static/psl-CiqYdQbY.js +0 -1
- package/web-ui/build/static/pug-BLE2Qayj.js +0 -1
- package/web-ui/build/static/puppet-CFKLWXft.js +0 -1
- package/web-ui/build/static/puppet-DQci0Dl5.js +0 -1
- package/web-ui/build/static/pure-D2h_GynV.js +0 -1
- package/web-ui/build/static/purebasic-BF8MVw8V.js +0 -1
- package/web-ui/build/static/purebasic-BTtHiCkh.js +0 -1
- package/web-ui/build/static/purescript-D1ZSh-sH.js +0 -1
- package/web-ui/build/static/python-Cp9_Vdhb.js +0 -1
- package/web-ui/build/static/python-DdgNw8IW.js +0 -1
- package/web-ui/build/static/python-repl-DvK89VMC.js +0 -1
- package/web-ui/build/static/q-COaIgwhT.js +0 -1
- package/web-ui/build/static/q-Cm0dQkW8.js +0 -1
- package/web-ui/build/static/qml-BpsOqqJM.js +0 -1
- package/web-ui/build/static/qml-BziQXlU4.js +0 -1
- package/web-ui/build/static/qore-Cutz6g-2.js +0 -1
- package/web-ui/build/static/qsharp-B16619X1.js +0 -1
- package/web-ui/build/static/r-CFUIj5Hd.js +0 -1
- package/web-ui/build/static/r-CPrwCi5w.js +0 -1
- package/web-ui/build/static/racket-Bh08DFXF.js +0 -1
- package/web-ui/build/static/reason-BxjDq4e-.js +0 -1
- package/web-ui/build/static/reasonml-Ds5SsGP8.js +0 -1
- package/web-ui/build/static/regex-DhBIDIMI.js +0 -1
- package/web-ui/build/static/rego-DCwxZXcB.js +0 -1
- package/web-ui/build/static/renpy-C2fuQfqb.js +0 -1
- package/web-ui/build/static/rest-C52ZpxWQ.js +0 -1
- package/web-ui/build/static/rib-Cbl2Mzyj.js +0 -1
- package/web-ui/build/static/rip-BTOu5ZIE.js +0 -1
- package/web-ui/build/static/roboconf-3Oi2wuVk.js +0 -1
- package/web-ui/build/static/roboconf-ndLZLE39.js +0 -1
- package/web-ui/build/static/robotframework-BzHXiIj1.js +0 -1
- package/web-ui/build/static/routeros-CkpPoqx-.js +0 -1
- package/web-ui/build/static/rsl-C0bwOQ38.js +0 -1
- package/web-ui/build/static/ruby-C_hIhtuQ.js +0 -1
- package/web-ui/build/static/ruby-DvKfZPzj.js +0 -1
- package/web-ui/build/static/ruleslanguage-CbZJlddz.js +0 -1
- package/web-ui/build/static/rust-BFPIhB-X.js +0 -1
- package/web-ui/build/static/rust-sBpUq-qE.js +0 -1
- package/web-ui/build/static/sas-BCXvYN9x.js +0 -1
- package/web-ui/build/static/sas-D7GAsTY3.js +0 -1
- package/web-ui/build/static/sass-BdaErGMN.js +0 -1
- package/web-ui/build/static/scala-Cj81oCl9.js +0 -1
- package/web-ui/build/static/scala-CvbksfY6.js +0 -1
- package/web-ui/build/static/scheme-BM5ZqKnl.js +0 -1
- package/web-ui/build/static/scheme-BPvlu9Tk.js +0 -1
- package/web-ui/build/static/scilab-CJanLKQN.js +0 -1
- package/web-ui/build/static/scss-C53YF_7f.js +0 -1
- package/web-ui/build/static/scss-DPp8UZbr.js +0 -1
- package/web-ui/build/static/shell-CC9bQXMe.js +0 -1
- package/web-ui/build/static/shell-session-CuR3fbf-.js +0 -1
- package/web-ui/build/static/smali-CUgLls3D.js +0 -1
- package/web-ui/build/static/smali-YODSX8qt.js +0 -1
- package/web-ui/build/static/smalltalk-BMJQ4bbs.js +0 -1
- package/web-ui/build/static/smalltalk-BVGY3CTl.js +0 -1
- package/web-ui/build/static/smarty-C9aNt4-p.js +0 -1
- package/web-ui/build/static/sml-C3BIHhfq.js +0 -1
- package/web-ui/build/static/sml-DTipyRmY.js +0 -1
- package/web-ui/build/static/solidity-1yuPUqoC.js +0 -1
- package/web-ui/build/static/solution-file-BgzK4GOU.js +0 -1
- package/web-ui/build/static/soy-CFJXRvqc.js +0 -1
- package/web-ui/build/static/sparql-CAosYMpl.js +0 -1
- package/web-ui/build/static/splunk-spl-DkINtWr8.js +0 -1
- package/web-ui/build/static/sqf-DbrWIS2M.js +0 -1
- package/web-ui/build/static/sqf-nq8Q9J2W.js +0 -1
- package/web-ui/build/static/sql-9bwClhZQ.js +0 -1
- package/web-ui/build/static/sql-CqPkY-lX.js +0 -1
- package/web-ui/build/static/sql_more-CsY5ts77.js +0 -1
- package/web-ui/build/static/squirrel-BuqtzRBD.js +0 -1
- package/web-ui/build/static/stan-BNxBSglc.js +0 -1
- package/web-ui/build/static/stan-CZVMc34l.js +0 -1
- package/web-ui/build/static/stata-DKnVdHCd.js +0 -1
- package/web-ui/build/static/step21-Cu_TaBGF.js +0 -1
- package/web-ui/build/static/stylus-BS7-OJew.js +0 -1
- package/web-ui/build/static/stylus-DtFrp1Nk.js +0 -1
- package/web-ui/build/static/subunit-DDCoWkkc.js +0 -1
- package/web-ui/build/static/swift-BaguUZbl.js +0 -1
- package/web-ui/build/static/swift-mwBsb8Bx.js +0 -1
- package/web-ui/build/static/systemd-D6PpyDKk.js +0 -1
- package/web-ui/build/static/t4-cs-Cem8g4Ck.js +0 -1
- package/web-ui/build/static/t4-templating-BZo-HjmD.js +0 -1
- package/web-ui/build/static/t4-vb-B4oVnKa4.js +0 -1
- package/web-ui/build/static/taggerscript-DweAZ5pw.js +0 -1
- package/web-ui/build/static/tap-DpuvKHHF.js +0 -1
- package/web-ui/build/static/tap-hUKmJObZ.js +0 -1
- package/web-ui/build/static/tcl-BUvhAi7u.js +0 -1
- package/web-ui/build/static/tcl-Dsck63d8.js +0 -1
- package/web-ui/build/static/textile-CgKbqJ-j.js +0 -1
- package/web-ui/build/static/thrift-B5H6rApp.js +0 -1
- package/web-ui/build/static/toml-DggTpfOo.js +0 -1
- package/web-ui/build/static/tp-CazB2P2X.js +0 -1
- package/web-ui/build/static/tremor-B1jy7S5p.js +0 -1
- package/web-ui/build/static/tsx-BqF2lVDi.js +0 -1
- package/web-ui/build/static/tt2-BNoNXpEe.js +0 -1
- package/web-ui/build/static/turtle-B0evd5mn.js +0 -1
- package/web-ui/build/static/twig-B5A7nMdv.js +0 -1
- package/web-ui/build/static/twig-DZnLWvh8.js +0 -1
- package/web-ui/build/static/typescript-Bbe_P093.js +0 -1
- package/web-ui/build/static/typescript-BfhvmSSG.js +0 -1
- package/web-ui/build/static/typoscript-BjuZEIgw.js +0 -1
- package/web-ui/build/static/unrealscript-C3iUCFRi.js +0 -1
- package/web-ui/build/static/uorazor-CbZXwzIj.js +0 -1
- package/web-ui/build/static/uri-xMPSnp6m.js +0 -1
- package/web-ui/build/static/v-BKcGo5I6.js +0 -1
- package/web-ui/build/static/vala-BRoBE4am.js +0 -1
- package/web-ui/build/static/vala-B__Iyrma.js +0 -1
- package/web-ui/build/static/vbnet-DBxlMRvN.js +0 -1
- package/web-ui/build/static/vbnet-DjAXt5BE.js +0 -1
- package/web-ui/build/static/vbscript-BNA4oANi.js +0 -1
- package/web-ui/build/static/vbscript-html-o8ckLPKG.js +0 -1
- package/web-ui/build/static/velocity-D7sc5ggA.js +0 -1
- package/web-ui/build/static/verilog-BWJfMIng.js +0 -1
- package/web-ui/build/static/verilog-jW2GPC--.js +0 -1
- package/web-ui/build/static/vhdl-BIVlXRPa.js +0 -1
- package/web-ui/build/static/vhdl-BeqdhhxD.js +0 -1
- package/web-ui/build/static/vim-712lI4-g.js +0 -1
- package/web-ui/build/static/vim-DMROTzr0.js +0 -1
- package/web-ui/build/static/visual-basic-CQfbM-ta.js +0 -1
- package/web-ui/build/static/warpscript-DFAvCXFQ.js +0 -1
- package/web-ui/build/static/wasm-CiYoxBl0.js +0 -1
- package/web-ui/build/static/web-idl-DoCkPK8y.js +0 -1
- package/web-ui/build/static/wiki-bvz0AGzB.js +0 -1
- package/web-ui/build/static/wolfram-fBuyFEgU.js +0 -1
- package/web-ui/build/static/wren-DvATFxjF.js +0 -1
- package/web-ui/build/static/x86asm-r4bPbUR_.js +0 -1
- package/web-ui/build/static/xeora-B6iOnDJY.js +0 -1
- package/web-ui/build/static/xl-Ce6B5slc.js +0 -1
- package/web-ui/build/static/xml-DNjyPmhQ.js +0 -1
- package/web-ui/build/static/xml-doc-DydogmZD.js +0 -1
- package/web-ui/build/static/xojo-DCQLltvr.js +0 -1
- package/web-ui/build/static/xquery-C-fAnA0H.js +0 -1
- package/web-ui/build/static/xquery-CNeqzhLO.js +0 -1
- package/web-ui/build/static/yaml-BsVaGsk5.js +0 -1
- package/web-ui/build/static/yaml-kVZvwv_C.js +0 -1
- package/web-ui/build/static/yang-B_gq9JEq.js +0 -1
- package/web-ui/build/static/zephir-ECIXgXhX.js +0 -1
- package/web-ui/build/static/zig-DY325EKG.js +0 -1
|
@@ -1,1315 +1,1373 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FileSystemTool - Handle file system operations safely
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* - Read, write, and manipulate files
|
|
6
|
-
* - Directory operations
|
|
7
|
-
* - File metadata and permissions
|
|
8
|
-
* - Safe file operations with validation
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { BaseTool } from './baseTool.js';
|
|
12
|
-
import TagParser from '../utilities/tagParser.js';
|
|
13
|
-
import DirectoryAccessManager from '../utilities/directoryAccessManager.js';
|
|
14
|
-
import fs from 'fs/promises';
|
|
15
|
-
import path from 'path';
|
|
16
|
-
import crypto from 'crypto';
|
|
17
|
-
|
|
18
|
-
import {
|
|
19
|
-
TOOL_STATUS,
|
|
20
|
-
FILE_EXTENSIONS,
|
|
21
|
-
SYSTEM_DEFAULTS
|
|
22
|
-
} from '../utilities/constants.js';
|
|
23
|
-
import { validateForToolResponse } from '../utilities/structuredFileValidator.js';
|
|
24
|
-
import { createTruncationNotice, getFileExtension } from '../utilities/jsonRepair.js';
|
|
25
|
-
|
|
26
|
-
class FileSystemTool extends BaseTool {
|
|
27
|
-
constructor(config = {}, logger = null) {
|
|
28
|
-
super(config, logger);
|
|
29
|
-
|
|
30
|
-
// Tool metadata
|
|
31
|
-
this.requiresProject = true;
|
|
32
|
-
this.isAsync = false; // Most file operations are quick
|
|
33
|
-
this.timeout = config.timeout || 30000; // 30 seconds
|
|
34
|
-
this.maxConcurrentOperations = config.maxConcurrentOperations || 5;
|
|
35
|
-
|
|
36
|
-
// Security settings
|
|
37
|
-
this.maxFileSize = config.maxFileSize || SYSTEM_DEFAULTS.MAX_FILE_SIZE;
|
|
38
|
-
this.allowedExtensions = config.allowedExtensions || null; // null = all allowed
|
|
39
|
-
this.blockedExtensions = config.blockedExtensions || ['.exe', '.scr', '.com'];
|
|
40
|
-
this.allowedDirectories = config.allowedDirectories || null; // null = project dir only
|
|
41
|
-
|
|
42
|
-
// Post-write validation for structured files (JSON, YAML, XML, etc.)
|
|
43
|
-
// When enabled, validates structured files after writing and includes result in response
|
|
44
|
-
this.validateStructuredFiles = config.validateStructuredFiles !== false; // enabled by default
|
|
45
|
-
|
|
46
|
-
// File operation history
|
|
47
|
-
this.operationHistory = [];
|
|
48
|
-
|
|
49
|
-
// Directory access manager
|
|
50
|
-
this.directoryAccessManager = new DirectoryAccessManager(config, logger);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Get tool description for LLM consumption
|
|
55
|
-
* @returns {string} Tool description
|
|
56
|
-
*/
|
|
57
|
-
getDescription() {
|
|
58
|
-
return `
|
|
59
|
-
File System Tool: Perform file and directory operations safely within the project scope.
|
|
60
|
-
|
|
61
|
-
USAGE:
|
|
62
|
-
\`\`\`json
|
|
63
|
-
{
|
|
64
|
-
"toolId": "filesystem",
|
|
65
|
-
"actions": [
|
|
66
|
-
{"type": "read", "filePath": "src/index.js"},
|
|
67
|
-
{"type": "write", "outputPath": "src/file.js", "content": "..."}
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
\`\`\`
|
|
71
|
-
|
|
72
|
-
TIP: For exploring large or unfamiliar files, prefer the code-map tool (skeleton + read-range) to understand structure without reading entire files. Use filesystem read when you need the complete file content.
|
|
73
|
-
|
|
74
|
-
SUPPORTED ACTIONS:
|
|
75
|
-
- read: Read file contents (filePath)
|
|
76
|
-
- write: Write content to file (outputPath, content)
|
|
77
|
-
- append: Append content to existing file (filePath, content)
|
|
78
|
-
- delete: Delete a file (filePath)
|
|
79
|
-
- copy: Copy file (sourcePath, destPath)
|
|
80
|
-
- move: Move/rename file (sourcePath, destPath)
|
|
81
|
-
- create-dir: Create directory (directory)
|
|
82
|
-
- list: List directory contents (directory)
|
|
83
|
-
- exists: Check if file/directory exists (filePath)
|
|
84
|
-
- stats: Get file/directory metadata (filePath)
|
|
85
|
-
|
|
86
|
-
PARAMETERS:
|
|
87
|
-
- filePath: Path to file (for read, delete, append, exists, stats)
|
|
88
|
-
- outputPath: Path where to write/create file
|
|
89
|
-
- sourcePath: Source path for copy/move operations
|
|
90
|
-
- destPath: Destination path for copy/move operations
|
|
91
|
-
- directory: Directory path for create-dir and list operations
|
|
92
|
-
- content: Content to write/append
|
|
93
|
-
- encoding: File encoding (default: utf8)
|
|
94
|
-
- createDirs: Create parent directories if they don't exist (true/false)
|
|
95
|
-
|
|
96
|
-
EXAMPLES:
|
|
97
|
-
|
|
98
|
-
Write a file:
|
|
99
|
-
\`\`\`json
|
|
100
|
-
{
|
|
101
|
-
"toolId": "filesystem",
|
|
102
|
-
"actions": [{"type": "write", "outputPath": "hello.js", "content": "console.log('Hello');"}]
|
|
103
|
-
}
|
|
104
|
-
\`\`\`
|
|
105
|
-
|
|
106
|
-
Read a file:
|
|
107
|
-
\`\`\`json
|
|
108
|
-
{
|
|
109
|
-
"toolId": "filesystem",
|
|
110
|
-
"actions": [{"type": "read", "filePath": "package.json"}]
|
|
111
|
-
}
|
|
112
|
-
\`\`\`
|
|
113
|
-
|
|
114
|
-
Multiple operations:
|
|
115
|
-
\`\`\`json
|
|
116
|
-
{
|
|
117
|
-
"toolId": "filesystem",
|
|
118
|
-
"actions": [
|
|
119
|
-
{"type": "read", "filePath": "src/index.js"},
|
|
120
|
-
{"type": "copy", "sourcePath": "template.js", "destPath": "src/component.js"},
|
|
121
|
-
{"type": "create-dir", "directory": "src/components/ui"}
|
|
122
|
-
]
|
|
123
|
-
}
|
|
124
|
-
\`\`\`
|
|
125
|
-
|
|
126
|
-
SECURITY:
|
|
127
|
-
- Operations restricted to project directory
|
|
128
|
-
- File size limits enforced (max ${Math.round(this.maxFileSize / 1024 / 1024)}MB)
|
|
129
|
-
- Dangerous file types blocked
|
|
130
|
-
- Path traversal protection
|
|
131
|
-
`;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Parse parameters from tool command content
|
|
136
|
-
* @param {string} content - Raw tool command content
|
|
137
|
-
* @returns {Object} Parsed parameters
|
|
138
|
-
*/
|
|
139
|
-
parseParameters(content) {
|
|
140
|
-
try {
|
|
141
|
-
const params = {};
|
|
142
|
-
const actions = [];
|
|
143
|
-
|
|
144
|
-
this.logger?.debug('FileSystem tool parsing parameters', {
|
|
145
|
-
contentLength: content.length,
|
|
146
|
-
contentPreview: content.substring(0, 200)
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Extract self-closing tags (read, delete, copy, etc.)
|
|
150
|
-
const selfClosingTags = [
|
|
151
|
-
'read', 'delete', 'copy', 'move', 'create-dir',
|
|
152
|
-
'list', 'exists', 'stats', 'append'
|
|
153
|
-
];
|
|
154
|
-
|
|
155
|
-
for (const tagName of selfClosingTags) {
|
|
156
|
-
const tags = TagParser.extractTagsWithAttributes(content, tagName);
|
|
157
|
-
for (const tag of tags) {
|
|
158
|
-
const action = {
|
|
159
|
-
type: tagName,
|
|
160
|
-
...tag.attributes
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
// Normalize common attribute names
|
|
164
|
-
if (action['file-path']) {
|
|
165
|
-
action.filePath = action['file-path'];
|
|
166
|
-
delete action['file-path'];
|
|
167
|
-
}
|
|
168
|
-
if (action['output-path']) {
|
|
169
|
-
action.outputPath = action['output-path'];
|
|
170
|
-
delete action['output-path'];
|
|
171
|
-
}
|
|
172
|
-
if (action['source-path']) {
|
|
173
|
-
action.sourcePath = action['source-path'];
|
|
174
|
-
delete action['source-path'];
|
|
175
|
-
}
|
|
176
|
-
if (action['dest-path']) {
|
|
177
|
-
action.destPath = action['dest-path'];
|
|
178
|
-
delete action['dest-path'];
|
|
179
|
-
}
|
|
180
|
-
if (action['create-dirs']) {
|
|
181
|
-
action.createDirs = action['create-dirs'] === 'true';
|
|
182
|
-
delete action['create-dirs'];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
actions.push(action);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Extract write and append tags with content
|
|
190
|
-
const writeMatches = content.matchAll(/<write\s+([^>]*)>(.*?)<\/write>/gs);
|
|
191
|
-
for (const match of writeMatches) {
|
|
192
|
-
const parser = new TagParser();
|
|
193
|
-
const attributes = parser.parseAttributes(match[1]);
|
|
194
|
-
const writeContent = match[2].trim();
|
|
195
|
-
|
|
196
|
-
const action = {
|
|
197
|
-
type: 'write',
|
|
198
|
-
content: writeContent,
|
|
199
|
-
...attributes
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// Normalize attribute names
|
|
203
|
-
if (action['output-path']) {
|
|
204
|
-
action.outputPath = action['output-path'];
|
|
205
|
-
delete action['output-path'];
|
|
206
|
-
}
|
|
207
|
-
if (action['create-dirs']) {
|
|
208
|
-
action.createDirs = action['create-dirs'] === 'true';
|
|
209
|
-
delete action['create-dirs'];
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
actions.push(action);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const appendMatches = content.matchAll(/<append\s+([^>]*)>(.*?)<\/append>/gs);
|
|
216
|
-
for (const match of appendMatches) {
|
|
217
|
-
const parser = new TagParser();
|
|
218
|
-
const attributes = parser.parseAttributes(match[1]);
|
|
219
|
-
const appendContent = match[2].trim();
|
|
220
|
-
|
|
221
|
-
const action = {
|
|
222
|
-
type: 'append',
|
|
223
|
-
content: appendContent,
|
|
224
|
-
...attributes
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// Normalize attribute names
|
|
228
|
-
if (action['file-path']) {
|
|
229
|
-
action.filePath = action['file-path'];
|
|
230
|
-
delete action['file-path'];
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
actions.push(action);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
params.actions = actions;
|
|
237
|
-
params.rawContent = content.trim();
|
|
238
|
-
|
|
239
|
-
this.logger?.debug('Parsed FileSystem tool parameters', {
|
|
240
|
-
totalActions: actions.length,
|
|
241
|
-
actionTypes: actions.map(a => a.type),
|
|
242
|
-
actions: actions.map(a => ({
|
|
243
|
-
type: a.type,
|
|
244
|
-
filePath: a.filePath,
|
|
245
|
-
outputPath: a.outputPath,
|
|
246
|
-
hasContent: !!a.content
|
|
247
|
-
}))
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
return params;
|
|
251
|
-
|
|
252
|
-
} catch (error) {
|
|
253
|
-
throw new Error(`Failed to parse filesystem parameters: ${error.message}`);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Get required parameters
|
|
259
|
-
* @returns {Array<string>} Array of required parameter names
|
|
260
|
-
*/
|
|
261
|
-
getRequiredParameters() {
|
|
262
|
-
return ['actions'];
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Custom parameter validation
|
|
267
|
-
* @param {Object} params - Parameters to validate
|
|
268
|
-
* @returns {Object} Validation result
|
|
269
|
-
*/
|
|
270
|
-
customValidateParameters(params) {
|
|
271
|
-
const errors = [];
|
|
272
|
-
|
|
273
|
-
if (!params.actions || !Array.isArray(params.actions) || params.actions.length === 0) {
|
|
274
|
-
errors.push('At least one action is required');
|
|
275
|
-
} else {
|
|
276
|
-
// Validate each action
|
|
277
|
-
for (const [index, action] of params.actions.entries()) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
case '
|
|
294
|
-
if (!action.
|
|
295
|
-
errors.push(`Action ${index + 1}:
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
errors.push(`Action ${index + 1}: content is
|
|
306
|
-
console.error('[FileSystemTool] Write validation failed: content is
|
|
307
|
-
outputPath: action.outputPath
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
errors.push(`Action ${index + 1}: content is
|
|
332
|
-
console.error('[FileSystemTool] Append validation failed: content is
|
|
333
|
-
filePath: action.filePath
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
});
|
|
341
|
-
} else if (action.content
|
|
342
|
-
|
|
343
|
-
console.
|
|
344
|
-
filePath: action.filePath
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
//
|
|
425
|
-
//
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
//
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
case '
|
|
555
|
-
result = await this.
|
|
556
|
-
break;
|
|
557
|
-
|
|
558
|
-
case '
|
|
559
|
-
result = await this.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
return
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
await fs.
|
|
874
|
-
|
|
875
|
-
const
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
throw new Error(`
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1
|
+
/**
|
|
2
|
+
* FileSystemTool - Handle file system operations safely
|
|
3
|
+
*
|
|
4
|
+
* Purpose:
|
|
5
|
+
* - Read, write, and manipulate files
|
|
6
|
+
* - Directory operations
|
|
7
|
+
* - File metadata and permissions
|
|
8
|
+
* - Safe file operations with validation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BaseTool } from './baseTool.js';
|
|
12
|
+
import TagParser from '../utilities/tagParser.js';
|
|
13
|
+
import DirectoryAccessManager from '../utilities/directoryAccessManager.js';
|
|
14
|
+
import fs from 'fs/promises';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import crypto from 'crypto';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
TOOL_STATUS,
|
|
20
|
+
FILE_EXTENSIONS,
|
|
21
|
+
SYSTEM_DEFAULTS
|
|
22
|
+
} from '../utilities/constants.js';
|
|
23
|
+
import { validateForToolResponse } from '../utilities/structuredFileValidator.js';
|
|
24
|
+
import { createTruncationNotice, getFileExtension } from '../utilities/jsonRepair.js';
|
|
25
|
+
|
|
26
|
+
class FileSystemTool extends BaseTool {
|
|
27
|
+
constructor(config = {}, logger = null) {
|
|
28
|
+
super(config, logger);
|
|
29
|
+
|
|
30
|
+
// Tool metadata
|
|
31
|
+
this.requiresProject = true;
|
|
32
|
+
this.isAsync = false; // Most file operations are quick
|
|
33
|
+
this.timeout = config.timeout || 30000; // 30 seconds
|
|
34
|
+
this.maxConcurrentOperations = config.maxConcurrentOperations || 5;
|
|
35
|
+
|
|
36
|
+
// Security settings
|
|
37
|
+
this.maxFileSize = config.maxFileSize || SYSTEM_DEFAULTS.MAX_FILE_SIZE;
|
|
38
|
+
this.allowedExtensions = config.allowedExtensions || null; // null = all allowed
|
|
39
|
+
this.blockedExtensions = config.blockedExtensions || ['.exe', '.scr', '.com'];
|
|
40
|
+
this.allowedDirectories = config.allowedDirectories || null; // null = project dir only
|
|
41
|
+
|
|
42
|
+
// Post-write validation for structured files (JSON, YAML, XML, etc.)
|
|
43
|
+
// When enabled, validates structured files after writing and includes result in response
|
|
44
|
+
this.validateStructuredFiles = config.validateStructuredFiles !== false; // enabled by default
|
|
45
|
+
|
|
46
|
+
// File operation history
|
|
47
|
+
this.operationHistory = [];
|
|
48
|
+
|
|
49
|
+
// Directory access manager
|
|
50
|
+
this.directoryAccessManager = new DirectoryAccessManager(config, logger);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get tool description for LLM consumption
|
|
55
|
+
* @returns {string} Tool description
|
|
56
|
+
*/
|
|
57
|
+
getDescription() {
|
|
58
|
+
return `
|
|
59
|
+
File System Tool: Perform file and directory operations safely within the project scope.
|
|
60
|
+
|
|
61
|
+
USAGE:
|
|
62
|
+
\`\`\`json
|
|
63
|
+
{
|
|
64
|
+
"toolId": "filesystem",
|
|
65
|
+
"actions": [
|
|
66
|
+
{"type": "read", "filePath": "src/index.js"},
|
|
67
|
+
{"type": "write", "outputPath": "src/file.js", "content": "..."}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
TIP: For exploring large or unfamiliar files, prefer the code-map tool (skeleton + read-range) to understand structure without reading entire files. Use filesystem read when you need the complete file content.
|
|
73
|
+
|
|
74
|
+
SUPPORTED ACTIONS:
|
|
75
|
+
- read: Read file contents (filePath)
|
|
76
|
+
- write: Write content to file (outputPath, content)
|
|
77
|
+
- append: Append content to existing file (filePath, content)
|
|
78
|
+
- delete: Delete a file (filePath)
|
|
79
|
+
- copy: Copy file (sourcePath, destPath)
|
|
80
|
+
- move: Move/rename file (sourcePath, destPath)
|
|
81
|
+
- create-dir: Create directory (directory)
|
|
82
|
+
- list: List directory contents (directory)
|
|
83
|
+
- exists: Check if file/directory exists (filePath)
|
|
84
|
+
- stats: Get file/directory metadata (filePath)
|
|
85
|
+
|
|
86
|
+
PARAMETERS:
|
|
87
|
+
- filePath: Path to file (for read, delete, append, exists, stats)
|
|
88
|
+
- outputPath: Path where to write/create file
|
|
89
|
+
- sourcePath: Source path for copy/move operations
|
|
90
|
+
- destPath: Destination path for copy/move operations
|
|
91
|
+
- directory: Directory path for create-dir and list operations
|
|
92
|
+
- content: Content to write/append
|
|
93
|
+
- encoding: File encoding (default: utf8)
|
|
94
|
+
- createDirs: Create parent directories if they don't exist (true/false)
|
|
95
|
+
|
|
96
|
+
EXAMPLES:
|
|
97
|
+
|
|
98
|
+
Write a file:
|
|
99
|
+
\`\`\`json
|
|
100
|
+
{
|
|
101
|
+
"toolId": "filesystem",
|
|
102
|
+
"actions": [{"type": "write", "outputPath": "hello.js", "content": "console.log('Hello');"}]
|
|
103
|
+
}
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
106
|
+
Read a file:
|
|
107
|
+
\`\`\`json
|
|
108
|
+
{
|
|
109
|
+
"toolId": "filesystem",
|
|
110
|
+
"actions": [{"type": "read", "filePath": "package.json"}]
|
|
111
|
+
}
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
Multiple operations:
|
|
115
|
+
\`\`\`json
|
|
116
|
+
{
|
|
117
|
+
"toolId": "filesystem",
|
|
118
|
+
"actions": [
|
|
119
|
+
{"type": "read", "filePath": "src/index.js"},
|
|
120
|
+
{"type": "copy", "sourcePath": "template.js", "destPath": "src/component.js"},
|
|
121
|
+
{"type": "create-dir", "directory": "src/components/ui"}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
SECURITY:
|
|
127
|
+
- Operations restricted to project directory
|
|
128
|
+
- File size limits enforced (max ${Math.round(this.maxFileSize / 1024 / 1024)}MB)
|
|
129
|
+
- Dangerous file types blocked
|
|
130
|
+
- Path traversal protection
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Parse parameters from tool command content
|
|
136
|
+
* @param {string} content - Raw tool command content
|
|
137
|
+
* @returns {Object} Parsed parameters
|
|
138
|
+
*/
|
|
139
|
+
parseParameters(content) {
|
|
140
|
+
try {
|
|
141
|
+
const params = {};
|
|
142
|
+
const actions = [];
|
|
143
|
+
|
|
144
|
+
this.logger?.debug('FileSystem tool parsing parameters', {
|
|
145
|
+
contentLength: content.length,
|
|
146
|
+
contentPreview: content.substring(0, 200)
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Extract self-closing tags (read, delete, copy, etc.)
|
|
150
|
+
const selfClosingTags = [
|
|
151
|
+
'read', 'delete', 'copy', 'move', 'create-dir',
|
|
152
|
+
'list', 'exists', 'stats', 'append'
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
for (const tagName of selfClosingTags) {
|
|
156
|
+
const tags = TagParser.extractTagsWithAttributes(content, tagName);
|
|
157
|
+
for (const tag of tags) {
|
|
158
|
+
const action = {
|
|
159
|
+
type: tagName,
|
|
160
|
+
...tag.attributes
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Normalize common attribute names
|
|
164
|
+
if (action['file-path']) {
|
|
165
|
+
action.filePath = action['file-path'];
|
|
166
|
+
delete action['file-path'];
|
|
167
|
+
}
|
|
168
|
+
if (action['output-path']) {
|
|
169
|
+
action.outputPath = action['output-path'];
|
|
170
|
+
delete action['output-path'];
|
|
171
|
+
}
|
|
172
|
+
if (action['source-path']) {
|
|
173
|
+
action.sourcePath = action['source-path'];
|
|
174
|
+
delete action['source-path'];
|
|
175
|
+
}
|
|
176
|
+
if (action['dest-path']) {
|
|
177
|
+
action.destPath = action['dest-path'];
|
|
178
|
+
delete action['dest-path'];
|
|
179
|
+
}
|
|
180
|
+
if (action['create-dirs']) {
|
|
181
|
+
action.createDirs = action['create-dirs'] === 'true';
|
|
182
|
+
delete action['create-dirs'];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
actions.push(action);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Extract write and append tags with content
|
|
190
|
+
const writeMatches = content.matchAll(/<write\s+([^>]*)>(.*?)<\/write>/gs);
|
|
191
|
+
for (const match of writeMatches) {
|
|
192
|
+
const parser = new TagParser();
|
|
193
|
+
const attributes = parser.parseAttributes(match[1]);
|
|
194
|
+
const writeContent = match[2].trim();
|
|
195
|
+
|
|
196
|
+
const action = {
|
|
197
|
+
type: 'write',
|
|
198
|
+
content: writeContent,
|
|
199
|
+
...attributes
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Normalize attribute names
|
|
203
|
+
if (action['output-path']) {
|
|
204
|
+
action.outputPath = action['output-path'];
|
|
205
|
+
delete action['output-path'];
|
|
206
|
+
}
|
|
207
|
+
if (action['create-dirs']) {
|
|
208
|
+
action.createDirs = action['create-dirs'] === 'true';
|
|
209
|
+
delete action['create-dirs'];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
actions.push(action);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const appendMatches = content.matchAll(/<append\s+([^>]*)>(.*?)<\/append>/gs);
|
|
216
|
+
for (const match of appendMatches) {
|
|
217
|
+
const parser = new TagParser();
|
|
218
|
+
const attributes = parser.parseAttributes(match[1]);
|
|
219
|
+
const appendContent = match[2].trim();
|
|
220
|
+
|
|
221
|
+
const action = {
|
|
222
|
+
type: 'append',
|
|
223
|
+
content: appendContent,
|
|
224
|
+
...attributes
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// Normalize attribute names
|
|
228
|
+
if (action['file-path']) {
|
|
229
|
+
action.filePath = action['file-path'];
|
|
230
|
+
delete action['file-path'];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
actions.push(action);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
params.actions = actions;
|
|
237
|
+
params.rawContent = content.trim();
|
|
238
|
+
|
|
239
|
+
this.logger?.debug('Parsed FileSystem tool parameters', {
|
|
240
|
+
totalActions: actions.length,
|
|
241
|
+
actionTypes: actions.map(a => a.type),
|
|
242
|
+
actions: actions.map(a => ({
|
|
243
|
+
type: a.type,
|
|
244
|
+
filePath: a.filePath,
|
|
245
|
+
outputPath: a.outputPath,
|
|
246
|
+
hasContent: !!a.content
|
|
247
|
+
}))
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return params;
|
|
251
|
+
|
|
252
|
+
} catch (error) {
|
|
253
|
+
throw new Error(`Failed to parse filesystem parameters: ${error.message}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Get required parameters
|
|
259
|
+
* @returns {Array<string>} Array of required parameter names
|
|
260
|
+
*/
|
|
261
|
+
getRequiredParameters() {
|
|
262
|
+
return ['actions'];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Custom parameter validation
|
|
267
|
+
* @param {Object} params - Parameters to validate
|
|
268
|
+
* @returns {Object} Validation result
|
|
269
|
+
*/
|
|
270
|
+
customValidateParameters(params) {
|
|
271
|
+
const errors = [];
|
|
272
|
+
|
|
273
|
+
if (!params.actions || !Array.isArray(params.actions) || params.actions.length === 0) {
|
|
274
|
+
errors.push('At least one action is required');
|
|
275
|
+
} else {
|
|
276
|
+
// Validate each action
|
|
277
|
+
for (const [index, action] of params.actions.entries()) {
|
|
278
|
+
// Accept both `type` and `action` as the item discriminator —
|
|
279
|
+
// some tools in the codebase (jobdone, docx, excel, pdf) use
|
|
280
|
+
// `action`, and agents pattern-match across tools. Normalize
|
|
281
|
+
// to `type` here so the rest of the switch + execute body
|
|
282
|
+
// reads canonically. See cross-tool envelope unification thread.
|
|
283
|
+
if (!action.type && action.action) action.type = action.action;
|
|
284
|
+
if (!action.type) {
|
|
285
|
+
errors.push(`Action ${index + 1}: type is required`);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
switch (action.type) {
|
|
290
|
+
case 'read':
|
|
291
|
+
case 'delete':
|
|
292
|
+
case 'exists':
|
|
293
|
+
case 'stats':
|
|
294
|
+
if (!action.filePath) {
|
|
295
|
+
errors.push(`Action ${index + 1}: file-path is required for ${action.type}`);
|
|
296
|
+
}
|
|
297
|
+
break;
|
|
298
|
+
|
|
299
|
+
case 'write':
|
|
300
|
+
if (!action.outputPath) {
|
|
301
|
+
errors.push(`Action ${index + 1}: output-path is required for write`);
|
|
302
|
+
}
|
|
303
|
+
// Content validation with detailed diagnostics
|
|
304
|
+
if (action.content === undefined) {
|
|
305
|
+
errors.push(`Action ${index + 1}: content is undefined for write (outputPath: ${action.outputPath || 'not set'})`);
|
|
306
|
+
console.error('[FileSystemTool] Write validation failed: content is undefined', {
|
|
307
|
+
outputPath: action.outputPath,
|
|
308
|
+
actionKeys: Object.keys(action)
|
|
309
|
+
});
|
|
310
|
+
} else if (action.content === null) {
|
|
311
|
+
errors.push(`Action ${index + 1}: content is null for write (outputPath: ${action.outputPath || 'not set'})`);
|
|
312
|
+
console.error('[FileSystemTool] Write validation failed: content is null', {
|
|
313
|
+
outputPath: action.outputPath
|
|
314
|
+
});
|
|
315
|
+
} else if (typeof action.content !== 'string') {
|
|
316
|
+
errors.push(`Action ${index + 1}: content must be a string, got ${typeof action.content}`);
|
|
317
|
+
console.error('[FileSystemTool] Write validation failed: content is not a string', {
|
|
318
|
+
outputPath: action.outputPath,
|
|
319
|
+
contentType: typeof action.content
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
// Note: empty string content is allowed (creates empty file)
|
|
323
|
+
break;
|
|
324
|
+
|
|
325
|
+
case 'append':
|
|
326
|
+
if (!action.filePath) {
|
|
327
|
+
errors.push(`Action ${index + 1}: file-path is required for append`);
|
|
328
|
+
}
|
|
329
|
+
// Content validation with detailed diagnostics
|
|
330
|
+
if (action.content === undefined) {
|
|
331
|
+
errors.push(`Action ${index + 1}: content is undefined for append (filePath: ${action.filePath || 'not set'})`);
|
|
332
|
+
console.error('[FileSystemTool] Append validation failed: content is undefined', {
|
|
333
|
+
filePath: action.filePath,
|
|
334
|
+
actionKeys: Object.keys(action)
|
|
335
|
+
});
|
|
336
|
+
} else if (action.content === null) {
|
|
337
|
+
errors.push(`Action ${index + 1}: content is null for append (filePath: ${action.filePath || 'not set'})`);
|
|
338
|
+
console.error('[FileSystemTool] Append validation failed: content is null', {
|
|
339
|
+
filePath: action.filePath
|
|
340
|
+
});
|
|
341
|
+
} else if (typeof action.content !== 'string') {
|
|
342
|
+
errors.push(`Action ${index + 1}: content must be a string, got ${typeof action.content}`);
|
|
343
|
+
console.error('[FileSystemTool] Append validation failed: content is not a string', {
|
|
344
|
+
filePath: action.filePath,
|
|
345
|
+
contentType: typeof action.content
|
|
346
|
+
});
|
|
347
|
+
} else if (action.content.length === 0) {
|
|
348
|
+
// Empty append is suspicious - log a warning but allow it
|
|
349
|
+
console.warn('[FileSystemTool] Append with empty content', {
|
|
350
|
+
filePath: action.filePath
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
|
|
355
|
+
case 'copy':
|
|
356
|
+
case 'move':
|
|
357
|
+
if (!action.sourcePath) {
|
|
358
|
+
errors.push(`Action ${index + 1}: source-path is required for ${action.type}`);
|
|
359
|
+
}
|
|
360
|
+
if (!action.destPath) {
|
|
361
|
+
errors.push(`Action ${index + 1}: dest-path is required for ${action.type}`);
|
|
362
|
+
}
|
|
363
|
+
break;
|
|
364
|
+
|
|
365
|
+
case 'create-dir':
|
|
366
|
+
case 'list':
|
|
367
|
+
if (!action.directory) {
|
|
368
|
+
errors.push(`Action ${index + 1}: directory is required for ${action.type}`);
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
|
|
372
|
+
default:
|
|
373
|
+
errors.push(`Action ${index + 1}: unknown action type: ${action.type}`);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Validate file extensions if specified
|
|
377
|
+
if (action.filePath && !this.isAllowedFileExtension(action.filePath)) {
|
|
378
|
+
errors.push(`Action ${index + 1}: file type not allowed: ${path.extname(action.filePath)}`);
|
|
379
|
+
}
|
|
380
|
+
if (action.outputPath && !this.isAllowedFileExtension(action.outputPath)) {
|
|
381
|
+
errors.push(`Action ${index + 1}: file type not allowed: ${path.extname(action.outputPath)}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
valid: errors.length === 0,
|
|
388
|
+
errors
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Execute tool with parsed parameters
|
|
394
|
+
* @param {Object} params - Parsed parameters
|
|
395
|
+
* @param {Object} context - Execution context
|
|
396
|
+
* @returns {Promise<Object>} Execution result
|
|
397
|
+
*/
|
|
398
|
+
async execute(params, context) {
|
|
399
|
+
// Validate params structure
|
|
400
|
+
if (!params || typeof params !== 'object') {
|
|
401
|
+
throw new Error('Invalid parameters: params must be an object');
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Forgiving normalization — production agents commonly call with
|
|
405
|
+
// the natural singular shape `{action: 'read', path: 'X'}` instead
|
|
406
|
+
// of the documented plural `{actions: [{type: 'read', filePath: 'X'}]}`.
|
|
407
|
+
// Live trace evidence: Kimi-K2.6 hits this on most multi-task
|
|
408
|
+
// sessions and cascades into chained tool failures. Accept both
|
|
409
|
+
// shapes here. The plural canonical form is preserved internally.
|
|
410
|
+
if (!params.actions && params.action) {
|
|
411
|
+
const { action, ...rest } = params;
|
|
412
|
+
// Map common alternate field names to canonical ones.
|
|
413
|
+
const promoted = { type: action };
|
|
414
|
+
if (rest.path && !rest.filePath) promoted.filePath = rest.path;
|
|
415
|
+
// Preserve everything else as-is (filePath, outputPath, content,
|
|
416
|
+
// sourcePath, destPath, directory, encoding, createDirs, etc.).
|
|
417
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
418
|
+
if (k === 'path') continue;
|
|
419
|
+
promoted[k] = v;
|
|
420
|
+
}
|
|
421
|
+
params = { ...params, actions: [promoted] };
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Normalize each action's discriminator field name: accept both
|
|
425
|
+
// `type` (canonical) and `action` (used by jobdone/docx/excel/pdf).
|
|
426
|
+
// Production path calls execute() directly, bypassing the
|
|
427
|
+
// validation hook — this guards the switch in execute.
|
|
428
|
+
if (Array.isArray(params.actions)) {
|
|
429
|
+
for (const a of params.actions) {
|
|
430
|
+
if (a && !a.type && a.action) a.type = a.action;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const { actions } = params;
|
|
435
|
+
|
|
436
|
+
// Validate actions array
|
|
437
|
+
if (!actions) {
|
|
438
|
+
throw new Error('Invalid parameters: actions is required (e.g. `actions: [{type: "read", filePath: "src/x.js"}]`). Singular shape `{action: "read", path: "X"}` also accepted. Received params: ' + JSON.stringify(Object.keys(params)));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (!Array.isArray(actions)) {
|
|
442
|
+
throw new Error('Invalid parameters: actions must be an array. Received type: ' + typeof actions);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (actions.length === 0) {
|
|
446
|
+
throw new Error('Invalid parameters: actions array is empty');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// CRITICAL: Run custom validation (not called by messageProcessor)
|
|
450
|
+
// This ensures write/append actions have required content
|
|
451
|
+
const validation = this.customValidateParameters(params);
|
|
452
|
+
if (!validation.valid) {
|
|
453
|
+
const errorMsg = validation.errors?.join('; ') || validation.error || 'Validation failed';
|
|
454
|
+
console.error('[FileSystemTool] Parameter validation failed:', errorMsg);
|
|
455
|
+
throw new Error(`Parameter validation failed: ${errorMsg}`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const { projectDir, agentId, directoryAccess } = context;
|
|
459
|
+
|
|
460
|
+
// Per-agent config overrides (agent.toolConfig.filesystem) merged
|
|
461
|
+
// with this tool's global defaults. Applied per-action at the top of
|
|
462
|
+
// the execute loop — every action that touches a file path is
|
|
463
|
+
// gated against the effective extension policy, and write/append
|
|
464
|
+
// payloads are size-gated against the effective maxFileSize.
|
|
465
|
+
const effectiveFs = this.getEffectiveConfig(context, {
|
|
466
|
+
allowedExtensions: this.allowedExtensions,
|
|
467
|
+
blockedExtensions: this.blockedExtensions,
|
|
468
|
+
maxFileSize: this.maxFileSize,
|
|
469
|
+
});
|
|
470
|
+
const effectiveBlockedExt = Array.isArray(effectiveFs.blockedExtensions)
|
|
471
|
+
? effectiveFs.blockedExtensions.map(e => String(e).toLowerCase())
|
|
472
|
+
: [];
|
|
473
|
+
const effectiveAllowedExt = (Array.isArray(effectiveFs.allowedExtensions) && effectiveFs.allowedExtensions.length > 0)
|
|
474
|
+
? effectiveFs.allowedExtensions.map(e => String(e).toLowerCase())
|
|
475
|
+
: null;
|
|
476
|
+
const effectiveMaxFileSize = (typeof effectiveFs.maxFileSize === 'number' && effectiveFs.maxFileSize > 0)
|
|
477
|
+
? effectiveFs.maxFileSize
|
|
478
|
+
: this.maxFileSize;
|
|
479
|
+
|
|
480
|
+
const _checkExt = (filePath) => {
|
|
481
|
+
if (!filePath) return null;
|
|
482
|
+
const ext = (filePath.match(/\.[^./\\]+$/)?.[0] || '').toLowerCase();
|
|
483
|
+
if (effectiveBlockedExt.includes(ext)) {
|
|
484
|
+
return `File extension ${ext || '(none)'} is blocked by agent policy: ${filePath}`;
|
|
485
|
+
}
|
|
486
|
+
if (effectiveAllowedExt && !effectiveAllowedExt.includes(ext)) {
|
|
487
|
+
return `File extension ${ext || '(none)'} is not in the agent's allowed list: ${filePath}`;
|
|
488
|
+
}
|
|
489
|
+
return null;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
// Get directory access configuration from agent or create default
|
|
493
|
+
const accessConfig = directoryAccess ||
|
|
494
|
+
this.directoryAccessManager.createDirectoryAccess({
|
|
495
|
+
workingDirectory: projectDir || process.cwd(),
|
|
496
|
+
writeEnabledDirectories: [projectDir || process.cwd()],
|
|
497
|
+
restrictToProject: true
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// IMPORTANT: If the agent has directoryAccess configured, use its workingDirectory
|
|
501
|
+
// This ensures UI-configured project directories are respected
|
|
502
|
+
if (directoryAccess && directoryAccess.workingDirectory) {
|
|
503
|
+
// Agent has explicitly configured working directory from UI - use it
|
|
504
|
+
console.log('FileSystem DEBUG: Using agent configured working directory:', directoryAccess.workingDirectory);
|
|
505
|
+
console.log('FileSystem DEBUG: Full directoryAccess object:', JSON.stringify(directoryAccess, null, 2));
|
|
506
|
+
} else {
|
|
507
|
+
// Using fallback to projectDir or process.cwd()
|
|
508
|
+
console.log('FileSystem DEBUG: Using fallback working directory:', projectDir || process.cwd());
|
|
509
|
+
console.log('FileSystem DEBUG: directoryAccess is:', directoryAccess);
|
|
510
|
+
console.log('FileSystem DEBUG: projectDir is:', projectDir);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const results = [];
|
|
514
|
+
|
|
515
|
+
for (const action of actions) {
|
|
516
|
+
try {
|
|
517
|
+
// Per-agent extension policy gate — runs BEFORE the action so
|
|
518
|
+
// disallowed file types never reach the filesystem layer. Terminal
|
|
519
|
+
// and web tools use the same short-circuit pattern.
|
|
520
|
+
const pathsToCheck = [action.filePath, action.outputPath].filter(Boolean);
|
|
521
|
+
for (const p of pathsToCheck) {
|
|
522
|
+
const err = _checkExt(p);
|
|
523
|
+
if (err) {
|
|
524
|
+
results.push({ success: false, action: action.type, error: err });
|
|
525
|
+
throw new Error('__skip');
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
// Per-agent maxFileSize gate for write/append — fires ONLY when
|
|
529
|
+
// the agent explicitly overrides maxFileSize via toolConfig. When
|
|
530
|
+
// the agent has no override, the existing `this.maxFileSize`
|
|
531
|
+
// check downstream handles it with its original error message,
|
|
532
|
+
// preserving backward compatibility. Read-side and stat-based
|
|
533
|
+
// size checks still use `this.maxFileSize` at deeper call sites.
|
|
534
|
+
const perAgentMaxFileSize = (typeof context?.toolConfig?.maxFileSize === 'number' && context.toolConfig.maxFileSize > 0)
|
|
535
|
+
? context.toolConfig.maxFileSize
|
|
536
|
+
: null;
|
|
537
|
+
if (perAgentMaxFileSize != null
|
|
538
|
+
&& (action.type === 'write' || action.type === 'append')
|
|
539
|
+
&& typeof action.content === 'string') {
|
|
540
|
+
const payloadBytes = Buffer.byteLength(action.content, 'utf8');
|
|
541
|
+
if (payloadBytes > perAgentMaxFileSize) {
|
|
542
|
+
results.push({
|
|
543
|
+
success: false,
|
|
544
|
+
action: action.type,
|
|
545
|
+
error: `Content too large: ${payloadBytes} bytes exceeds per-agent maxFileSize (${perAgentMaxFileSize})`,
|
|
546
|
+
});
|
|
547
|
+
throw new Error('__skip');
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
let result;
|
|
552
|
+
|
|
553
|
+
switch (action.type) {
|
|
554
|
+
case 'read':
|
|
555
|
+
result = await this.readFile(action.filePath, accessConfig, action.encoding);
|
|
556
|
+
break;
|
|
557
|
+
|
|
558
|
+
case 'write':
|
|
559
|
+
result = await this.writeFile(action.outputPath, action.content, accessConfig, {
|
|
560
|
+
encoding: action.encoding,
|
|
561
|
+
createDirs: action.createDirs,
|
|
562
|
+
wasTruncated: context.wasTruncated || false
|
|
563
|
+
});
|
|
564
|
+
break;
|
|
565
|
+
|
|
566
|
+
case 'append':
|
|
567
|
+
result = await this.appendToFile(action.filePath, action.content, accessConfig, action.encoding);
|
|
568
|
+
break;
|
|
569
|
+
|
|
570
|
+
case 'delete':
|
|
571
|
+
result = await this.deleteFile(action.filePath, accessConfig);
|
|
572
|
+
break;
|
|
573
|
+
|
|
574
|
+
case 'copy':
|
|
575
|
+
result = await this.copyFile(action.sourcePath, action.destPath, accessConfig);
|
|
576
|
+
break;
|
|
577
|
+
|
|
578
|
+
case 'move':
|
|
579
|
+
result = await this.moveFile(action.sourcePath, action.destPath, accessConfig);
|
|
580
|
+
break;
|
|
581
|
+
|
|
582
|
+
case 'create-dir':
|
|
583
|
+
result = await this.createDirectory(action.directory, accessConfig);
|
|
584
|
+
break;
|
|
585
|
+
|
|
586
|
+
case 'list':
|
|
587
|
+
result = await this.listDirectory(action.directory, accessConfig);
|
|
588
|
+
break;
|
|
589
|
+
|
|
590
|
+
case 'exists':
|
|
591
|
+
result = await this.checkExists(action.filePath, accessConfig);
|
|
592
|
+
break;
|
|
593
|
+
|
|
594
|
+
case 'stats':
|
|
595
|
+
result = await this.getFileStats(action.filePath, accessConfig);
|
|
596
|
+
break;
|
|
597
|
+
|
|
598
|
+
default:
|
|
599
|
+
throw new Error(`Unknown action type: ${action.type}`);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
results.push(result);
|
|
603
|
+
this.addToHistory(action, result, context.agentId);
|
|
604
|
+
|
|
605
|
+
// Invalidate the codebase-knowledge cache for files we just
|
|
606
|
+
// mutated — the agent should know its cached skeleton/range
|
|
607
|
+
// for these paths is now stale and must be re-fetched.
|
|
608
|
+
// Best-effort: never block on this. See
|
|
609
|
+
// services/codebaseKnowledgeService.js for design rationale.
|
|
610
|
+
if (context.agentId && ['write','append','delete','copy','move'].includes(action.type) && result?.success !== false) {
|
|
611
|
+
try {
|
|
612
|
+
const { getCodebaseKnowledgeService } = await import('../services/codebaseKnowledgeService.js');
|
|
613
|
+
const ks = getCodebaseKnowledgeService(this.logger);
|
|
614
|
+
const paths = [];
|
|
615
|
+
if (action.outputPath) paths.push(action.outputPath);
|
|
616
|
+
if (action.filePath) paths.push(action.filePath);
|
|
617
|
+
if (action.destPath) paths.push(action.destPath); // for copy/move (the dest is newly written)
|
|
618
|
+
if (action.sourcePath && action.type === 'move') paths.push(action.sourcePath); // src gone
|
|
619
|
+
if (action.sourcePath && action.type === 'delete') paths.push(action.sourcePath);
|
|
620
|
+
const wd = context.directoryAccess?.workingDirectory || context.projectDir || null;
|
|
621
|
+
for (const p of paths) ks.markDirty(context.agentId, p, wd);
|
|
622
|
+
} catch (e) {
|
|
623
|
+
this.logger?.debug?.('codebase-knowledge invalidation failed (filesystem)', { error: e.message });
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
} catch (error) {
|
|
628
|
+
// Per-agent policy gate above uses "__skip" to signal that it
|
|
629
|
+
// already pushed a useful error onto results — don't double-log
|
|
630
|
+
// or double-push.
|
|
631
|
+
if (error.message === '__skip') {
|
|
632
|
+
this.addToHistory(action, results[results.length - 1], context.agentId);
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Log detailed error for debugging
|
|
637
|
+
console.error(`[FileSystemTool] Action '${action.type}' failed:`, {
|
|
638
|
+
action: action.type,
|
|
639
|
+
filePath: action.filePath || action.outputPath || action.directory,
|
|
640
|
+
error: error.message,
|
|
641
|
+
stack: error.stack?.split('\n').slice(0, 3).join('\n'),
|
|
642
|
+
contentLength: action.content?.length,
|
|
643
|
+
hasContent: action.content !== undefined && action.content !== null
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
const errorResult = {
|
|
647
|
+
success: false,
|
|
648
|
+
action: action.type,
|
|
649
|
+
error: error.message,
|
|
650
|
+
filePath: action.filePath || action.outputPath || action.directory,
|
|
651
|
+
// Include debug info for troubleshooting
|
|
652
|
+
debug: {
|
|
653
|
+
contentProvided: action.content !== undefined && action.content !== null,
|
|
654
|
+
contentLength: action.content?.length || 0,
|
|
655
|
+
contentPreview: action.content ? action.content.substring(0, 100) + (action.content.length > 100 ? '...' : '') : null
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
results.push(errorResult);
|
|
660
|
+
this.addToHistory(action, errorResult, context.agentId);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Determine overall success - only true if ALL actions succeeded
|
|
665
|
+
const allSucceeded = results.every(r => r.success === true);
|
|
666
|
+
const failedCount = results.filter(r => r.success === false).length;
|
|
667
|
+
|
|
668
|
+
return {
|
|
669
|
+
success: allSucceeded,
|
|
670
|
+
actions: results,
|
|
671
|
+
executedActions: actions.length,
|
|
672
|
+
successfulActions: actions.length - failedCount,
|
|
673
|
+
failedActions: failedCount,
|
|
674
|
+
toolUsed: 'filesys',
|
|
675
|
+
...(failedCount > 0 && {
|
|
676
|
+
warning: `${failedCount} of ${actions.length} action(s) failed. Check individual action results for details.`
|
|
677
|
+
})
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Read file contents
|
|
683
|
+
* @private
|
|
684
|
+
*/
|
|
685
|
+
async readFile(filePath, accessConfig, encoding = 'utf8') {
|
|
686
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
687
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
688
|
+
|
|
689
|
+
// Validate read access using DirectoryAccessManager
|
|
690
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
691
|
+
if (!accessResult.allowed) {
|
|
692
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
try {
|
|
696
|
+
const stats = await fs.stat(fullPath);
|
|
697
|
+
|
|
698
|
+
if (stats.size > this.maxFileSize) {
|
|
699
|
+
throw new Error(`File too large: ${stats.size} bytes (max ${this.maxFileSize})`);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const content = await fs.readFile(fullPath, encoding);
|
|
703
|
+
|
|
704
|
+
return {
|
|
705
|
+
success: true,
|
|
706
|
+
action: 'read',
|
|
707
|
+
filePath: this.directoryAccessManager.createRelativePath(fullPath, accessConfig),
|
|
708
|
+
content,
|
|
709
|
+
size: stats.size,
|
|
710
|
+
encoding,
|
|
711
|
+
lastModified: stats.mtime.toISOString(),
|
|
712
|
+
message: `Read ${stats.size} bytes from ${filePath}`
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
} catch (error) {
|
|
716
|
+
throw new Error(`Failed to read file ${filePath}: ${error.message}`);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Write content to file
|
|
722
|
+
* @private
|
|
723
|
+
*/
|
|
724
|
+
async writeFile(outputPath, content, accessConfig, options = {}) {
|
|
725
|
+
const { encoding = 'utf8', createDirs = true, wasTruncated = false } = options;
|
|
726
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
727
|
+
const fullPath = this.resolvePath(outputPath, workingDir);
|
|
728
|
+
|
|
729
|
+
// Validate write access using DirectoryAccessManager
|
|
730
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
731
|
+
if (!accessResult.allowed) {
|
|
732
|
+
throw new Error(`Write access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Handle truncated content - append notice if AI response was cut off
|
|
736
|
+
let finalContent = content;
|
|
737
|
+
let truncationApplied = false;
|
|
738
|
+
|
|
739
|
+
if (wasTruncated && content) {
|
|
740
|
+
const fileExt = getFileExtension(outputPath);
|
|
741
|
+
const truncationNotice = createTruncationNotice(fileExt);
|
|
742
|
+
if (truncationNotice) {
|
|
743
|
+
finalContent = content + truncationNotice;
|
|
744
|
+
truncationApplied = true;
|
|
745
|
+
console.log(`[FileSystemTool] Appending truncation notice to ${outputPath} (AI response was truncated)`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
try {
|
|
750
|
+
// Check content size
|
|
751
|
+
const contentSize = Buffer.byteLength(finalContent, encoding);
|
|
752
|
+
if (contentSize > this.maxFileSize) {
|
|
753
|
+
throw new Error(`Content too large: ${contentSize} bytes (max ${this.maxFileSize})`);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Create parent directories if requested
|
|
757
|
+
if (createDirs) {
|
|
758
|
+
const dirPath = path.dirname(fullPath);
|
|
759
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Create backup if file exists
|
|
763
|
+
let backupPath = null;
|
|
764
|
+
try {
|
|
765
|
+
await fs.access(fullPath);
|
|
766
|
+
backupPath = `${fullPath}.backup-${Date.now()}`;
|
|
767
|
+
await fs.copyFile(fullPath, backupPath);
|
|
768
|
+
} catch {
|
|
769
|
+
// File doesn't exist, no backup needed
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
await fs.writeFile(fullPath, finalContent, encoding);
|
|
773
|
+
|
|
774
|
+
// VERIFICATION: Confirm file was written correctly
|
|
775
|
+
const stats = await fs.stat(fullPath);
|
|
776
|
+
|
|
777
|
+
// Verify file size matches expected content size
|
|
778
|
+
const expectedSize = Buffer.byteLength(finalContent, encoding);
|
|
779
|
+
if (stats.size !== expectedSize) {
|
|
780
|
+
throw new Error(`Write verification failed: expected ${expectedSize} bytes but file is ${stats.size} bytes`);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// For text files, verify content was written (read back and compare hash)
|
|
784
|
+
if (encoding === 'utf8' || encoding === 'utf-8') {
|
|
785
|
+
const writtenContent = await fs.readFile(fullPath, encoding);
|
|
786
|
+
if (writtenContent !== finalContent) {
|
|
787
|
+
throw new Error(`Write verification failed: content mismatch after write`);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
792
|
+
|
|
793
|
+
// Build base result
|
|
794
|
+
const result = {
|
|
795
|
+
success: true,
|
|
796
|
+
action: 'write',
|
|
797
|
+
outputPath: relativePath,
|
|
798
|
+
fullPath: fullPath,
|
|
799
|
+
size: stats.size,
|
|
800
|
+
encoding,
|
|
801
|
+
verified: true, // Content was verified after write
|
|
802
|
+
backupPath: backupPath ? this.directoryAccessManager.createRelativePath(backupPath, accessConfig) : null,
|
|
803
|
+
backupFullPath: backupPath || null,
|
|
804
|
+
message: `Wrote ${stats.size} bytes to ${fullPath} (verified)`,
|
|
805
|
+
// Include truncation info if applicable
|
|
806
|
+
...(truncationApplied && {
|
|
807
|
+
wasTruncated: true,
|
|
808
|
+
truncationWarning: 'Content was truncated due to AI response token limit. A notice was appended to the file.'
|
|
809
|
+
}),
|
|
810
|
+
// Warn if content is empty
|
|
811
|
+
...(stats.size === 0 && {
|
|
812
|
+
emptyContent: true,
|
|
813
|
+
emptyWarning: 'File was written with empty content'
|
|
814
|
+
})
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
// Add truncation warning to message
|
|
818
|
+
if (truncationApplied) {
|
|
819
|
+
result.message += ' [PARTIAL: AI response was truncated - content may be incomplete]';
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Post-write validation for structured files (plug-and-play via structuredFileValidator)
|
|
823
|
+
if (this.validateStructuredFiles) {
|
|
824
|
+
const validation = validateForToolResponse(content, fullPath);
|
|
825
|
+
if (validation) {
|
|
826
|
+
result.validation = validation;
|
|
827
|
+
// Add warning to message if validation failed
|
|
828
|
+
if (!validation.valid) {
|
|
829
|
+
result.message += ` [WARNING: ${validation.format.toUpperCase()} validation failed with ${validation.errorCount} error(s)]`;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
return result;
|
|
835
|
+
|
|
836
|
+
} catch (error) {
|
|
837
|
+
throw new Error(`Failed to write file ${fullPath}: ${error.message}`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Append content to file
|
|
843
|
+
* @private
|
|
844
|
+
*/
|
|
845
|
+
async appendToFile(filePath, content, accessConfig, encoding = 'utf8') {
|
|
846
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
847
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
848
|
+
|
|
849
|
+
// Validate write access using DirectoryAccessManager
|
|
850
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
851
|
+
if (!accessResult.allowed) {
|
|
852
|
+
throw new Error(`Write access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
try {
|
|
856
|
+
// Check if file exists and get current size
|
|
857
|
+
let currentSize = 0;
|
|
858
|
+
try {
|
|
859
|
+
const stats = await fs.stat(fullPath);
|
|
860
|
+
currentSize = stats.size;
|
|
861
|
+
} catch {
|
|
862
|
+
// File doesn't exist, will be created
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const contentSize = Buffer.byteLength(content, encoding);
|
|
866
|
+
if (currentSize + contentSize > this.maxFileSize) {
|
|
867
|
+
throw new Error(`File would become too large: ${currentSize + contentSize} bytes (max ${this.maxFileSize})`);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Store size before append for verification
|
|
871
|
+
const sizeBefore = currentSize;
|
|
872
|
+
|
|
873
|
+
await fs.appendFile(fullPath, content, encoding);
|
|
874
|
+
|
|
875
|
+
const stats = await fs.stat(fullPath);
|
|
876
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
877
|
+
|
|
878
|
+
// VERIFICATION: Confirm append actually happened
|
|
879
|
+
const expectedSize = sizeBefore + contentSize;
|
|
880
|
+
if (stats.size < expectedSize) {
|
|
881
|
+
throw new Error(`Append verification failed: expected at least ${expectedSize} bytes but file is ${stats.size} bytes`);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// For text files, verify the appended content is at the end
|
|
885
|
+
if (encoding === 'utf8' || encoding === 'utf-8') {
|
|
886
|
+
const fileContent = await fs.readFile(fullPath, encoding);
|
|
887
|
+
if (!fileContent.endsWith(content)) {
|
|
888
|
+
throw new Error(`Append verification failed: appended content not found at end of file`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
return {
|
|
893
|
+
success: true,
|
|
894
|
+
action: 'append',
|
|
895
|
+
filePath: relativePath,
|
|
896
|
+
fullPath: fullPath,
|
|
897
|
+
appendedBytes: contentSize,
|
|
898
|
+
totalSize: stats.size,
|
|
899
|
+
sizeBefore: sizeBefore,
|
|
900
|
+
encoding,
|
|
901
|
+
verified: true,
|
|
902
|
+
message: `Appended ${contentSize} bytes to ${fullPath} (verified)`
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
} catch (error) {
|
|
906
|
+
throw new Error(`Failed to append to file ${fullPath}: ${error.message}`);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Delete file
|
|
912
|
+
* @private
|
|
913
|
+
*/
|
|
914
|
+
async deleteFile(filePath, accessConfig) {
|
|
915
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
916
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
917
|
+
|
|
918
|
+
// Validate write access for deletion
|
|
919
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
920
|
+
if (!accessResult.allowed) {
|
|
921
|
+
throw new Error(`Delete access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
try {
|
|
925
|
+
const stats = await fs.stat(fullPath);
|
|
926
|
+
|
|
927
|
+
// Create backup before deletion
|
|
928
|
+
const backupPath = `${fullPath}.deleted-backup-${Date.now()}`;
|
|
929
|
+
await fs.copyFile(fullPath, backupPath);
|
|
930
|
+
|
|
931
|
+
await fs.unlink(fullPath);
|
|
932
|
+
|
|
933
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
934
|
+
const backupRelativePath = this.directoryAccessManager.createRelativePath(backupPath, accessConfig);
|
|
935
|
+
|
|
936
|
+
return {
|
|
937
|
+
success: true,
|
|
938
|
+
action: 'delete',
|
|
939
|
+
filePath: relativePath,
|
|
940
|
+
fullPath: fullPath,
|
|
941
|
+
size: stats.size,
|
|
942
|
+
backupPath: backupRelativePath,
|
|
943
|
+
backupFullPath: backupPath,
|
|
944
|
+
message: `Deleted ${fullPath} (backup created)`
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
} catch (error) {
|
|
948
|
+
throw new Error(`Failed to delete file ${fullPath}: ${error.message}`);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* Copy file
|
|
954
|
+
* @private
|
|
955
|
+
*/
|
|
956
|
+
async copyFile(sourcePath, destPath, accessConfig) {
|
|
957
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
958
|
+
const fullSourcePath = this.resolvePath(sourcePath, workingDir);
|
|
959
|
+
const fullDestPath = this.resolvePath(destPath, workingDir);
|
|
960
|
+
|
|
961
|
+
// Validate read access for source
|
|
962
|
+
const sourceAccessResult = this.directoryAccessManager.validateReadAccess(fullSourcePath, accessConfig);
|
|
963
|
+
if (!sourceAccessResult.allowed) {
|
|
964
|
+
throw new Error(`Source read access denied: ${sourceAccessResult.reason} (${sourceAccessResult.path})`);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Validate write access for destination
|
|
968
|
+
const destAccessResult = this.directoryAccessManager.validateWriteAccess(fullDestPath, accessConfig);
|
|
969
|
+
if (!destAccessResult.allowed) {
|
|
970
|
+
throw new Error(`Destination write access denied: ${destAccessResult.reason} (${destAccessResult.path})`);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
try {
|
|
974
|
+
const sourceStats = await fs.stat(fullSourcePath);
|
|
975
|
+
|
|
976
|
+
if (sourceStats.size > this.maxFileSize) {
|
|
977
|
+
throw new Error(`Source file too large: ${sourceStats.size} bytes`);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// Create destination directory if needed
|
|
981
|
+
const destDir = path.dirname(fullDestPath);
|
|
982
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
983
|
+
|
|
984
|
+
await fs.copyFile(fullSourcePath, fullDestPath);
|
|
985
|
+
|
|
986
|
+
const sourceRelativePath = this.directoryAccessManager.createRelativePath(fullSourcePath, accessConfig);
|
|
987
|
+
const destRelativePath = this.directoryAccessManager.createRelativePath(fullDestPath, accessConfig);
|
|
988
|
+
|
|
989
|
+
return {
|
|
990
|
+
success: true,
|
|
991
|
+
action: 'copy',
|
|
992
|
+
sourcePath: sourceRelativePath,
|
|
993
|
+
destPath: destRelativePath,
|
|
994
|
+
sourceFullPath: fullSourcePath,
|
|
995
|
+
destFullPath: fullDestPath,
|
|
996
|
+
size: sourceStats.size,
|
|
997
|
+
message: `Copied ${fullSourcePath} to ${fullDestPath}`
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
throw new Error(`Failed to copy ${fullSourcePath} to ${fullDestPath}: ${error.message}`);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Move/rename file
|
|
1007
|
+
* @private
|
|
1008
|
+
*/
|
|
1009
|
+
async moveFile(sourcePath, destPath, accessConfig) {
|
|
1010
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1011
|
+
const fullSourcePath = this.resolvePath(sourcePath, workingDir);
|
|
1012
|
+
const fullDestPath = this.resolvePath(destPath, workingDir);
|
|
1013
|
+
|
|
1014
|
+
// Validate read access for source
|
|
1015
|
+
const readResult = this.directoryAccessManager.validateReadAccess(fullSourcePath, accessConfig);
|
|
1016
|
+
if (!readResult.allowed) {
|
|
1017
|
+
throw new Error(`Read access denied for source: ${readResult.reason} (${readResult.path})`);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// Validate write access for destination
|
|
1021
|
+
const writeResult = this.directoryAccessManager.validateWriteAccess(fullDestPath, accessConfig);
|
|
1022
|
+
if (!writeResult.allowed) {
|
|
1023
|
+
throw new Error(`Write access denied for destination: ${writeResult.reason} (${writeResult.path})`);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
try {
|
|
1027
|
+
const sourceStats = await fs.stat(fullSourcePath);
|
|
1028
|
+
|
|
1029
|
+
// Create destination directory if needed
|
|
1030
|
+
const destDir = path.dirname(fullDestPath);
|
|
1031
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
1032
|
+
|
|
1033
|
+
await fs.rename(fullSourcePath, fullDestPath);
|
|
1034
|
+
|
|
1035
|
+
const relativeSource = this.directoryAccessManager.createRelativePath(fullSourcePath, accessConfig);
|
|
1036
|
+
const relativeDest = this.directoryAccessManager.createRelativePath(fullDestPath, accessConfig);
|
|
1037
|
+
|
|
1038
|
+
return {
|
|
1039
|
+
success: true,
|
|
1040
|
+
action: 'move',
|
|
1041
|
+
sourcePath: relativeSource,
|
|
1042
|
+
destPath: relativeDest,
|
|
1043
|
+
fullSourcePath: fullSourcePath,
|
|
1044
|
+
fullDestPath: fullDestPath,
|
|
1045
|
+
size: sourceStats.size,
|
|
1046
|
+
message: `Moved ${sourcePath} to ${destPath}`
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
} catch (error) {
|
|
1050
|
+
throw new Error(`Failed to move ${sourcePath} to ${destPath}: ${error.message}`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Create directory
|
|
1056
|
+
* @private
|
|
1057
|
+
*/
|
|
1058
|
+
async createDirectory(directory, accessConfig) {
|
|
1059
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1060
|
+
const fullPath = this.resolvePath(directory, workingDir);
|
|
1061
|
+
|
|
1062
|
+
// Validate write access using DirectoryAccessManager
|
|
1063
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
1064
|
+
if (!accessResult.allowed) {
|
|
1065
|
+
throw new Error(`Write access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
try {
|
|
1069
|
+
await fs.mkdir(fullPath, { recursive: true });
|
|
1070
|
+
|
|
1071
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1072
|
+
|
|
1073
|
+
return {
|
|
1074
|
+
success: true,
|
|
1075
|
+
action: 'create-dir',
|
|
1076
|
+
directory: relativePath,
|
|
1077
|
+
fullPath: fullPath,
|
|
1078
|
+
message: `Created directory ${directory}`
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
throw new Error(`Failed to create directory ${directory}: ${error.message}`);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* List directory contents
|
|
1088
|
+
* @private
|
|
1089
|
+
*/
|
|
1090
|
+
async listDirectory(directory, accessConfig) {
|
|
1091
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1092
|
+
const fullPath = this.resolvePath(directory, workingDir);
|
|
1093
|
+
|
|
1094
|
+
// Validate read access using DirectoryAccessManager
|
|
1095
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1096
|
+
if (!accessResult.allowed) {
|
|
1097
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
try {
|
|
1101
|
+
const entries = await fs.readdir(fullPath, { withFileTypes: true });
|
|
1102
|
+
|
|
1103
|
+
const contents = [];
|
|
1104
|
+
for (const entry of entries) {
|
|
1105
|
+
const entryPath = path.join(fullPath, entry.name);
|
|
1106
|
+
const stats = await fs.stat(entryPath);
|
|
1107
|
+
|
|
1108
|
+
contents.push({
|
|
1109
|
+
name: entry.name,
|
|
1110
|
+
type: entry.isDirectory() ? 'directory' : 'file',
|
|
1111
|
+
size: entry.isFile() ? stats.size : undefined,
|
|
1112
|
+
lastModified: stats.mtime.toISOString(),
|
|
1113
|
+
permissions: stats.mode,
|
|
1114
|
+
isSymlink: entry.isSymbolicLink()
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1119
|
+
|
|
1120
|
+
return {
|
|
1121
|
+
success: true,
|
|
1122
|
+
action: 'list',
|
|
1123
|
+
directory: relativePath,
|
|
1124
|
+
fullPath: fullPath,
|
|
1125
|
+
contents,
|
|
1126
|
+
totalItems: contents.length,
|
|
1127
|
+
directories: contents.filter(item => item.type === 'directory').length,
|
|
1128
|
+
files: contents.filter(item => item.type === 'file').length,
|
|
1129
|
+
message: `Listed ${contents.length} items in ${directory}`
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
throw new Error(`Failed to list directory ${directory}: ${error.message}`);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* Check if file/directory exists
|
|
1139
|
+
* @private
|
|
1140
|
+
*/
|
|
1141
|
+
async checkExists(filePath, accessConfig) {
|
|
1142
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1143
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
1144
|
+
|
|
1145
|
+
// Validate read access
|
|
1146
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1147
|
+
if (!accessResult.allowed) {
|
|
1148
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
try {
|
|
1152
|
+
const stats = await fs.stat(fullPath);
|
|
1153
|
+
|
|
1154
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1155
|
+
|
|
1156
|
+
return {
|
|
1157
|
+
success: true,
|
|
1158
|
+
action: 'exists',
|
|
1159
|
+
filePath: relativePath,
|
|
1160
|
+
fullPath: fullPath,
|
|
1161
|
+
exists: true,
|
|
1162
|
+
type: stats.isDirectory() ? 'directory' : 'file',
|
|
1163
|
+
message: `${filePath} exists as ${stats.isDirectory() ? 'directory' : 'file'}`
|
|
1164
|
+
};
|
|
1165
|
+
|
|
1166
|
+
} catch (error) {
|
|
1167
|
+
if (error.code === 'ENOENT') {
|
|
1168
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1169
|
+
return {
|
|
1170
|
+
success: true,
|
|
1171
|
+
action: 'exists',
|
|
1172
|
+
filePath: relativePath,
|
|
1173
|
+
fullPath: fullPath,
|
|
1174
|
+
exists: false,
|
|
1175
|
+
message: `${filePath} does not exist`
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
throw new Error(`Failed to check existence of ${filePath}: ${error.message}`);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
/**
|
|
1184
|
+
* Get file statistics
|
|
1185
|
+
* @private
|
|
1186
|
+
*/
|
|
1187
|
+
async getFileStats(filePath, accessConfig) {
|
|
1188
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1189
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
1190
|
+
|
|
1191
|
+
// Validate read access
|
|
1192
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1193
|
+
if (!accessResult.allowed) {
|
|
1194
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
try {
|
|
1198
|
+
const stats = await fs.stat(fullPath);
|
|
1199
|
+
|
|
1200
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1201
|
+
|
|
1202
|
+
return {
|
|
1203
|
+
success: true,
|
|
1204
|
+
action: 'stats',
|
|
1205
|
+
filePath: relativePath,
|
|
1206
|
+
fullPath: fullPath,
|
|
1207
|
+
stats: {
|
|
1208
|
+
size: stats.size,
|
|
1209
|
+
type: stats.isDirectory() ? 'directory' : 'file',
|
|
1210
|
+
lastModified: stats.mtime.toISOString(),
|
|
1211
|
+
lastAccessed: stats.atime.toISOString(),
|
|
1212
|
+
created: stats.birthtime.toISOString(),
|
|
1213
|
+
permissions: stats.mode,
|
|
1214
|
+
isSymlink: stats.isSymbolicLink()
|
|
1215
|
+
},
|
|
1216
|
+
message: `Retrieved stats for ${filePath}`
|
|
1217
|
+
};
|
|
1218
|
+
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
throw new Error(`Failed to get stats for ${filePath}: ${error.message}`);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* Resolve file path safely (legacy method for compatibility)
|
|
1226
|
+
* @private
|
|
1227
|
+
*/
|
|
1228
|
+
resolvePath(filePath, workingDir) {
|
|
1229
|
+
const resolved = path.isAbsolute(filePath)
|
|
1230
|
+
? path.normalize(filePath)
|
|
1231
|
+
: path.resolve(workingDir, filePath);
|
|
1232
|
+
|
|
1233
|
+
// Guard against the "doubled folder" trap. Reasoning models lose track
|
|
1234
|
+
// of the session CWD after a change-directory and re-prepend the
|
|
1235
|
+
// project folder name to every relative path — turning
|
|
1236
|
+
// CWD=".../foo" + "foo/bar/x.js" into ".../foo/foo/bar/x.js", which
|
|
1237
|
+
// the filesystem silently creates. We detect this by scanning the
|
|
1238
|
+
// FINAL resolved path for consecutive duplicate segments, so the
|
|
1239
|
+
// guard fires whether the duplication came from (a) relative prefix
|
|
1240
|
+
// (`foo/...` while inside `.../foo`), (b) relative mid-path
|
|
1241
|
+
// (`pkg/foo/foo/bar`), or (c) an absolute path written out in full
|
|
1242
|
+
// (`C:\...\foo\foo\bar`). Root-level duplicates like Windows drives
|
|
1243
|
+
// are ignored by design (`C:\C:\...` is impossible in normalized form).
|
|
1244
|
+
const segs = resolved.split(/[\\/]/).filter(Boolean);
|
|
1245
|
+
for (let i = 1; i < segs.length; i++) {
|
|
1246
|
+
if (segs[i].toLowerCase() === segs[i - 1].toLowerCase()) {
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
`Refused: resolved path contains a duplicated segment "${segs[i]}" (${resolved}). ` +
|
|
1249
|
+
`Current working directory: ${workingDir}. ` +
|
|
1250
|
+
`This almost always means the project folder name was prepended to a relative path while the CWD is already inside it. ` +
|
|
1251
|
+
`Drop the duplicated "${segs[i]}/" from the path — relative paths are resolved from the CWD — or pass an absolute path with no duplication.`
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
return resolved;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Validate path access using DirectoryAccessManager
|
|
1261
|
+
* @private
|
|
1262
|
+
*/
|
|
1263
|
+
validatePathAccess(fullPath, accessConfig, operation = 'read') {
|
|
1264
|
+
const accessResult = operation === 'write'
|
|
1265
|
+
? this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig)
|
|
1266
|
+
: this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1267
|
+
|
|
1268
|
+
if (!accessResult.allowed) {
|
|
1269
|
+
throw new Error(`${operation} access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return accessResult;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* Check if file extension is allowed
|
|
1277
|
+
* @private
|
|
1278
|
+
*/
|
|
1279
|
+
isAllowedFileExtension(filePath) {
|
|
1280
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
1281
|
+
|
|
1282
|
+
if (this.blockedExtensions.includes(ext)) {
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
if (this.allowedExtensions && !this.allowedExtensions.includes(ext)) {
|
|
1287
|
+
return false;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
return true;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Add operation to history
|
|
1295
|
+
* @private
|
|
1296
|
+
*/
|
|
1297
|
+
addToHistory(action, result, agentId) {
|
|
1298
|
+
const historyEntry = {
|
|
1299
|
+
timestamp: new Date().toISOString(),
|
|
1300
|
+
agentId,
|
|
1301
|
+
action: action.type,
|
|
1302
|
+
filePath: action.filePath || action.outputPath || action.directory,
|
|
1303
|
+
success: result.success,
|
|
1304
|
+
size: result.size
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
this.operationHistory.push(historyEntry);
|
|
1308
|
+
|
|
1309
|
+
// Keep only last 200 entries
|
|
1310
|
+
if (this.operationHistory.length > 200) {
|
|
1311
|
+
this.operationHistory = this.operationHistory.slice(-200);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Get supported actions for this tool
|
|
1317
|
+
* @returns {Array<string>} Array of supported action names
|
|
1318
|
+
*/
|
|
1319
|
+
getSupportedActions() {
|
|
1320
|
+
return [
|
|
1321
|
+
'read', 'write', 'append', 'delete', 'copy', 'move',
|
|
1322
|
+
'create-dir', 'list', 'exists', 'stats'
|
|
1323
|
+
];
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* Get parameter schema for validation
|
|
1328
|
+
* @returns {Object} Parameter schema
|
|
1329
|
+
*/
|
|
1330
|
+
getParameterSchema() {
|
|
1331
|
+
return {
|
|
1332
|
+
type: 'object',
|
|
1333
|
+
properties: {
|
|
1334
|
+
actions: {
|
|
1335
|
+
type: 'array',
|
|
1336
|
+
minItems: 1,
|
|
1337
|
+
items: {
|
|
1338
|
+
type: 'object',
|
|
1339
|
+
properties: {
|
|
1340
|
+
type: {
|
|
1341
|
+
type: 'string',
|
|
1342
|
+
enum: this.getSupportedActions()
|
|
1343
|
+
},
|
|
1344
|
+
filePath: { type: 'string' },
|
|
1345
|
+
outputPath: { type: 'string' },
|
|
1346
|
+
sourcePath: { type: 'string' },
|
|
1347
|
+
destPath: { type: 'string' },
|
|
1348
|
+
directory: { type: 'string' },
|
|
1349
|
+
content: { type: 'string' },
|
|
1350
|
+
encoding: { type: 'string' },
|
|
1351
|
+
createDirs: { type: 'boolean' }
|
|
1352
|
+
},
|
|
1353
|
+
required: ['type']
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
},
|
|
1357
|
+
required: ['actions']
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
/**
|
|
1362
|
+
* Get operation history for debugging
|
|
1363
|
+
* @returns {Array} Operation history
|
|
1364
|
+
*/
|
|
1365
|
+
getOperationHistory(agentId = null) {
|
|
1366
|
+
if (agentId) {
|
|
1367
|
+
return this.operationHistory.filter(entry => entry.agentId === agentId);
|
|
1368
|
+
}
|
|
1369
|
+
return [...this.operationHistory];
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1315
1373
|
export default FileSystemTool;
|