dominds 0.1.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/LICENSE +157 -0
- package/README.md +250 -0
- package/README.zh.md +161 -0
- package/dist/access-control.js +253 -0
- package/dist/cli/create.js +263 -0
- package/dist/cli/read.js +84 -0
- package/dist/cli/tui.js +199 -0
- package/dist/cli/webui.js +169 -0
- package/dist/cli.js +227 -0
- package/dist/dialog-factory.js +53 -0
- package/dist/dialog-global-registry.js +68 -0
- package/dist/dialog-instance-registry.js +78 -0
- package/dist/dialog-run-state.js +198 -0
- package/dist/dialog.js +1024 -0
- package/dist/evt-registry.js +103 -0
- package/dist/index.js +8 -0
- package/dist/llm/client.js +69 -0
- package/dist/llm/defaults.yaml +386 -0
- package/dist/llm/driver.js +3214 -0
- package/dist/llm/gen/anthropic.js +611 -0
- package/dist/llm/gen/codex.js +375 -0
- package/dist/llm/gen/mock.js +326 -0
- package/dist/llm/gen/openai.js +470 -0
- package/dist/llm/gen/registry.js +26 -0
- package/dist/llm/gen.js +2 -0
- package/dist/llm/tools-projection.js +37 -0
- package/dist/log.js +228 -0
- package/dist/mcp/config.js +230 -0
- package/dist/mcp/sdk-client.js +129 -0
- package/dist/mcp/server-runtime.js +57 -0
- package/dist/mcp/stdio-client.js +280 -0
- package/dist/mcp/supervisor.js +979 -0
- package/dist/mcp/tool-names.js +109 -0
- package/dist/minds/builtin/cmdr/persona.md +3 -0
- package/dist/minds/builtin/dijiang/knowledge.md +287 -0
- package/dist/minds/builtin/dijiang/persona.md +7 -0
- package/dist/minds/builtin/fuxi/persona.en.md +59 -0
- package/dist/minds/builtin/fuxi/persona.zh.md +49 -0
- package/dist/minds/builtin/pangu/persona.en.md +78 -0
- package/dist/minds/builtin/pangu/persona.zh.md +71 -0
- package/dist/minds/load.js +617 -0
- package/dist/minds/minds-i18n.js +131 -0
- package/dist/minds/system-prompt.js +281 -0
- package/dist/persistence.js +3128 -0
- package/dist/problems.js +109 -0
- package/dist/server/api-routes.js +1031 -0
- package/dist/server/auth.js +180 -0
- package/dist/server/mime-types.js +32 -0
- package/dist/server/prompts-routes.js +543 -0
- package/dist/server/server-core.js +235 -0
- package/dist/server/setup-routes.js +697 -0
- package/dist/server/static-server.js +132 -0
- package/dist/server/websocket-handler.js +1011 -0
- package/dist/server.js +164 -0
- package/dist/shared/async-fifo-mutex.js +36 -0
- package/dist/shared/diligence.js +20 -0
- package/dist/shared/dotenv.js +144 -0
- package/dist/shared/evt.js +195 -0
- package/dist/shared/i18n/driver-messages.js +267 -0
- package/dist/shared/i18n/text.js +9 -0
- package/dist/shared/i18n/tool-result-messages.js +51 -0
- package/dist/shared/rtws-cli.js +73 -0
- package/dist/shared/runtime-language.js +47 -0
- package/dist/shared/team-mgmt-manual.js +116 -0
- package/dist/shared/types/context-health.js +2 -0
- package/dist/shared/types/dialog.js +11 -0
- package/dist/shared/types/i18n.js +2 -0
- package/dist/shared/types/index.js +26 -0
- package/dist/shared/types/language.js +40 -0
- package/dist/shared/types/problems.js +2 -0
- package/dist/shared/types/prompts.js +2 -0
- package/dist/shared/types/q4h.js +7 -0
- package/dist/shared/types/run-state.js +8 -0
- package/dist/shared/types/setup.js +2 -0
- package/dist/shared/types/storage.js +10 -0
- package/dist/shared/types/tellask.js +8 -0
- package/dist/shared/types/tools-registry.js +2 -0
- package/dist/shared/types/wire.js +12 -0
- package/dist/shared/utils/fmt.js +9 -0
- package/dist/shared/utils/html.js +20 -0
- package/dist/shared/utils/id.js +18 -0
- package/dist/shared/utils/inter-dialog-format.js +101 -0
- package/dist/shared/utils/time.js +13 -0
- package/dist/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/static/assets/_baseUniq-Crfl3d5Y.js +661 -0
- package/dist/static/assets/_baseUniq-Crfl3d5Y.js.map +1 -0
- package/dist/static/assets/arc-CbA_x9GD.js +132 -0
- package/dist/static/assets/arc-CbA_x9GD.js.map +1 -0
- package/dist/static/assets/architectureDiagram-VXUJARFQ-lcFS8ZQJ.js +8685 -0
- package/dist/static/assets/architectureDiagram-VXUJARFQ-lcFS8ZQJ.js.map +1 -0
- package/dist/static/assets/blockDiagram-VD42YOAC-B3Q36qRc.js +3608 -0
- package/dist/static/assets/blockDiagram-VD42YOAC-B3Q36qRc.js.map +1 -0
- package/dist/static/assets/c4Diagram-YG6GDRKO-Mt-aq3VH.js +2482 -0
- package/dist/static/assets/c4Diagram-YG6GDRKO-Mt-aq3VH.js.map +1 -0
- package/dist/static/assets/channel-BVr1Yke-.js +8 -0
- package/dist/static/assets/channel-BVr1Yke-.js.map +1 -0
- package/dist/static/assets/chunk-4BX2VUAB-qCIn5Iic.js +17 -0
- package/dist/static/assets/chunk-4BX2VUAB-qCIn5Iic.js.map +1 -0
- package/dist/static/assets/chunk-55IACEB6-q172NeCV.js +14 -0
- package/dist/static/assets/chunk-55IACEB6-q172NeCV.js.map +1 -0
- package/dist/static/assets/chunk-B4BG7PRW-CMJmtYzq.js +1827 -0
- package/dist/static/assets/chunk-B4BG7PRW-CMJmtYzq.js.map +1 -0
- package/dist/static/assets/chunk-DI55MBZ5-DiuwwZPL.js +1916 -0
- package/dist/static/assets/chunk-DI55MBZ5-DiuwwZPL.js.map +1 -0
- package/dist/static/assets/chunk-FMBD7UC4-06sqZTTn.js +20 -0
- package/dist/static/assets/chunk-FMBD7UC4-06sqZTTn.js.map +1 -0
- package/dist/static/assets/chunk-QN33PNHL-CnpBNkpP.js +25 -0
- package/dist/static/assets/chunk-QN33PNHL-CnpBNkpP.js.map +1 -0
- package/dist/static/assets/chunk-QZHKN3VN-CNgjMR-e.js +18 -0
- package/dist/static/assets/chunk-QZHKN3VN-CNgjMR-e.js.map +1 -0
- package/dist/static/assets/chunk-TZMSLE5B-BxtzW6--.js +109 -0
- package/dist/static/assets/chunk-TZMSLE5B-BxtzW6--.js.map +1 -0
- package/dist/static/assets/classDiagram-2ON5EDUG-29huvmn-.js +23 -0
- package/dist/static/assets/classDiagram-2ON5EDUG-29huvmn-.js.map +1 -0
- package/dist/static/assets/classDiagram-v2-WZHVMYZB-29huvmn-.js +23 -0
- package/dist/static/assets/classDiagram-v2-WZHVMYZB-29huvmn-.js.map +1 -0
- package/dist/static/assets/clone-D2OgLSSn.js +9 -0
- package/dist/static/assets/clone-D2OgLSSn.js.map +1 -0
- package/dist/static/assets/cose-bilkent-S5V4N54A-BNegDCxl.js +4943 -0
- package/dist/static/assets/cose-bilkent-S5V4N54A-BNegDCxl.js.map +1 -0
- package/dist/static/assets/cytoscape.esm-Bm8DJGmZ.js +30240 -0
- package/dist/static/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -0
- package/dist/static/assets/dagre-6UL2VRFP-f1XrTRSn.js +695 -0
- package/dist/static/assets/dagre-6UL2VRFP-f1XrTRSn.js.map +1 -0
- package/dist/static/assets/defaultLocale-DVr69WTU.js +207 -0
- package/dist/static/assets/defaultLocale-DVr69WTU.js.map +1 -0
- package/dist/static/assets/diagram-PSM6KHXK-8w1WbeDi.js +849 -0
- package/dist/static/assets/diagram-PSM6KHXK-8w1WbeDi.js.map +1 -0
- package/dist/static/assets/diagram-QEK2KX5R-CF4wtMmR.js +303 -0
- package/dist/static/assets/diagram-QEK2KX5R-CF4wtMmR.js.map +1 -0
- package/dist/static/assets/diagram-S2PKOQOG-8p3Avgn2.js +213 -0
- package/dist/static/assets/diagram-S2PKOQOG-8p3Avgn2.js.map +1 -0
- package/dist/static/assets/erDiagram-Q2GNP2WA-BMKLxlM9.js +1159 -0
- package/dist/static/assets/erDiagram-Q2GNP2WA-BMKLxlM9.js.map +1 -0
- package/dist/static/assets/favicon-Cmg5RbCj.svg +8 -0
- package/dist/static/assets/flowDiagram-NV44I4VS-CgEuPNK2.js +2332 -0
- package/dist/static/assets/flowDiagram-NV44I4VS-CgEuPNK2.js.map +1 -0
- package/dist/static/assets/ganttDiagram-JELNMOA3-bJkDCf-9.js +3681 -0
- package/dist/static/assets/ganttDiagram-JELNMOA3-bJkDCf-9.js.map +1 -0
- package/dist/static/assets/gitGraphDiagram-NY62KEGX-4QE9kesp.js +1206 -0
- package/dist/static/assets/gitGraphDiagram-NY62KEGX-4QE9kesp.js.map +1 -0
- package/dist/static/assets/graph-CS0Pmm7c.js +597 -0
- package/dist/static/assets/graph-CS0Pmm7c.js.map +1 -0
- package/dist/static/assets/index-BS6HnGzC.js +112303 -0
- package/dist/static/assets/index-BS6HnGzC.js.map +1 -0
- package/dist/static/assets/index-DaIsSzC_.css +483 -0
- package/dist/static/assets/infoDiagram-WHAUD3N6-ypBcKfUs.js +34 -0
- package/dist/static/assets/infoDiagram-WHAUD3N6-ypBcKfUs.js.map +1 -0
- package/dist/static/assets/init-ZxktEp_H.js +17 -0
- package/dist/static/assets/init-ZxktEp_H.js.map +1 -0
- package/dist/static/assets/journeyDiagram-XKPGCS4Q-QnrxDowJ.js +1255 -0
- package/dist/static/assets/journeyDiagram-XKPGCS4Q-QnrxDowJ.js.map +1 -0
- package/dist/static/assets/kanban-definition-3W4ZIXB7-CfvEc4z5.js +1048 -0
- package/dist/static/assets/kanban-definition-3W4ZIXB7-CfvEc4z5.js.map +1 -0
- package/dist/static/assets/layout-8TGxpm23.js +2218 -0
- package/dist/static/assets/layout-8TGxpm23.js.map +1 -0
- package/dist/static/assets/linear-BATBPQQv.js +341 -0
- package/dist/static/assets/linear-BATBPQQv.js.map +1 -0
- package/dist/static/assets/min-B3oVH3AC.js +42 -0
- package/dist/static/assets/min-B3oVH3AC.js.map +1 -0
- package/dist/static/assets/mindmap-definition-VGOIOE7T-L7VLwwF8.js +1127 -0
- package/dist/static/assets/mindmap-definition-VGOIOE7T-L7VLwwF8.js.map +1 -0
- package/dist/static/assets/ordinal-CxptdPJm.js +77 -0
- package/dist/static/assets/ordinal-CxptdPJm.js.map +1 -0
- package/dist/static/assets/pieDiagram-ADFJNKIX-CFW3zIhM.js +241 -0
- package/dist/static/assets/pieDiagram-ADFJNKIX-CFW3zIhM.js.map +1 -0
- package/dist/static/assets/quadrantDiagram-AYHSOK5B-B7ssen3E.js +1338 -0
- package/dist/static/assets/quadrantDiagram-AYHSOK5B-B7ssen3E.js.map +1 -0
- package/dist/static/assets/requirementDiagram-UZGBJVZJ-D0v5BArv.js +1162 -0
- package/dist/static/assets/requirementDiagram-UZGBJVZJ-D0v5BArv.js.map +1 -0
- package/dist/static/assets/sankeyDiagram-TZEHDZUN-B7slncJe.js +1195 -0
- package/dist/static/assets/sankeyDiagram-TZEHDZUN-B7slncJe.js.map +1 -0
- package/dist/static/assets/sequenceDiagram-WL72ISMW-oXU2lRh_.js +3875 -0
- package/dist/static/assets/sequenceDiagram-WL72ISMW-oXU2lRh_.js.map +1 -0
- package/dist/static/assets/stateDiagram-FKZM4ZOC-CFYsEd0x.js +452 -0
- package/dist/static/assets/stateDiagram-FKZM4ZOC-CFYsEd0x.js.map +1 -0
- package/dist/static/assets/stateDiagram-v2-4FDKWEC3-C0UWaNA7.js +22 -0
- package/dist/static/assets/stateDiagram-v2-4FDKWEC3-C0UWaNA7.js.map +1 -0
- package/dist/static/assets/timeline-definition-IT6M3QCI-C3KODUrh.js +1223 -0
- package/dist/static/assets/timeline-definition-IT6M3QCI-C3KODUrh.js.map +1 -0
- package/dist/static/assets/treemap-KMMF4GRG-DAGDLhj2.js +18753 -0
- package/dist/static/assets/treemap-KMMF4GRG-DAGDLhj2.js.map +1 -0
- package/dist/static/assets/xychartDiagram-PRI3JC2R-C0J9iwTO.js +1888 -0
- package/dist/static/assets/xychartDiagram-PRI3JC2R-C0J9iwTO.js.map +1 -0
- package/dist/static/index.html +71 -0
- package/dist/static/testing/dom-observation-utils.js +425 -0
- package/dist/static/testing/e2e-test-helper.js +3119 -0
- package/dist/team.js +1160 -0
- package/dist/tellask.js +431 -0
- package/dist/tool.js +150 -0
- package/dist/tools/apply-patch.js +542 -0
- package/dist/tools/builtins.js +196 -0
- package/dist/tools/context-health.js +177 -0
- package/dist/tools/ctrl.js +478 -0
- package/dist/tools/diag.js +583 -0
- package/dist/tools/env.js +184 -0
- package/dist/tools/fs.js +818 -0
- package/dist/tools/mcp.js +138 -0
- package/dist/tools/mem.js +349 -0
- package/dist/tools/os.js +751 -0
- package/dist/tools/prompts/team_mgmt.en.md +70 -0
- package/dist/tools/prompts/team_mgmt.zh.md +70 -0
- package/dist/tools/prompts/ws_mod.en.md +86 -0
- package/dist/tools/prompts/ws_mod.zh.md +87 -0
- package/dist/tools/registry-snapshot.js +31 -0
- package/dist/tools/registry.js +121 -0
- package/dist/tools/ripgrep.js +678 -0
- package/dist/tools/team-mgmt.js +3300 -0
- package/dist/tools/txt.js +3178 -0
- package/dist/utils/id.js +72 -0
- package/dist/utils/task-doc.js +236 -0
- package/dist/utils/task-package.js +522 -0
- package/dist/utils/taskdoc-search.js +280 -0
- package/dist/utils/taskdoc.js +400 -0
- package/package.json +69 -0
package/dist/tools/fs.js
ADDED
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.moveDirTool = exports.moveFileTool = exports.mkDirTool = exports.rmFileTool = exports.rmDirTool = exports.listDirTool = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Module: tools/fs
|
|
9
|
+
*
|
|
10
|
+
* Filesystem tools: list directories, remove directories/files, create/move paths.
|
|
11
|
+
* Includes helpers for text-file detection and line counting.
|
|
12
|
+
*/
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const readline_1 = require("readline");
|
|
17
|
+
const access_control_1 = require("../access-control");
|
|
18
|
+
const log_1 = require("../log");
|
|
19
|
+
const runtime_language_1 = require("../shared/runtime-language");
|
|
20
|
+
function formatSize(bytes) {
|
|
21
|
+
if (bytes === 0)
|
|
22
|
+
return '0 B';
|
|
23
|
+
const k = 1024;
|
|
24
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
25
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
26
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
27
|
+
}
|
|
28
|
+
function isTextFile(filename) {
|
|
29
|
+
// prettier-ignore
|
|
30
|
+
const textExtensions = [
|
|
31
|
+
'.txt', '.md', '.js', '.ts', '.jsx', '.tsx', '.json', '.xml', '.html', '.htm',
|
|
32
|
+
'.css', '.scss', '.sass', '.less', '.py', '.java', '.c', '.cpp', '.h', '.hpp',
|
|
33
|
+
'.cs', '.php', '.rb', '.go', '.rs', '.swift', '.kt', '.scala', '.sh', '.bash',
|
|
34
|
+
'.zsh', '.fish', '.ps1', '.bat', '.cmd', '.yml', '.yaml', '.toml', '.ini',
|
|
35
|
+
'.cfg', '.conf', '.config', '.env', '.gitignore', '.gitattributes', '.editorconfig',
|
|
36
|
+
'.prettierrc', '.eslintrc', '.babelrc', '.dockerignore', '.dockerfile', '.makefile',
|
|
37
|
+
'.cmake', '.sql', '.graphql', '.gql', '.vue', '.svelte', '.astro', '.r', '.R',
|
|
38
|
+
'.m', '.mm', '.pl', '.pm', '.lua', '.vim', '.vimrc', '.tmux', '.zshrc',
|
|
39
|
+
'.bashrc', '.profile', '.aliases', '.functions', '.exports', '.path', '.extra', '.log',
|
|
40
|
+
];
|
|
41
|
+
const ext = path_1.default.extname(filename).toLowerCase();
|
|
42
|
+
const basename = path_1.default.basename(filename).toLowerCase();
|
|
43
|
+
// Check by extension
|
|
44
|
+
if (textExtensions.includes(ext)) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
// Check by common filenames without extensions
|
|
48
|
+
// prettier-ignore
|
|
49
|
+
const textFilenames = [
|
|
50
|
+
'readme', 'license', 'changelog', 'contributing', 'authors', 'contributors',
|
|
51
|
+
'copying', 'install', 'news', 'todo', 'makefile', 'dockerfile', 'gemfile',
|
|
52
|
+
'rakefile', 'procfile', 'vagrantfile', 'gruntfile', 'gulpfile', 'webpack',
|
|
53
|
+
];
|
|
54
|
+
return textFilenames.includes(basename) || textFilenames.includes(basename.split('.')[0]);
|
|
55
|
+
}
|
|
56
|
+
async function countLines(filePath) {
|
|
57
|
+
try {
|
|
58
|
+
const fileStream = (0, fs_1.createReadStream)(filePath, { encoding: 'utf-8' });
|
|
59
|
+
const rl = (0, readline_1.createInterface)({
|
|
60
|
+
input: fileStream,
|
|
61
|
+
crlfDelay: Infinity, // Handle Windows line endings properly
|
|
62
|
+
});
|
|
63
|
+
let lineCount = 0;
|
|
64
|
+
for await (const line of rl) {
|
|
65
|
+
lineCount++;
|
|
66
|
+
}
|
|
67
|
+
return lineCount;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
log_1.log.warn(`Failed to count lines in file ${filePath}:`, err);
|
|
71
|
+
return 0; // Return 0 if file can't be read as text
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.listDirTool = {
|
|
75
|
+
type: 'func',
|
|
76
|
+
name: 'list_dir',
|
|
77
|
+
description: 'List directory contents relative to workspace with detailed information (sizes, line counts for text files, symlink targets).',
|
|
78
|
+
descriptionI18n: {
|
|
79
|
+
en: 'List directory contents relative to workspace with detailed information (sizes, line counts for text files, symlink targets).',
|
|
80
|
+
zh: '列出工作区内目录内容(包含大小、文本文件行数、符号链接目标等信息)。',
|
|
81
|
+
},
|
|
82
|
+
parameters: {
|
|
83
|
+
type: 'object',
|
|
84
|
+
additionalProperties: false,
|
|
85
|
+
properties: {
|
|
86
|
+
path: {
|
|
87
|
+
type: 'string',
|
|
88
|
+
description: "Workspace-relative directory path. Defaults to '.'.",
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
argsValidation: 'dominds',
|
|
93
|
+
call: async (_dlg, caller, args) => {
|
|
94
|
+
const workLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
95
|
+
const labels = workLanguage === 'zh'
|
|
96
|
+
? {
|
|
97
|
+
accessDenied: '❌ **访问被拒绝**\n\n路径必须位于工作区内',
|
|
98
|
+
notFound: (p) => `❌ **未找到**\n\n目录 \`${p}\` 不存在。`,
|
|
99
|
+
notDir: (p) => `❌ **错误**\n\n路径 \`${p}\` 不是目录。`,
|
|
100
|
+
readDirFailed: (msg) => `❌ **错误**\n\n读取目录失败:${msg}`,
|
|
101
|
+
dirHeader: '📁 **目录:**',
|
|
102
|
+
emptyDir: '_此目录为空。_',
|
|
103
|
+
table: {
|
|
104
|
+
name: '名称',
|
|
105
|
+
type: '类型',
|
|
106
|
+
size: '大小',
|
|
107
|
+
lines: '行数',
|
|
108
|
+
target: '目标',
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
accessDenied: '❌ **Access Denied**\n\nPath must be within workspace',
|
|
113
|
+
notFound: (p) => `❌ **Not Found**\n\nDirectory \`${p}\` does not exist.`,
|
|
114
|
+
notDir: (p) => `❌ **Error**\n\nPath \`${p}\` is not a directory.`,
|
|
115
|
+
readDirFailed: (msg) => `❌ **Error**\n\nFailed to read directory: ${msg}`,
|
|
116
|
+
dirHeader: '📁 **Directory:**',
|
|
117
|
+
emptyDir: '_This directory is empty._',
|
|
118
|
+
table: {
|
|
119
|
+
name: 'Name',
|
|
120
|
+
type: 'Type',
|
|
121
|
+
size: 'Size',
|
|
122
|
+
lines: 'Lines',
|
|
123
|
+
target: 'Target',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
let rel = '.';
|
|
127
|
+
const pathValue = args['path'];
|
|
128
|
+
if (typeof pathValue === 'string' && pathValue.trim() !== '')
|
|
129
|
+
rel = pathValue.trim();
|
|
130
|
+
// Resolve path relative to current working directory (workspace)
|
|
131
|
+
const dir = path_1.default.resolve(process.cwd(), rel);
|
|
132
|
+
// Basic security check - ensure path is within workspace
|
|
133
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
134
|
+
if (!dir.startsWith(cwd)) {
|
|
135
|
+
const content = labels.accessDenied;
|
|
136
|
+
return content;
|
|
137
|
+
}
|
|
138
|
+
// Check member access permissions
|
|
139
|
+
if (!(0, access_control_1.hasReadAccess)(caller, rel)) {
|
|
140
|
+
const content = (0, access_control_1.getAccessDeniedMessage)('read', rel, workLanguage);
|
|
141
|
+
return content;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
try {
|
|
145
|
+
const stats = await promises_1.default.lstat(dir);
|
|
146
|
+
if (!stats.isDirectory()) {
|
|
147
|
+
const content = labels.notDir(rel);
|
|
148
|
+
return content;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
if (typeof error === 'object' &&
|
|
153
|
+
error !== null &&
|
|
154
|
+
'code' in error &&
|
|
155
|
+
error.code === 'ENOENT') {
|
|
156
|
+
const content = labels.notFound(rel);
|
|
157
|
+
return content;
|
|
158
|
+
}
|
|
159
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
160
|
+
const content = labels.readDirFailed(msg);
|
|
161
|
+
return content;
|
|
162
|
+
}
|
|
163
|
+
const entries = await promises_1.default.readdir(dir, { withFileTypes: true });
|
|
164
|
+
const data = [];
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
const entryPath = path_1.default.join(dir, entry.name);
|
|
167
|
+
const dirEntry = {
|
|
168
|
+
name: entry.name,
|
|
169
|
+
type: 'other',
|
|
170
|
+
};
|
|
171
|
+
try {
|
|
172
|
+
const stats = await promises_1.default.lstat(entryPath);
|
|
173
|
+
if (entry.isDirectory()) {
|
|
174
|
+
dirEntry.type = 'dir';
|
|
175
|
+
dirEntry.size = stats.size;
|
|
176
|
+
}
|
|
177
|
+
else if (entry.isFile()) {
|
|
178
|
+
dirEntry.type = 'file';
|
|
179
|
+
dirEntry.size = stats.size;
|
|
180
|
+
// Count lines for text files
|
|
181
|
+
if (isTextFile(entry.name)) {
|
|
182
|
+
dirEntry.lines = await countLines(entryPath);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (entry.isSymbolicLink()) {
|
|
186
|
+
dirEntry.type = 'symlink';
|
|
187
|
+
dirEntry.size = stats.size;
|
|
188
|
+
try {
|
|
189
|
+
const target = await promises_1.default.readlink(entryPath);
|
|
190
|
+
dirEntry.target = target;
|
|
191
|
+
// If symlink points to a text file, count lines from the target
|
|
192
|
+
try {
|
|
193
|
+
const targetStats = await promises_1.default.stat(entryPath); // Follow the symlink
|
|
194
|
+
if (targetStats.isFile() && isTextFile(entry.name)) {
|
|
195
|
+
dirEntry.lines = await countLines(entryPath);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
log_1.log.warn(`Failed to stat symlink target ${entryPath}:`, err);
|
|
200
|
+
// Target doesn't exist or can't be accessed
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
log_1.log.warn(`Failed to read symlink ${entryPath}:`, err);
|
|
205
|
+
dirEntry.target = '<unreadable>';
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
dirEntry.type = 'other';
|
|
210
|
+
dirEntry.size = stats.size;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
// If we can't stat the entry, just include basic info
|
|
215
|
+
if (entry.isDirectory()) {
|
|
216
|
+
dirEntry.type = 'dir';
|
|
217
|
+
}
|
|
218
|
+
else if (entry.isFile()) {
|
|
219
|
+
dirEntry.type = 'file';
|
|
220
|
+
}
|
|
221
|
+
else if (entry.isSymbolicLink()) {
|
|
222
|
+
dirEntry.type = 'symlink';
|
|
223
|
+
dirEntry.target = '<error>';
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
data.push(dirEntry);
|
|
227
|
+
}
|
|
228
|
+
const relativeDir = path_1.default.relative(cwd, dir) || '.';
|
|
229
|
+
// Create markdown table for directory entries
|
|
230
|
+
let markdown = `${labels.dirHeader} \`${relativeDir}\`\n\n`;
|
|
231
|
+
if (data.length === 0) {
|
|
232
|
+
markdown += labels.emptyDir;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
markdown += `| ${labels.table.name} | ${labels.table.type} | ${labels.table.size} | ${labels.table.lines} | ${labels.table.target} |\n`;
|
|
236
|
+
markdown += '|------|------|------|-------|--------|\n';
|
|
237
|
+
for (const entry of data) {
|
|
238
|
+
const typeIcon = entry.type === 'dir'
|
|
239
|
+
? '📁'
|
|
240
|
+
: entry.type === 'file'
|
|
241
|
+
? '📄'
|
|
242
|
+
: entry.type === 'symlink'
|
|
243
|
+
? '🔗'
|
|
244
|
+
: '❓';
|
|
245
|
+
const sizeStr = entry.size ? formatSize(entry.size) : '-';
|
|
246
|
+
const linesStr = entry.lines ? entry.lines.toString() : '-';
|
|
247
|
+
const targetStr = entry.target ? `→ ${entry.target}` : '-';
|
|
248
|
+
markdown += `| ${typeIcon} \`${entry.name}\` | ${entry.type} | ${sizeStr} | ${linesStr} | ${targetStr} |\n`;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return markdown;
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
if (typeof error === 'object' &&
|
|
255
|
+
error !== null &&
|
|
256
|
+
'code' in error &&
|
|
257
|
+
error.code === 'ENOENT') {
|
|
258
|
+
const content = labels.notFound(rel);
|
|
259
|
+
return content;
|
|
260
|
+
}
|
|
261
|
+
if (typeof error === 'object' &&
|
|
262
|
+
error !== null &&
|
|
263
|
+
'code' in error &&
|
|
264
|
+
error.code === 'ENOTDIR') {
|
|
265
|
+
const content = labels.notDir(rel);
|
|
266
|
+
return content;
|
|
267
|
+
}
|
|
268
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
269
|
+
const content = labels.readDirFailed(msg);
|
|
270
|
+
return content;
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
exports.rmDirTool = {
|
|
275
|
+
type: 'func',
|
|
276
|
+
name: 'rm_dir',
|
|
277
|
+
description: 'Remove a directory relative to workspace.',
|
|
278
|
+
descriptionI18n: {
|
|
279
|
+
en: 'Remove a directory relative to workspace.',
|
|
280
|
+
zh: '删除工作区内目录。',
|
|
281
|
+
},
|
|
282
|
+
parameters: {
|
|
283
|
+
type: 'object',
|
|
284
|
+
additionalProperties: false,
|
|
285
|
+
required: ['path'],
|
|
286
|
+
properties: {
|
|
287
|
+
path: { type: 'string', description: 'Workspace-relative directory path.' },
|
|
288
|
+
recursive: {
|
|
289
|
+
type: 'boolean',
|
|
290
|
+
description: 'When true, remove directory and all contents.',
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
argsValidation: 'dominds',
|
|
295
|
+
call: async (_dlg, caller, args) => {
|
|
296
|
+
const workLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
297
|
+
const labels = workLanguage === 'zh'
|
|
298
|
+
? {
|
|
299
|
+
formatError: '请使用正确的目录删除参数。\n\n**期望参数:** `{ "path": "<path>", "recursive": true|false }`\n\n**示例:**\n```json\n{ \"path\": \"temp\", \"recursive\": true }\n```',
|
|
300
|
+
dirPathRequired: '❌ **错误**\n\n需要提供目录路径。',
|
|
301
|
+
pathMustBeWithinWorkspace: '❌ **错误**\n\n路径必须位于工作区内。',
|
|
302
|
+
notDir: (p) => `❌ **错误**\n\n\`${p}\` 不是目录。`,
|
|
303
|
+
notEmpty: (p) => `❌ **错误**\n\n目录 \`${p}\` 非空。请设置 \`recursive: true\` 删除非空目录。`,
|
|
304
|
+
removed: (p) => `✅ 已删除目录:\`${p}\`。`,
|
|
305
|
+
doesNotExist: (p) => `❌ **未找到**\n\n目录 \`${p}\` 不存在。`,
|
|
306
|
+
removeFailed: (msg) => `❌ **错误**\n\n删除目录失败:${msg}`,
|
|
307
|
+
}
|
|
308
|
+
: {
|
|
309
|
+
formatError: 'Please use the correct arguments for removing directories.\n\n**Expected args:** `{ "path": "<path>", "recursive": true|false }`\n\n**Example:**\n```json\n{ \"path\": \"temp\", \"recursive\": true }\n```',
|
|
310
|
+
dirPathRequired: '❌ **Error**\n\nDirectory path is required.',
|
|
311
|
+
pathMustBeWithinWorkspace: '❌ **Error**\n\nPath must be within workspace.',
|
|
312
|
+
notDir: (p) => `❌ **Error**\n\n\`${p}\` is not a directory.`,
|
|
313
|
+
notEmpty: (p) => `❌ **Error**\n\nDirectory \`${p}\` is not empty. Set \`recursive: true\` to remove non-empty directories.`,
|
|
314
|
+
removed: (p) => `✅ Removed directory: \`${p}\`.`,
|
|
315
|
+
doesNotExist: (p) => `❌ **Not Found**\n\nDirectory \`${p}\` does not exist.`,
|
|
316
|
+
removeFailed: (msg) => `❌ **Error**\n\nError removing directory: ${msg}`,
|
|
317
|
+
};
|
|
318
|
+
const pathValue = args['path'];
|
|
319
|
+
const rel = typeof pathValue === 'string' ? pathValue.trim() : '';
|
|
320
|
+
if (!rel)
|
|
321
|
+
return labels.dirPathRequired;
|
|
322
|
+
const recursiveValue = args['recursive'];
|
|
323
|
+
const recursive = recursiveValue === undefined ? false : recursiveValue === true ? true : false;
|
|
324
|
+
if (recursiveValue !== undefined && typeof recursiveValue !== 'boolean')
|
|
325
|
+
return labels.formatError;
|
|
326
|
+
// Resolve path relative to current working directory (workspace)
|
|
327
|
+
const targetPath = path_1.default.resolve(process.cwd(), rel);
|
|
328
|
+
// Basic security check - ensure path is within workspace
|
|
329
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
330
|
+
if (!targetPath.startsWith(cwd)) {
|
|
331
|
+
return labels.pathMustBeWithinWorkspace;
|
|
332
|
+
}
|
|
333
|
+
// Check member write access permissions
|
|
334
|
+
if (!(0, access_control_1.hasWriteAccess)(caller, rel)) {
|
|
335
|
+
return (0, access_control_1.getAccessDeniedMessage)('write', rel, workLanguage);
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
// Check if path exists and is a directory
|
|
339
|
+
const stats = await promises_1.default.lstat(targetPath);
|
|
340
|
+
if (!stats.isDirectory()) {
|
|
341
|
+
return labels.notDir(rel);
|
|
342
|
+
}
|
|
343
|
+
// Check if directory is empty when not using recursive
|
|
344
|
+
if (!recursive) {
|
|
345
|
+
const entries = await promises_1.default.readdir(targetPath);
|
|
346
|
+
if (entries.length > 0) {
|
|
347
|
+
return labels.notEmpty(rel);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Remove the directory
|
|
351
|
+
await promises_1.default.rmdir(targetPath, { recursive });
|
|
352
|
+
return labels.removed(rel);
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
if (typeof error === 'object' &&
|
|
356
|
+
error !== null &&
|
|
357
|
+
'code' in error &&
|
|
358
|
+
error.code === 'ENOENT') {
|
|
359
|
+
return labels.doesNotExist(rel);
|
|
360
|
+
}
|
|
361
|
+
return labels.removeFailed(error instanceof Error ? error.message : String(error));
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
exports.rmFileTool = {
|
|
366
|
+
type: 'func',
|
|
367
|
+
name: 'rm_file',
|
|
368
|
+
description: 'Remove a file relative to workspace.',
|
|
369
|
+
descriptionI18n: {
|
|
370
|
+
en: 'Remove a file relative to workspace.',
|
|
371
|
+
zh: '删除工作区内文件。',
|
|
372
|
+
},
|
|
373
|
+
parameters: {
|
|
374
|
+
type: 'object',
|
|
375
|
+
additionalProperties: false,
|
|
376
|
+
required: ['path'],
|
|
377
|
+
properties: {
|
|
378
|
+
path: { type: 'string', description: 'Workspace-relative file path.' },
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
argsValidation: 'dominds',
|
|
382
|
+
call: async (_dlg, caller, args) => {
|
|
383
|
+
const workLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
384
|
+
const labels = workLanguage === 'zh'
|
|
385
|
+
? {
|
|
386
|
+
formatError: '请使用正确的文件删除参数。\n\n**期望参数:** `{ \"path\": \"<path>\" }`\n\n**示例:**\n```json\n{ \"path\": \"temp/old-file.txt\" }\n```',
|
|
387
|
+
filePathRequired: '❌ **错误**\n\n需要提供文件路径。',
|
|
388
|
+
pathMustBeWithinWorkspace: '❌ **错误**\n\n路径必须位于工作区内。',
|
|
389
|
+
notFile: (p) => `❌ **错误**\n\n\`${p}\` 不是文件。`,
|
|
390
|
+
removed: (p) => `✅ 已删除文件:\`${p}\`。`,
|
|
391
|
+
doesNotExist: (p) => `❌ **未找到**\n\n文件 \`${p}\` 不存在。`,
|
|
392
|
+
removeFailed: (msg) => `❌ **错误**\n\n删除文件失败:${msg}`,
|
|
393
|
+
}
|
|
394
|
+
: {
|
|
395
|
+
formatError: 'Please use the correct arguments for removing files.\n\n**Expected args:** `{ \"path\": \"<path>\" }`\n\n**Example:**\n```json\n{ \"path\": \"temp/old-file.txt\" }\n```',
|
|
396
|
+
filePathRequired: '❌ **Error**\n\nFile path is required.',
|
|
397
|
+
pathMustBeWithinWorkspace: '❌ **Error**\n\nPath must be within workspace.',
|
|
398
|
+
notFile: (p) => `❌ **Error**\n\n\`${p}\` is not a file.`,
|
|
399
|
+
removed: (p) => `✅ Removed file: \`${p}\`.`,
|
|
400
|
+
doesNotExist: (p) => `❌ **Not Found**\n\nFile \`${p}\` does not exist.`,
|
|
401
|
+
removeFailed: (msg) => `❌ **Error**\n\nError removing file: ${msg}`,
|
|
402
|
+
};
|
|
403
|
+
const pathValue = args['path'];
|
|
404
|
+
const rel = typeof pathValue === 'string' ? pathValue.trim() : '';
|
|
405
|
+
if (!rel)
|
|
406
|
+
return labels.filePathRequired;
|
|
407
|
+
// Resolve path relative to current working directory (workspace)
|
|
408
|
+
const targetPath = path_1.default.resolve(process.cwd(), rel);
|
|
409
|
+
// Basic security check - ensure path is within workspace
|
|
410
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
411
|
+
if (!targetPath.startsWith(cwd)) {
|
|
412
|
+
return labels.pathMustBeWithinWorkspace;
|
|
413
|
+
}
|
|
414
|
+
// Check member write access permissions
|
|
415
|
+
if (!(0, access_control_1.hasWriteAccess)(caller, rel)) {
|
|
416
|
+
return (0, access_control_1.getAccessDeniedMessage)('write', rel, workLanguage);
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
// Check if path exists and is a file
|
|
420
|
+
const stats = await promises_1.default.lstat(targetPath);
|
|
421
|
+
if (!stats.isFile()) {
|
|
422
|
+
return labels.notFile(rel);
|
|
423
|
+
}
|
|
424
|
+
// Remove the file
|
|
425
|
+
await promises_1.default.unlink(targetPath);
|
|
426
|
+
return labels.removed(rel);
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
if (typeof error === 'object' &&
|
|
430
|
+
error !== null &&
|
|
431
|
+
'code' in error &&
|
|
432
|
+
error.code === 'ENOENT') {
|
|
433
|
+
return labels.doesNotExist(rel);
|
|
434
|
+
}
|
|
435
|
+
return labels.removeFailed(error instanceof Error ? error.message : String(error));
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
function yamlQuote(value) {
|
|
440
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
441
|
+
}
|
|
442
|
+
function formatYamlCodeBlock(yaml) {
|
|
443
|
+
return `\`\`\`yaml\n${yaml}\n\`\`\``;
|
|
444
|
+
}
|
|
445
|
+
async function countDirEntries(absPath) {
|
|
446
|
+
let count = 0;
|
|
447
|
+
const entries = await promises_1.default.readdir(absPath, { withFileTypes: true });
|
|
448
|
+
for (const entry of entries) {
|
|
449
|
+
count++;
|
|
450
|
+
if (entry.isDirectory()) {
|
|
451
|
+
count += await countDirEntries(path_1.default.join(absPath, entry.name));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return count;
|
|
455
|
+
}
|
|
456
|
+
exports.mkDirTool = {
|
|
457
|
+
type: 'func',
|
|
458
|
+
name: 'mk_dir',
|
|
459
|
+
description: 'Create a directory relative to workspace.',
|
|
460
|
+
descriptionI18n: { en: 'Create a directory relative to workspace.', zh: '创建工作区内目录。' },
|
|
461
|
+
parameters: {
|
|
462
|
+
type: 'object',
|
|
463
|
+
additionalProperties: false,
|
|
464
|
+
required: ['path'],
|
|
465
|
+
properties: {
|
|
466
|
+
path: { type: 'string', description: 'Workspace-relative directory path.' },
|
|
467
|
+
parents: { type: 'boolean', description: 'Create parent directories as needed.' },
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
argsValidation: 'dominds',
|
|
471
|
+
call: async (_dlg, caller, args) => {
|
|
472
|
+
const workLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
473
|
+
const pathValue = args['path'];
|
|
474
|
+
const rel = typeof pathValue === 'string' ? pathValue.trim() : '';
|
|
475
|
+
if (!rel) {
|
|
476
|
+
const yaml = [
|
|
477
|
+
`status: error`,
|
|
478
|
+
`error: PATH_REQUIRED`,
|
|
479
|
+
`summary: ${yamlQuote(workLanguage === 'zh' ? 'Mk-dir failed: path required.' : 'Mk-dir failed: path required.')}`,
|
|
480
|
+
].join('\n');
|
|
481
|
+
return formatYamlCodeBlock(yaml);
|
|
482
|
+
}
|
|
483
|
+
const parentsValue = args['parents'];
|
|
484
|
+
const parents = parentsValue === undefined
|
|
485
|
+
? true
|
|
486
|
+
: parentsValue === true
|
|
487
|
+
? true
|
|
488
|
+
: parentsValue === false
|
|
489
|
+
? false
|
|
490
|
+
: true;
|
|
491
|
+
if (parentsValue !== undefined && typeof parentsValue !== 'boolean') {
|
|
492
|
+
const yaml = [
|
|
493
|
+
`status: error`,
|
|
494
|
+
`error: INVALID_ARGS`,
|
|
495
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
496
|
+
? 'Mk-dir failed: invalid args. Expected { path: string, parents?: boolean }.'
|
|
497
|
+
: 'Mk-dir failed: invalid args. Expected { path: string, parents?: boolean }.')}`,
|
|
498
|
+
].join('\n');
|
|
499
|
+
return formatYamlCodeBlock(yaml);
|
|
500
|
+
}
|
|
501
|
+
const targetPath = path_1.default.resolve(process.cwd(), rel);
|
|
502
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
503
|
+
if (!targetPath.startsWith(cwd)) {
|
|
504
|
+
const yaml = [
|
|
505
|
+
`status: error`,
|
|
506
|
+
`path: ${yamlQuote(rel)}`,
|
|
507
|
+
`error: PATH_OUTSIDE_WORKSPACE`,
|
|
508
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
509
|
+
? 'Mk-dir failed: path must be within workspace.'
|
|
510
|
+
: 'Mk-dir failed: path must be within workspace.')}`,
|
|
511
|
+
].join('\n');
|
|
512
|
+
return formatYamlCodeBlock(yaml);
|
|
513
|
+
}
|
|
514
|
+
if (!(0, access_control_1.hasWriteAccess)(caller, rel)) {
|
|
515
|
+
return (0, access_control_1.getAccessDeniedMessage)('write', rel, workLanguage);
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
const st = await promises_1.default.lstat(targetPath).catch((err) => {
|
|
519
|
+
if (typeof err === 'object' &&
|
|
520
|
+
err !== null &&
|
|
521
|
+
'code' in err &&
|
|
522
|
+
err.code === 'ENOENT') {
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
525
|
+
throw err;
|
|
526
|
+
});
|
|
527
|
+
if (st) {
|
|
528
|
+
if (!st.isDirectory()) {
|
|
529
|
+
const yaml = [
|
|
530
|
+
`status: error`,
|
|
531
|
+
`path: ${yamlQuote(rel)}`,
|
|
532
|
+
`error: PATH_EXISTS_NOT_DIR`,
|
|
533
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
534
|
+
? 'Mk-dir failed: path exists and is not a directory.'
|
|
535
|
+
: 'Mk-dir failed: path exists and is not a directory.')}`,
|
|
536
|
+
].join('\n');
|
|
537
|
+
return formatYamlCodeBlock(yaml);
|
|
538
|
+
}
|
|
539
|
+
const yaml = [
|
|
540
|
+
`status: ok`,
|
|
541
|
+
`path: ${yamlQuote(rel)}`,
|
|
542
|
+
`created: false`,
|
|
543
|
+
`summary: ${yamlQuote(`Mk-dir: ${rel} (parents=${parents}).`)}`,
|
|
544
|
+
].join('\n');
|
|
545
|
+
return formatYamlCodeBlock(yaml);
|
|
546
|
+
}
|
|
547
|
+
await promises_1.default.mkdir(targetPath, { recursive: parents });
|
|
548
|
+
const yaml = [
|
|
549
|
+
`status: ok`,
|
|
550
|
+
`path: ${yamlQuote(rel)}`,
|
|
551
|
+
`created: true`,
|
|
552
|
+
`summary: ${yamlQuote(`Mk-dir: ${rel} (parents=${parents}).`)}`,
|
|
553
|
+
].join('\n');
|
|
554
|
+
return formatYamlCodeBlock(yaml);
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
const yaml = [
|
|
558
|
+
`status: error`,
|
|
559
|
+
`path: ${yamlQuote(rel)}`,
|
|
560
|
+
`error: FAILED`,
|
|
561
|
+
`summary: ${yamlQuote(error instanceof Error ? error.message : String(error))}`,
|
|
562
|
+
].join('\n');
|
|
563
|
+
return formatYamlCodeBlock(yaml);
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
};
|
|
567
|
+
exports.moveFileTool = {
|
|
568
|
+
type: 'func',
|
|
569
|
+
name: 'move_file',
|
|
570
|
+
description: 'Move/rename a file relative to workspace.',
|
|
571
|
+
descriptionI18n: {
|
|
572
|
+
en: 'Move/rename a file relative to workspace.',
|
|
573
|
+
zh: '移动/重命名工作区内文件。',
|
|
574
|
+
},
|
|
575
|
+
parameters: {
|
|
576
|
+
type: 'object',
|
|
577
|
+
additionalProperties: false,
|
|
578
|
+
required: ['from', 'to'],
|
|
579
|
+
properties: {
|
|
580
|
+
from: { type: 'string', description: 'Workspace-relative source file path.' },
|
|
581
|
+
to: { type: 'string', description: 'Workspace-relative destination file path.' },
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
argsValidation: 'dominds',
|
|
585
|
+
call: async (_dlg, caller, args) => {
|
|
586
|
+
const workLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
587
|
+
const fromValue = args['from'];
|
|
588
|
+
const toValue = args['to'];
|
|
589
|
+
const from = typeof fromValue === 'string' ? fromValue.trim() : '';
|
|
590
|
+
const to = typeof toValue === 'string' ? toValue.trim() : '';
|
|
591
|
+
if (!from || !to) {
|
|
592
|
+
const yaml = [
|
|
593
|
+
`status: error`,
|
|
594
|
+
`error: INVALID_ARGS`,
|
|
595
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
596
|
+
? 'Move-file failed: from/to required.'
|
|
597
|
+
: 'Move-file failed: from/to required.')}`,
|
|
598
|
+
].join('\n');
|
|
599
|
+
return formatYamlCodeBlock(yaml);
|
|
600
|
+
}
|
|
601
|
+
const absFrom = path_1.default.resolve(process.cwd(), from);
|
|
602
|
+
const absTo = path_1.default.resolve(process.cwd(), to);
|
|
603
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
604
|
+
if (!absFrom.startsWith(cwd) || !absTo.startsWith(cwd)) {
|
|
605
|
+
const yaml = [
|
|
606
|
+
`status: error`,
|
|
607
|
+
`from: ${yamlQuote(from)}`,
|
|
608
|
+
`to: ${yamlQuote(to)}`,
|
|
609
|
+
`error: PATH_OUTSIDE_WORKSPACE`,
|
|
610
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
611
|
+
? 'Move-file failed: paths must be within workspace.'
|
|
612
|
+
: 'Move-file failed: paths must be within workspace.')}`,
|
|
613
|
+
].join('\n');
|
|
614
|
+
return formatYamlCodeBlock(yaml);
|
|
615
|
+
}
|
|
616
|
+
if (!(0, access_control_1.hasWriteAccess)(caller, from) || !(0, access_control_1.hasWriteAccess)(caller, to)) {
|
|
617
|
+
return (0, access_control_1.getAccessDeniedMessage)('write', from, workLanguage);
|
|
618
|
+
}
|
|
619
|
+
try {
|
|
620
|
+
const st = await promises_1.default.lstat(absFrom);
|
|
621
|
+
if (!st.isFile()) {
|
|
622
|
+
const yaml = [
|
|
623
|
+
`status: error`,
|
|
624
|
+
`from: ${yamlQuote(from)}`,
|
|
625
|
+
`to: ${yamlQuote(to)}`,
|
|
626
|
+
`error: FROM_NOT_FILE`,
|
|
627
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
628
|
+
? 'Move-file failed: from is not a file.'
|
|
629
|
+
: 'Move-file failed: from is not a file.')}`,
|
|
630
|
+
].join('\n');
|
|
631
|
+
return formatYamlCodeBlock(yaml);
|
|
632
|
+
}
|
|
633
|
+
const toParent = path_1.default.dirname(absTo);
|
|
634
|
+
const toParentSt = await promises_1.default.lstat(toParent).catch(() => undefined);
|
|
635
|
+
if (!toParentSt || !toParentSt.isDirectory()) {
|
|
636
|
+
const yaml = [
|
|
637
|
+
`status: error`,
|
|
638
|
+
`from: ${yamlQuote(from)}`,
|
|
639
|
+
`to: ${yamlQuote(to)}`,
|
|
640
|
+
`error: TO_PARENT_NOT_DIR`,
|
|
641
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
642
|
+
? 'Move-file failed: destination parent directory does not exist. Use mk_dir first.'
|
|
643
|
+
: 'Move-file failed: destination parent directory does not exist. Use mk_dir first.')}`,
|
|
644
|
+
].join('\n');
|
|
645
|
+
return formatYamlCodeBlock(yaml);
|
|
646
|
+
}
|
|
647
|
+
const toExists = await promises_1.default
|
|
648
|
+
.lstat(absTo)
|
|
649
|
+
.then(() => true)
|
|
650
|
+
.catch((err) => {
|
|
651
|
+
if (typeof err === 'object' &&
|
|
652
|
+
err !== null &&
|
|
653
|
+
'code' in err &&
|
|
654
|
+
err.code === 'ENOENT') {
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
throw err;
|
|
658
|
+
});
|
|
659
|
+
if (toExists) {
|
|
660
|
+
const yaml = [
|
|
661
|
+
`status: error`,
|
|
662
|
+
`from: ${yamlQuote(from)}`,
|
|
663
|
+
`to: ${yamlQuote(to)}`,
|
|
664
|
+
`error: TO_EXISTS`,
|
|
665
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
666
|
+
? 'Move-file failed: destination already exists.'
|
|
667
|
+
: 'Move-file failed: destination already exists.')}`,
|
|
668
|
+
].join('\n');
|
|
669
|
+
return formatYamlCodeBlock(yaml);
|
|
670
|
+
}
|
|
671
|
+
await promises_1.default.rename(absFrom, absTo);
|
|
672
|
+
const yaml = [
|
|
673
|
+
`status: ok`,
|
|
674
|
+
`from: ${yamlQuote(from)}`,
|
|
675
|
+
`to: ${yamlQuote(to)}`,
|
|
676
|
+
`summary: ${yamlQuote(`Move-file: ${from} \u2192 ${to}.`)}`,
|
|
677
|
+
].join('\n');
|
|
678
|
+
return formatYamlCodeBlock(yaml);
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
const yaml = [
|
|
682
|
+
`status: error`,
|
|
683
|
+
`from: ${yamlQuote(from)}`,
|
|
684
|
+
`to: ${yamlQuote(to)}`,
|
|
685
|
+
`error: FAILED`,
|
|
686
|
+
`summary: ${yamlQuote(error instanceof Error ? error.message : String(error))}`,
|
|
687
|
+
].join('\n');
|
|
688
|
+
return formatYamlCodeBlock(yaml);
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
};
|
|
692
|
+
exports.moveDirTool = {
|
|
693
|
+
type: 'func',
|
|
694
|
+
name: 'move_dir',
|
|
695
|
+
description: 'Move/rename a directory relative to workspace.',
|
|
696
|
+
descriptionI18n: {
|
|
697
|
+
en: 'Move/rename a directory relative to workspace.',
|
|
698
|
+
zh: '移动/重命名工作区内目录。',
|
|
699
|
+
},
|
|
700
|
+
parameters: {
|
|
701
|
+
type: 'object',
|
|
702
|
+
additionalProperties: false,
|
|
703
|
+
required: ['from', 'to'],
|
|
704
|
+
properties: {
|
|
705
|
+
from: { type: 'string', description: 'Workspace-relative source directory path.' },
|
|
706
|
+
to: { type: 'string', description: 'Workspace-relative destination directory path.' },
|
|
707
|
+
},
|
|
708
|
+
},
|
|
709
|
+
argsValidation: 'dominds',
|
|
710
|
+
call: async (_dlg, caller, args) => {
|
|
711
|
+
const workLanguage = (0, runtime_language_1.getWorkLanguage)();
|
|
712
|
+
const fromValue = args['from'];
|
|
713
|
+
const toValue = args['to'];
|
|
714
|
+
const from = typeof fromValue === 'string' ? fromValue.trim() : '';
|
|
715
|
+
const to = typeof toValue === 'string' ? toValue.trim() : '';
|
|
716
|
+
if (!from || !to) {
|
|
717
|
+
const yaml = [
|
|
718
|
+
`status: error`,
|
|
719
|
+
`error: INVALID_ARGS`,
|
|
720
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
721
|
+
? 'Move-dir failed: from/to required.'
|
|
722
|
+
: 'Move-dir failed: from/to required.')}`,
|
|
723
|
+
].join('\n');
|
|
724
|
+
return formatYamlCodeBlock(yaml);
|
|
725
|
+
}
|
|
726
|
+
const absFrom = path_1.default.resolve(process.cwd(), from);
|
|
727
|
+
const absTo = path_1.default.resolve(process.cwd(), to);
|
|
728
|
+
const cwd = path_1.default.resolve(process.cwd());
|
|
729
|
+
if (!absFrom.startsWith(cwd) || !absTo.startsWith(cwd)) {
|
|
730
|
+
const yaml = [
|
|
731
|
+
`status: error`,
|
|
732
|
+
`from: ${yamlQuote(from)}`,
|
|
733
|
+
`to: ${yamlQuote(to)}`,
|
|
734
|
+
`error: PATH_OUTSIDE_WORKSPACE`,
|
|
735
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
736
|
+
? 'Move-dir failed: paths must be within workspace.'
|
|
737
|
+
: 'Move-dir failed: paths must be within workspace.')}`,
|
|
738
|
+
].join('\n');
|
|
739
|
+
return formatYamlCodeBlock(yaml);
|
|
740
|
+
}
|
|
741
|
+
if (!(0, access_control_1.hasWriteAccess)(caller, from) || !(0, access_control_1.hasWriteAccess)(caller, to)) {
|
|
742
|
+
return (0, access_control_1.getAccessDeniedMessage)('write', from, workLanguage);
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
const st = await promises_1.default.lstat(absFrom);
|
|
746
|
+
if (!st.isDirectory()) {
|
|
747
|
+
const yaml = [
|
|
748
|
+
`status: error`,
|
|
749
|
+
`from: ${yamlQuote(from)}`,
|
|
750
|
+
`to: ${yamlQuote(to)}`,
|
|
751
|
+
`error: FROM_NOT_DIR`,
|
|
752
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
753
|
+
? 'Move-dir failed: from is not a directory.'
|
|
754
|
+
: 'Move-dir failed: from is not a directory.')}`,
|
|
755
|
+
].join('\n');
|
|
756
|
+
return formatYamlCodeBlock(yaml);
|
|
757
|
+
}
|
|
758
|
+
const toParent = path_1.default.dirname(absTo);
|
|
759
|
+
const toParentSt = await promises_1.default.lstat(toParent).catch(() => undefined);
|
|
760
|
+
if (!toParentSt || !toParentSt.isDirectory()) {
|
|
761
|
+
const yaml = [
|
|
762
|
+
`status: error`,
|
|
763
|
+
`from: ${yamlQuote(from)}`,
|
|
764
|
+
`to: ${yamlQuote(to)}`,
|
|
765
|
+
`error: TO_PARENT_NOT_DIR`,
|
|
766
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
767
|
+
? 'Move-dir failed: destination parent directory does not exist. Use mk_dir first.'
|
|
768
|
+
: 'Move-dir failed: destination parent directory does not exist. Use mk_dir first.')}`,
|
|
769
|
+
].join('\n');
|
|
770
|
+
return formatYamlCodeBlock(yaml);
|
|
771
|
+
}
|
|
772
|
+
const toExists = await promises_1.default
|
|
773
|
+
.lstat(absTo)
|
|
774
|
+
.then(() => true)
|
|
775
|
+
.catch((err) => {
|
|
776
|
+
if (typeof err === 'object' &&
|
|
777
|
+
err !== null &&
|
|
778
|
+
'code' in err &&
|
|
779
|
+
err.code === 'ENOENT') {
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
throw err;
|
|
783
|
+
});
|
|
784
|
+
if (toExists) {
|
|
785
|
+
const yaml = [
|
|
786
|
+
`status: error`,
|
|
787
|
+
`from: ${yamlQuote(from)}`,
|
|
788
|
+
`to: ${yamlQuote(to)}`,
|
|
789
|
+
`error: TO_EXISTS`,
|
|
790
|
+
`summary: ${yamlQuote(workLanguage === 'zh'
|
|
791
|
+
? 'Move-dir failed: destination already exists.'
|
|
792
|
+
: 'Move-dir failed: destination already exists.')}`,
|
|
793
|
+
].join('\n');
|
|
794
|
+
return formatYamlCodeBlock(yaml);
|
|
795
|
+
}
|
|
796
|
+
const movedEntryCount = await countDirEntries(absFrom);
|
|
797
|
+
await promises_1.default.rename(absFrom, absTo);
|
|
798
|
+
const yaml = [
|
|
799
|
+
`status: ok`,
|
|
800
|
+
`from: ${yamlQuote(from)}`,
|
|
801
|
+
`to: ${yamlQuote(to)}`,
|
|
802
|
+
`moved_entry_count: ${movedEntryCount}`,
|
|
803
|
+
`summary: ${yamlQuote(`Move-dir: ${from} \u2192 ${to} (${movedEntryCount} entries).`)}`,
|
|
804
|
+
].join('\n');
|
|
805
|
+
return formatYamlCodeBlock(yaml);
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
const yaml = [
|
|
809
|
+
`status: error`,
|
|
810
|
+
`from: ${yamlQuote(from)}`,
|
|
811
|
+
`to: ${yamlQuote(to)}`,
|
|
812
|
+
`error: FAILED`,
|
|
813
|
+
`summary: ${yamlQuote(error instanceof Error ? error.message : String(error))}`,
|
|
814
|
+
].join('\n');
|
|
815
|
+
return formatYamlCodeBlock(yaml);
|
|
816
|
+
}
|
|
817
|
+
},
|
|
818
|
+
};
|