onbuzz 3.3.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 +267 -0
- package/README.md +425 -0
- package/bin/cli.js +556 -0
- package/bin/loxia-terminal-v2.js +162 -0
- package/bin/loxia-terminal.js +90 -0
- package/bin/start-with-terminal.js +200 -0
- package/node_modules/@isaacs/balanced-match/LICENSE.md +23 -0
- package/node_modules/@isaacs/balanced-match/README.md +60 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.d.ts +9 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.js +59 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.js.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/package.json +3 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.d.ts +9 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.d.ts.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.js +54 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.js.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/package.json +3 -0
- package/node_modules/@isaacs/balanced-match/package.json +79 -0
- package/node_modules/@isaacs/brace-expansion/LICENSE +23 -0
- package/node_modules/@isaacs/brace-expansion/README.md +97 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.d.ts +6 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js +199 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/package.json +3 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.d.ts +6 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.d.ts.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js +195 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/package.json +3 -0
- package/node_modules/@isaacs/brace-expansion/package.json +60 -0
- package/node_modules/glob/LICENSE.md +63 -0
- package/node_modules/glob/README.md +1177 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts +388 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/glob.js +247 -0
- package/node_modules/glob/dist/commonjs/glob.js.map +1 -0
- package/node_modules/glob/dist/commonjs/has-magic.d.ts +14 -0
- package/node_modules/glob/dist/commonjs/has-magic.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/has-magic.js +27 -0
- package/node_modules/glob/dist/commonjs/has-magic.js.map +1 -0
- package/node_modules/glob/dist/commonjs/ignore.d.ts +24 -0
- package/node_modules/glob/dist/commonjs/ignore.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/ignore.js +119 -0
- package/node_modules/glob/dist/commonjs/ignore.js.map +1 -0
- package/node_modules/glob/dist/commonjs/index.d.ts +97 -0
- package/node_modules/glob/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/index.js +68 -0
- package/node_modules/glob/dist/commonjs/index.js.map +1 -0
- package/node_modules/glob/dist/commonjs/index.min.js +4 -0
- package/node_modules/glob/dist/commonjs/index.min.js.map +7 -0
- package/node_modules/glob/dist/commonjs/package.json +3 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts +76 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/pattern.js +219 -0
- package/node_modules/glob/dist/commonjs/pattern.js.map +1 -0
- package/node_modules/glob/dist/commonjs/processor.d.ts +59 -0
- package/node_modules/glob/dist/commonjs/processor.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/processor.js +301 -0
- package/node_modules/glob/dist/commonjs/processor.js.map +1 -0
- package/node_modules/glob/dist/commonjs/walker.d.ts +97 -0
- package/node_modules/glob/dist/commonjs/walker.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/walker.js +387 -0
- package/node_modules/glob/dist/commonjs/walker.js.map +1 -0
- package/node_modules/glob/dist/esm/glob.d.ts +388 -0
- package/node_modules/glob/dist/esm/glob.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/glob.js +243 -0
- package/node_modules/glob/dist/esm/glob.js.map +1 -0
- package/node_modules/glob/dist/esm/has-magic.d.ts +14 -0
- package/node_modules/glob/dist/esm/has-magic.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/has-magic.js +23 -0
- package/node_modules/glob/dist/esm/has-magic.js.map +1 -0
- package/node_modules/glob/dist/esm/ignore.d.ts +24 -0
- package/node_modules/glob/dist/esm/ignore.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/ignore.js +115 -0
- package/node_modules/glob/dist/esm/ignore.js.map +1 -0
- package/node_modules/glob/dist/esm/index.d.ts +97 -0
- package/node_modules/glob/dist/esm/index.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/index.js +55 -0
- package/node_modules/glob/dist/esm/index.js.map +1 -0
- package/node_modules/glob/dist/esm/index.min.js +4 -0
- package/node_modules/glob/dist/esm/index.min.js.map +7 -0
- package/node_modules/glob/dist/esm/package.json +3 -0
- package/node_modules/glob/dist/esm/pattern.d.ts +76 -0
- package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/pattern.js +215 -0
- package/node_modules/glob/dist/esm/pattern.js.map +1 -0
- package/node_modules/glob/dist/esm/processor.d.ts +59 -0
- package/node_modules/glob/dist/esm/processor.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/processor.js +294 -0
- package/node_modules/glob/dist/esm/processor.js.map +1 -0
- package/node_modules/glob/dist/esm/walker.d.ts +97 -0
- package/node_modules/glob/dist/esm/walker.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/walker.js +381 -0
- package/node_modules/glob/dist/esm/walker.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/LICENSE.md +55 -0
- package/node_modules/glob/node_modules/minimatch/README.md +453 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +2 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js +14 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +20 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +591 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts +8 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +152 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +15 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +30 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +94 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +1029 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/package.json +3 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +22 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +38 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +2 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js +10 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +20 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +587 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts +8 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +148 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +15 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +26 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +94 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +1016 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/package.json +3 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +22 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +34 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/package.json +67 -0
- package/node_modules/glob/package.json +101 -0
- package/node_modules/minipass/LICENSE +15 -0
- package/node_modules/minipass/README.md +825 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts +549 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/minipass/dist/commonjs/index.js +1028 -0
- package/node_modules/minipass/dist/commonjs/index.js.map +1 -0
- package/node_modules/minipass/dist/commonjs/package.json +3 -0
- package/node_modules/minipass/dist/esm/index.d.ts +549 -0
- package/node_modules/minipass/dist/esm/index.d.ts.map +1 -0
- package/node_modules/minipass/dist/esm/index.js +1018 -0
- package/node_modules/minipass/dist/esm/index.js.map +1 -0
- package/node_modules/minipass/dist/esm/package.json +3 -0
- package/node_modules/minipass/package.json +82 -0
- package/node_modules/package-json-from-dist/LICENSE.md +63 -0
- package/node_modules/package-json-from-dist/README.md +110 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts +89 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.js +134 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.js.map +1 -0
- package/node_modules/package-json-from-dist/dist/commonjs/package.json +3 -0
- package/node_modules/package-json-from-dist/dist/esm/index.d.ts +89 -0
- package/node_modules/package-json-from-dist/dist/esm/index.d.ts.map +1 -0
- package/node_modules/package-json-from-dist/dist/esm/index.js +129 -0
- package/node_modules/package-json-from-dist/dist/esm/index.js.map +1 -0
- package/node_modules/package-json-from-dist/dist/esm/package.json +3 -0
- package/node_modules/package-json-from-dist/package.json +68 -0
- package/node_modules/path-scurry/LICENSE.md +55 -0
- package/node_modules/path-scurry/README.md +636 -0
- package/node_modules/path-scurry/dist/commonjs/index.d.ts +1115 -0
- package/node_modules/path-scurry/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/path-scurry/dist/commonjs/index.js +2018 -0
- package/node_modules/path-scurry/dist/commonjs/index.js.map +1 -0
- package/node_modules/path-scurry/dist/commonjs/package.json +3 -0
- package/node_modules/path-scurry/dist/esm/index.d.ts +1115 -0
- package/node_modules/path-scurry/dist/esm/index.d.ts.map +1 -0
- package/node_modules/path-scurry/dist/esm/index.js +1983 -0
- package/node_modules/path-scurry/dist/esm/index.js.map +1 -0
- package/node_modules/path-scurry/dist/esm/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/LICENSE.md +55 -0
- package/node_modules/path-scurry/node_modules/lru-cache/README.md +383 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +1323 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +1589 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +1323 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +1585 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/package.json +101 -0
- package/node_modules/path-scurry/package.json +88 -0
- package/node_modules/rimraf/LICENSE.md +55 -0
- package/node_modules/rimraf/README.md +226 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.js +58 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/error.d.ts +6 -0
- package/node_modules/rimraf/dist/commonjs/error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/error.js +10 -0
- package/node_modules/rimraf/dist/commonjs/error.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.js +38 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fs.d.ts +15 -0
- package/node_modules/rimraf/dist/commonjs/fs.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fs.js +33 -0
- package/node_modules/rimraf/dist/commonjs/fs.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.js +24 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/index.d.ts +50 -0
- package/node_modules/rimraf/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/index.js +78 -0
- package/node_modules/rimraf/dist/commonjs/index.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts +34 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.js +53 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/package.json +3 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.js +48 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.js +19 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.d.ts +8 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.js +65 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.js +8 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js +138 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.js +24 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.js +103 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.js +159 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/use-native.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/use-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/use-native.js +18 -0
- package/node_modules/rimraf/dist/commonjs/use-native.js.map +1 -0
- package/node_modules/rimraf/dist/esm/bin.d.mts +3 -0
- package/node_modules/rimraf/dist/esm/bin.d.mts.map +1 -0
- package/node_modules/rimraf/dist/esm/bin.mjs +250 -0
- package/node_modules/rimraf/dist/esm/bin.mjs.map +1 -0
- package/node_modules/rimraf/dist/esm/default-tmp.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/default-tmp.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/default-tmp.js +55 -0
- package/node_modules/rimraf/dist/esm/default-tmp.js.map +1 -0
- package/node_modules/rimraf/dist/esm/error.d.ts +6 -0
- package/node_modules/rimraf/dist/esm/error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/error.js +5 -0
- package/node_modules/rimraf/dist/esm/error.js.map +1 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.js +33 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.js.map +1 -0
- package/node_modules/rimraf/dist/esm/fs.d.ts +15 -0
- package/node_modules/rimraf/dist/esm/fs.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/fs.js +18 -0
- package/node_modules/rimraf/dist/esm/fs.js.map +1 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.js +19 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.js.map +1 -0
- package/node_modules/rimraf/dist/esm/index.d.ts +50 -0
- package/node_modules/rimraf/dist/esm/index.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/index.js +70 -0
- package/node_modules/rimraf/dist/esm/index.js.map +1 -0
- package/node_modules/rimraf/dist/esm/opt-arg.d.ts +34 -0
- package/node_modules/rimraf/dist/esm/opt-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/opt-arg.js +46 -0
- package/node_modules/rimraf/dist/esm/opt-arg.js.map +1 -0
- package/node_modules/rimraf/dist/esm/package.json +3 -0
- package/node_modules/rimraf/dist/esm/path-arg.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/path-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/path-arg.js +46 -0
- package/node_modules/rimraf/dist/esm/path-arg.js.map +1 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.js +14 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.js.map +1 -0
- package/node_modules/rimraf/dist/esm/retry-busy.d.ts +8 -0
- package/node_modules/rimraf/dist/esm/retry-busy.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/retry-busy.js +60 -0
- package/node_modules/rimraf/dist/esm/retry-busy.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.js +5 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.js +133 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.js +19 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.js +98 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.js +154 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.js.map +1 -0
- package/node_modules/rimraf/dist/esm/use-native.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/use-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/use-native.js +15 -0
- package/node_modules/rimraf/dist/esm/use-native.js.map +1 -0
- package/node_modules/rimraf/package.json +92 -0
- package/package.json +152 -0
- package/scripts/install-scanners.js +258 -0
- package/scripts/watchdog.js +147 -0
- package/src/analyzers/CSSAnalyzer.js +297 -0
- package/src/analyzers/ConfigValidator.js +690 -0
- package/src/analyzers/ESLintAnalyzer.js +320 -0
- package/src/analyzers/JavaScriptAnalyzer.js +261 -0
- package/src/analyzers/PrettierFormatter.js +247 -0
- package/src/analyzers/PythonAnalyzer.js +283 -0
- package/src/analyzers/SecurityAnalyzer.js +729 -0
- package/src/analyzers/SparrowAnalyzer.js +341 -0
- package/src/analyzers/TypeScriptAnalyzer.js +247 -0
- package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
- package/src/analyzers/codeCloneDetector/detector.js +250 -0
- package/src/analyzers/codeCloneDetector/index.js +192 -0
- package/src/analyzers/codeCloneDetector/parser.js +199 -0
- package/src/analyzers/codeCloneDetector/reporter.js +148 -0
- package/src/analyzers/codeCloneDetector/scanner.js +88 -0
- package/src/core/agentPool.js +1957 -0
- package/src/core/agentScheduler.js +3212 -0
- package/src/core/contextManager.js +709 -0
- package/src/core/flowExecutor.js +928 -0
- package/src/core/messageProcessor.js +808 -0
- package/src/core/orchestrator.js +584 -0
- package/src/core/stateManager.js +1500 -0
- package/src/index.js +972 -0
- package/src/interfaces/cli.js +553 -0
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +208 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +236 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +138 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +137 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +350 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +332 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +256 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +388 -0
- package/src/interfaces/terminal/api/apiClient.js +299 -0
- package/src/interfaces/terminal/api/messageRouter.js +262 -0
- package/src/interfaces/terminal/api/session.js +266 -0
- package/src/interfaces/terminal/api/websocket.js +497 -0
- package/src/interfaces/terminal/components/AgentCreator.js +705 -0
- package/src/interfaces/terminal/components/AgentEditor.js +678 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +330 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +92 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +264 -0
- package/src/interfaces/terminal/components/Header.js +28 -0
- package/src/interfaces/terminal/components/HelpPanel.js +231 -0
- package/src/interfaces/terminal/components/InputBox.js +118 -0
- package/src/interfaces/terminal/components/Layout.js +603 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +71 -0
- package/src/interfaces/terminal/components/MessageList.js +281 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +251 -0
- package/src/interfaces/terminal/components/SearchPanel.js +265 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +415 -0
- package/src/interfaces/terminal/components/StatusBar.js +65 -0
- package/src/interfaces/terminal/components/TextInput.js +127 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +227 -0
- package/src/interfaces/terminal/config/constants.js +393 -0
- package/src/interfaces/terminal/index.js +168 -0
- package/src/interfaces/terminal/state/useAgentControl.js +496 -0
- package/src/interfaces/terminal/state/useAgents.js +537 -0
- package/src/interfaces/terminal/state/useConnection.js +444 -0
- package/src/interfaces/terminal/state/useMessages.js +630 -0
- package/src/interfaces/terminal/state/useTools.js +554 -0
- package/src/interfaces/terminal/utils/debugLogger.js +44 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +232 -0
- package/src/interfaces/terminal/utils/theme.js +85 -0
- package/src/interfaces/webServer.js +5457 -0
- package/src/modules/fileExplorer/controller.js +413 -0
- package/src/modules/fileExplorer/index.js +37 -0
- package/src/modules/fileExplorer/middleware.js +92 -0
- package/src/modules/fileExplorer/routes.js +158 -0
- package/src/modules/fileExplorer/types.js +44 -0
- package/src/services/agentActivityService.js +399 -0
- package/src/services/aiService.js +2618 -0
- package/src/services/apiKeyManager.js +334 -0
- package/src/services/benchmarkService.js +196 -0
- package/src/services/budgetService.js +565 -0
- package/src/services/contextInjectionService.js +268 -0
- package/src/services/conversationCompactionService.js +1103 -0
- package/src/services/credentialVault.js +685 -0
- package/src/services/errorHandler.js +810 -0
- package/src/services/fileAttachmentService.js +547 -0
- package/src/services/flowContextService.js +189 -0
- package/src/services/memoryService.js +521 -0
- package/src/services/modelRouterService.js +365 -0
- package/src/services/modelsService.js +323 -0
- package/src/services/ollamaService.js +452 -0
- package/src/services/portRegistry.js +336 -0
- package/src/services/portTracker.js +223 -0
- package/src/services/projectDetector.js +404 -0
- package/src/services/promptService.js +372 -0
- package/src/services/qualityInspector.js +796 -0
- package/src/services/scheduleService.js +725 -0
- package/src/services/serviceRegistry.js +386 -0
- package/src/services/skillsService.js +486 -0
- package/src/services/telegramService.js +920 -0
- package/src/services/tokenCountingService.js +316 -0
- package/src/services/visualEditorBridge.js +1033 -0
- package/src/services/visualEditorServer.js +1727 -0
- package/src/services/whatsappService.js +663 -0
- package/src/tools/__tests__/webTool.e2e.test.js +569 -0
- package/src/tools/__tests__/webTool.unit.test.js +195 -0
- package/src/tools/agentCommunicationTool.js +1343 -0
- package/src/tools/agentDelayTool.js +498 -0
- package/src/tools/asyncToolManager.js +604 -0
- package/src/tools/baseTool.js +887 -0
- package/src/tools/browserTool.js +897 -0
- package/src/tools/cloneDetectionTool.js +581 -0
- package/src/tools/codeMapTool.js +857 -0
- package/src/tools/dependencyResolverTool.js +1212 -0
- package/src/tools/docxTool.js +623 -0
- package/src/tools/excelTool.js +636 -0
- package/src/tools/fileContentReplaceTool.js +840 -0
- package/src/tools/fileTreeTool.js +833 -0
- package/src/tools/filesystemTool.js +1217 -0
- package/src/tools/helpTool.js +198 -0
- package/src/tools/imageTool.js +1034 -0
- package/src/tools/importAnalyzerTool.js +1056 -0
- package/src/tools/jobDoneTool.js +388 -0
- package/src/tools/memoryTool.js +554 -0
- package/src/tools/pdfTool.js +627 -0
- package/src/tools/seekTool.js +883 -0
- package/src/tools/skillsTool.js +276 -0
- package/src/tools/staticAnalysisTool.js +2146 -0
- package/src/tools/taskManagerTool.js +2836 -0
- package/src/tools/terminalTool.js +2486 -0
- package/src/tools/userPromptTool.js +474 -0
- package/src/tools/videoTool.js +1139 -0
- package/src/tools/visionTool.js +507 -0
- package/src/tools/visualEditorTool.js +1175 -0
- package/src/tools/webTool.js +3114 -0
- package/src/tools/whatsappTool.js +457 -0
- package/src/types/agent.js +519 -0
- package/src/types/contextReference.js +972 -0
- package/src/types/conversation.js +730 -0
- package/src/types/toolCommand.js +747 -0
- package/src/utilities/attachmentValidator.js +288 -0
- package/src/utilities/browserStealth.js +630 -0
- package/src/utilities/configManager.js +618 -0
- package/src/utilities/constants.js +870 -0
- package/src/utilities/directoryAccessManager.js +566 -0
- package/src/utilities/fileProcessor.js +307 -0
- package/src/utilities/humanBehavior.js +453 -0
- package/src/utilities/jsonRepair.js +242 -0
- package/src/utilities/logger.js +436 -0
- package/src/utilities/platformUtils.js +255 -0
- package/src/utilities/platformUtils.test.js +98 -0
- package/src/utilities/stealthConstants.js +377 -0
- package/src/utilities/structuredFileValidator.js +699 -0
- package/src/utilities/tagParser.js +878 -0
- package/src/utilities/toolConstants.js +415 -0
- package/src/utilities/userDataDir.js +300 -0
- package/web-ui/build/brands/autopilot/favicon.svg +1 -0
- package/web-ui/build/brands/autopilot/logo.webp +0 -0
- package/web-ui/build/brands/onbuzz/favicon.svg +1 -0
- package/web-ui/build/brands/onbuzz/logo-text.webp +0 -0
- package/web-ui/build/brands/onbuzz/logo.webp +0 -0
- package/web-ui/build/index.html +15 -0
- package/web-ui/build/logo.png +0 -0
- package/web-ui/build/logo2.png +0 -0
- package/web-ui/build/static/index-SmQFfvBs.js +746 -0
- package/web-ui/build/static/index-V2ySwjHp.css +1 -0
|
@@ -0,0 +1,1217 @@
|
|
|
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', '.bat', '.cmd', '.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
|
+
if (!action.type) {
|
|
279
|
+
errors.push(`Action ${index + 1}: type is required`);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
switch (action.type) {
|
|
284
|
+
case 'read':
|
|
285
|
+
case 'delete':
|
|
286
|
+
case 'exists':
|
|
287
|
+
case 'stats':
|
|
288
|
+
if (!action.filePath) {
|
|
289
|
+
errors.push(`Action ${index + 1}: file-path is required for ${action.type}`);
|
|
290
|
+
}
|
|
291
|
+
break;
|
|
292
|
+
|
|
293
|
+
case 'write':
|
|
294
|
+
if (!action.outputPath) {
|
|
295
|
+
errors.push(`Action ${index + 1}: output-path is required for write`);
|
|
296
|
+
}
|
|
297
|
+
// Content validation with detailed diagnostics
|
|
298
|
+
if (action.content === undefined) {
|
|
299
|
+
errors.push(`Action ${index + 1}: content is undefined for write (outputPath: ${action.outputPath || 'not set'})`);
|
|
300
|
+
console.error('[FileSystemTool] Write validation failed: content is undefined', {
|
|
301
|
+
outputPath: action.outputPath,
|
|
302
|
+
actionKeys: Object.keys(action)
|
|
303
|
+
});
|
|
304
|
+
} else if (action.content === null) {
|
|
305
|
+
errors.push(`Action ${index + 1}: content is null for write (outputPath: ${action.outputPath || 'not set'})`);
|
|
306
|
+
console.error('[FileSystemTool] Write validation failed: content is null', {
|
|
307
|
+
outputPath: action.outputPath
|
|
308
|
+
});
|
|
309
|
+
} else if (typeof action.content !== 'string') {
|
|
310
|
+
errors.push(`Action ${index + 1}: content must be a string, got ${typeof action.content}`);
|
|
311
|
+
console.error('[FileSystemTool] Write validation failed: content is not a string', {
|
|
312
|
+
outputPath: action.outputPath,
|
|
313
|
+
contentType: typeof action.content
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
// Note: empty string content is allowed (creates empty file)
|
|
317
|
+
break;
|
|
318
|
+
|
|
319
|
+
case 'append':
|
|
320
|
+
if (!action.filePath) {
|
|
321
|
+
errors.push(`Action ${index + 1}: file-path is required for append`);
|
|
322
|
+
}
|
|
323
|
+
// Content validation with detailed diagnostics
|
|
324
|
+
if (action.content === undefined) {
|
|
325
|
+
errors.push(`Action ${index + 1}: content is undefined for append (filePath: ${action.filePath || 'not set'})`);
|
|
326
|
+
console.error('[FileSystemTool] Append validation failed: content is undefined', {
|
|
327
|
+
filePath: action.filePath,
|
|
328
|
+
actionKeys: Object.keys(action)
|
|
329
|
+
});
|
|
330
|
+
} else if (action.content === null) {
|
|
331
|
+
errors.push(`Action ${index + 1}: content is null for append (filePath: ${action.filePath || 'not set'})`);
|
|
332
|
+
console.error('[FileSystemTool] Append validation failed: content is null', {
|
|
333
|
+
filePath: action.filePath
|
|
334
|
+
});
|
|
335
|
+
} else if (typeof action.content !== 'string') {
|
|
336
|
+
errors.push(`Action ${index + 1}: content must be a string, got ${typeof action.content}`);
|
|
337
|
+
console.error('[FileSystemTool] Append validation failed: content is not a string', {
|
|
338
|
+
filePath: action.filePath,
|
|
339
|
+
contentType: typeof action.content
|
|
340
|
+
});
|
|
341
|
+
} else if (action.content.length === 0) {
|
|
342
|
+
// Empty append is suspicious - log a warning but allow it
|
|
343
|
+
console.warn('[FileSystemTool] Append with empty content', {
|
|
344
|
+
filePath: action.filePath
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
break;
|
|
348
|
+
|
|
349
|
+
case 'copy':
|
|
350
|
+
case 'move':
|
|
351
|
+
if (!action.sourcePath) {
|
|
352
|
+
errors.push(`Action ${index + 1}: source-path is required for ${action.type}`);
|
|
353
|
+
}
|
|
354
|
+
if (!action.destPath) {
|
|
355
|
+
errors.push(`Action ${index + 1}: dest-path is required for ${action.type}`);
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
|
|
359
|
+
case 'create-dir':
|
|
360
|
+
case 'list':
|
|
361
|
+
if (!action.directory) {
|
|
362
|
+
errors.push(`Action ${index + 1}: directory is required for ${action.type}`);
|
|
363
|
+
}
|
|
364
|
+
break;
|
|
365
|
+
|
|
366
|
+
default:
|
|
367
|
+
errors.push(`Action ${index + 1}: unknown action type: ${action.type}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Validate file extensions if specified
|
|
371
|
+
if (action.filePath && !this.isAllowedFileExtension(action.filePath)) {
|
|
372
|
+
errors.push(`Action ${index + 1}: file type not allowed: ${path.extname(action.filePath)}`);
|
|
373
|
+
}
|
|
374
|
+
if (action.outputPath && !this.isAllowedFileExtension(action.outputPath)) {
|
|
375
|
+
errors.push(`Action ${index + 1}: file type not allowed: ${path.extname(action.outputPath)}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return {
|
|
381
|
+
valid: errors.length === 0,
|
|
382
|
+
errors
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Execute tool with parsed parameters
|
|
388
|
+
* @param {Object} params - Parsed parameters
|
|
389
|
+
* @param {Object} context - Execution context
|
|
390
|
+
* @returns {Promise<Object>} Execution result
|
|
391
|
+
*/
|
|
392
|
+
async execute(params, context) {
|
|
393
|
+
// Validate params structure
|
|
394
|
+
if (!params || typeof params !== 'object') {
|
|
395
|
+
throw new Error('Invalid parameters: params must be an object');
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const { actions } = params;
|
|
399
|
+
|
|
400
|
+
// Validate actions array
|
|
401
|
+
if (!actions) {
|
|
402
|
+
throw new Error('Invalid parameters: actions is required. Received params: ' + JSON.stringify(Object.keys(params)));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (!Array.isArray(actions)) {
|
|
406
|
+
throw new Error('Invalid parameters: actions must be an array. Received type: ' + typeof actions);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (actions.length === 0) {
|
|
410
|
+
throw new Error('Invalid parameters: actions array is empty');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// CRITICAL: Run custom validation (not called by messageProcessor)
|
|
414
|
+
// This ensures write/append actions have required content
|
|
415
|
+
const validation = this.customValidateParameters(params);
|
|
416
|
+
if (!validation.valid) {
|
|
417
|
+
const errorMsg = validation.errors?.join('; ') || validation.error || 'Validation failed';
|
|
418
|
+
console.error('[FileSystemTool] Parameter validation failed:', errorMsg);
|
|
419
|
+
throw new Error(`Parameter validation failed: ${errorMsg}`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const { projectDir, agentId, directoryAccess } = context;
|
|
423
|
+
|
|
424
|
+
// Get directory access configuration from agent or create default
|
|
425
|
+
const accessConfig = directoryAccess ||
|
|
426
|
+
this.directoryAccessManager.createDirectoryAccess({
|
|
427
|
+
workingDirectory: projectDir || process.cwd(),
|
|
428
|
+
writeEnabledDirectories: [projectDir || process.cwd()],
|
|
429
|
+
restrictToProject: true
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// IMPORTANT: If the agent has directoryAccess configured, use its workingDirectory
|
|
433
|
+
// This ensures UI-configured project directories are respected
|
|
434
|
+
if (directoryAccess && directoryAccess.workingDirectory) {
|
|
435
|
+
// Agent has explicitly configured working directory from UI - use it
|
|
436
|
+
console.log('FileSystem DEBUG: Using agent configured working directory:', directoryAccess.workingDirectory);
|
|
437
|
+
console.log('FileSystem DEBUG: Full directoryAccess object:', JSON.stringify(directoryAccess, null, 2));
|
|
438
|
+
} else {
|
|
439
|
+
// Using fallback to projectDir or process.cwd()
|
|
440
|
+
console.log('FileSystem DEBUG: Using fallback working directory:', projectDir || process.cwd());
|
|
441
|
+
console.log('FileSystem DEBUG: directoryAccess is:', directoryAccess);
|
|
442
|
+
console.log('FileSystem DEBUG: projectDir is:', projectDir);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const results = [];
|
|
446
|
+
|
|
447
|
+
for (const action of actions) {
|
|
448
|
+
try {
|
|
449
|
+
let result;
|
|
450
|
+
|
|
451
|
+
switch (action.type) {
|
|
452
|
+
case 'read':
|
|
453
|
+
result = await this.readFile(action.filePath, accessConfig, action.encoding);
|
|
454
|
+
break;
|
|
455
|
+
|
|
456
|
+
case 'write':
|
|
457
|
+
result = await this.writeFile(action.outputPath, action.content, accessConfig, {
|
|
458
|
+
encoding: action.encoding,
|
|
459
|
+
createDirs: action.createDirs,
|
|
460
|
+
wasTruncated: context.wasTruncated || false
|
|
461
|
+
});
|
|
462
|
+
break;
|
|
463
|
+
|
|
464
|
+
case 'append':
|
|
465
|
+
result = await this.appendToFile(action.filePath, action.content, accessConfig, action.encoding);
|
|
466
|
+
break;
|
|
467
|
+
|
|
468
|
+
case 'delete':
|
|
469
|
+
result = await this.deleteFile(action.filePath, accessConfig);
|
|
470
|
+
break;
|
|
471
|
+
|
|
472
|
+
case 'copy':
|
|
473
|
+
result = await this.copyFile(action.sourcePath, action.destPath, accessConfig);
|
|
474
|
+
break;
|
|
475
|
+
|
|
476
|
+
case 'move':
|
|
477
|
+
result = await this.moveFile(action.sourcePath, action.destPath, accessConfig);
|
|
478
|
+
break;
|
|
479
|
+
|
|
480
|
+
case 'create-dir':
|
|
481
|
+
result = await this.createDirectory(action.directory, accessConfig);
|
|
482
|
+
break;
|
|
483
|
+
|
|
484
|
+
case 'list':
|
|
485
|
+
result = await this.listDirectory(action.directory, accessConfig);
|
|
486
|
+
break;
|
|
487
|
+
|
|
488
|
+
case 'exists':
|
|
489
|
+
result = await this.checkExists(action.filePath, accessConfig);
|
|
490
|
+
break;
|
|
491
|
+
|
|
492
|
+
case 'stats':
|
|
493
|
+
result = await this.getFileStats(action.filePath, accessConfig);
|
|
494
|
+
break;
|
|
495
|
+
|
|
496
|
+
default:
|
|
497
|
+
throw new Error(`Unknown action type: ${action.type}`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
results.push(result);
|
|
501
|
+
this.addToHistory(action, result, context.agentId);
|
|
502
|
+
|
|
503
|
+
} catch (error) {
|
|
504
|
+
// Log detailed error for debugging
|
|
505
|
+
console.error(`[FileSystemTool] Action '${action.type}' failed:`, {
|
|
506
|
+
action: action.type,
|
|
507
|
+
filePath: action.filePath || action.outputPath || action.directory,
|
|
508
|
+
error: error.message,
|
|
509
|
+
stack: error.stack?.split('\n').slice(0, 3).join('\n'),
|
|
510
|
+
contentLength: action.content?.length,
|
|
511
|
+
hasContent: action.content !== undefined && action.content !== null
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const errorResult = {
|
|
515
|
+
success: false,
|
|
516
|
+
action: action.type,
|
|
517
|
+
error: error.message,
|
|
518
|
+
filePath: action.filePath || action.outputPath || action.directory,
|
|
519
|
+
// Include debug info for troubleshooting
|
|
520
|
+
debug: {
|
|
521
|
+
contentProvided: action.content !== undefined && action.content !== null,
|
|
522
|
+
contentLength: action.content?.length || 0,
|
|
523
|
+
contentPreview: action.content ? action.content.substring(0, 100) + (action.content.length > 100 ? '...' : '') : null
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
results.push(errorResult);
|
|
528
|
+
this.addToHistory(action, errorResult, context.agentId);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Determine overall success - only true if ALL actions succeeded
|
|
533
|
+
const allSucceeded = results.every(r => r.success === true);
|
|
534
|
+
const failedCount = results.filter(r => r.success === false).length;
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
success: allSucceeded,
|
|
538
|
+
actions: results,
|
|
539
|
+
executedActions: actions.length,
|
|
540
|
+
successfulActions: actions.length - failedCount,
|
|
541
|
+
failedActions: failedCount,
|
|
542
|
+
toolUsed: 'filesys',
|
|
543
|
+
...(failedCount > 0 && {
|
|
544
|
+
warning: `${failedCount} of ${actions.length} action(s) failed. Check individual action results for details.`
|
|
545
|
+
})
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Read file contents
|
|
551
|
+
* @private
|
|
552
|
+
*/
|
|
553
|
+
async readFile(filePath, accessConfig, encoding = 'utf8') {
|
|
554
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
555
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
556
|
+
|
|
557
|
+
// Validate read access using DirectoryAccessManager
|
|
558
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
559
|
+
if (!accessResult.allowed) {
|
|
560
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
const stats = await fs.stat(fullPath);
|
|
565
|
+
|
|
566
|
+
if (stats.size > this.maxFileSize) {
|
|
567
|
+
throw new Error(`File too large: ${stats.size} bytes (max ${this.maxFileSize})`);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const content = await fs.readFile(fullPath, encoding);
|
|
571
|
+
|
|
572
|
+
return {
|
|
573
|
+
success: true,
|
|
574
|
+
action: 'read',
|
|
575
|
+
filePath: this.directoryAccessManager.createRelativePath(fullPath, accessConfig),
|
|
576
|
+
content,
|
|
577
|
+
size: stats.size,
|
|
578
|
+
encoding,
|
|
579
|
+
lastModified: stats.mtime.toISOString(),
|
|
580
|
+
message: `Read ${stats.size} bytes from ${filePath}`
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
} catch (error) {
|
|
584
|
+
throw new Error(`Failed to read file ${filePath}: ${error.message}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Write content to file
|
|
590
|
+
* @private
|
|
591
|
+
*/
|
|
592
|
+
async writeFile(outputPath, content, accessConfig, options = {}) {
|
|
593
|
+
const { encoding = 'utf8', createDirs = true, wasTruncated = false } = options;
|
|
594
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
595
|
+
const fullPath = this.resolvePath(outputPath, workingDir);
|
|
596
|
+
|
|
597
|
+
// Validate write access using DirectoryAccessManager
|
|
598
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
599
|
+
if (!accessResult.allowed) {
|
|
600
|
+
throw new Error(`Write access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Handle truncated content - append notice if AI response was cut off
|
|
604
|
+
let finalContent = content;
|
|
605
|
+
let truncationApplied = false;
|
|
606
|
+
|
|
607
|
+
if (wasTruncated && content) {
|
|
608
|
+
const fileExt = getFileExtension(outputPath);
|
|
609
|
+
const truncationNotice = createTruncationNotice(fileExt);
|
|
610
|
+
if (truncationNotice) {
|
|
611
|
+
finalContent = content + truncationNotice;
|
|
612
|
+
truncationApplied = true;
|
|
613
|
+
console.log(`[FileSystemTool] Appending truncation notice to ${outputPath} (AI response was truncated)`);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
try {
|
|
618
|
+
// Check content size
|
|
619
|
+
const contentSize = Buffer.byteLength(finalContent, encoding);
|
|
620
|
+
if (contentSize > this.maxFileSize) {
|
|
621
|
+
throw new Error(`Content too large: ${contentSize} bytes (max ${this.maxFileSize})`);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// Create parent directories if requested
|
|
625
|
+
if (createDirs) {
|
|
626
|
+
const dirPath = path.dirname(fullPath);
|
|
627
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Create backup if file exists
|
|
631
|
+
let backupPath = null;
|
|
632
|
+
try {
|
|
633
|
+
await fs.access(fullPath);
|
|
634
|
+
backupPath = `${fullPath}.backup-${Date.now()}`;
|
|
635
|
+
await fs.copyFile(fullPath, backupPath);
|
|
636
|
+
} catch {
|
|
637
|
+
// File doesn't exist, no backup needed
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
await fs.writeFile(fullPath, finalContent, encoding);
|
|
641
|
+
|
|
642
|
+
// VERIFICATION: Confirm file was written correctly
|
|
643
|
+
const stats = await fs.stat(fullPath);
|
|
644
|
+
|
|
645
|
+
// Verify file size matches expected content size
|
|
646
|
+
const expectedSize = Buffer.byteLength(finalContent, encoding);
|
|
647
|
+
if (stats.size !== expectedSize) {
|
|
648
|
+
throw new Error(`Write verification failed: expected ${expectedSize} bytes but file is ${stats.size} bytes`);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// For text files, verify content was written (read back and compare hash)
|
|
652
|
+
if (encoding === 'utf8' || encoding === 'utf-8') {
|
|
653
|
+
const writtenContent = await fs.readFile(fullPath, encoding);
|
|
654
|
+
if (writtenContent !== finalContent) {
|
|
655
|
+
throw new Error(`Write verification failed: content mismatch after write`);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
660
|
+
|
|
661
|
+
// Build base result
|
|
662
|
+
const result = {
|
|
663
|
+
success: true,
|
|
664
|
+
action: 'write',
|
|
665
|
+
outputPath: relativePath,
|
|
666
|
+
fullPath: fullPath,
|
|
667
|
+
size: stats.size,
|
|
668
|
+
encoding,
|
|
669
|
+
verified: true, // Content was verified after write
|
|
670
|
+
backupPath: backupPath ? this.directoryAccessManager.createRelativePath(backupPath, accessConfig) : null,
|
|
671
|
+
backupFullPath: backupPath || null,
|
|
672
|
+
message: `Wrote ${stats.size} bytes to ${fullPath} (verified)`,
|
|
673
|
+
// Include truncation info if applicable
|
|
674
|
+
...(truncationApplied && {
|
|
675
|
+
wasTruncated: true,
|
|
676
|
+
truncationWarning: 'Content was truncated due to AI response token limit. A notice was appended to the file.'
|
|
677
|
+
}),
|
|
678
|
+
// Warn if content is empty
|
|
679
|
+
...(stats.size === 0 && {
|
|
680
|
+
emptyContent: true,
|
|
681
|
+
emptyWarning: 'File was written with empty content'
|
|
682
|
+
})
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// Add truncation warning to message
|
|
686
|
+
if (truncationApplied) {
|
|
687
|
+
result.message += ' [PARTIAL: AI response was truncated - content may be incomplete]';
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Post-write validation for structured files (plug-and-play via structuredFileValidator)
|
|
691
|
+
if (this.validateStructuredFiles) {
|
|
692
|
+
const validation = validateForToolResponse(content, fullPath);
|
|
693
|
+
if (validation) {
|
|
694
|
+
result.validation = validation;
|
|
695
|
+
// Add warning to message if validation failed
|
|
696
|
+
if (!validation.valid) {
|
|
697
|
+
result.message += ` [WARNING: ${validation.format.toUpperCase()} validation failed with ${validation.errorCount} error(s)]`;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return result;
|
|
703
|
+
|
|
704
|
+
} catch (error) {
|
|
705
|
+
throw new Error(`Failed to write file ${fullPath}: ${error.message}`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Append content to file
|
|
711
|
+
* @private
|
|
712
|
+
*/
|
|
713
|
+
async appendToFile(filePath, content, accessConfig, encoding = 'utf8') {
|
|
714
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
715
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
716
|
+
|
|
717
|
+
// Validate write access using DirectoryAccessManager
|
|
718
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
719
|
+
if (!accessResult.allowed) {
|
|
720
|
+
throw new Error(`Write access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
try {
|
|
724
|
+
// Check if file exists and get current size
|
|
725
|
+
let currentSize = 0;
|
|
726
|
+
try {
|
|
727
|
+
const stats = await fs.stat(fullPath);
|
|
728
|
+
currentSize = stats.size;
|
|
729
|
+
} catch {
|
|
730
|
+
// File doesn't exist, will be created
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const contentSize = Buffer.byteLength(content, encoding);
|
|
734
|
+
if (currentSize + contentSize > this.maxFileSize) {
|
|
735
|
+
throw new Error(`File would become too large: ${currentSize + contentSize} bytes (max ${this.maxFileSize})`);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Store size before append for verification
|
|
739
|
+
const sizeBefore = currentSize;
|
|
740
|
+
|
|
741
|
+
await fs.appendFile(fullPath, content, encoding);
|
|
742
|
+
|
|
743
|
+
const stats = await fs.stat(fullPath);
|
|
744
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
745
|
+
|
|
746
|
+
// VERIFICATION: Confirm append actually happened
|
|
747
|
+
const expectedSize = sizeBefore + contentSize;
|
|
748
|
+
if (stats.size < expectedSize) {
|
|
749
|
+
throw new Error(`Append verification failed: expected at least ${expectedSize} bytes but file is ${stats.size} bytes`);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// For text files, verify the appended content is at the end
|
|
753
|
+
if (encoding === 'utf8' || encoding === 'utf-8') {
|
|
754
|
+
const fileContent = await fs.readFile(fullPath, encoding);
|
|
755
|
+
if (!fileContent.endsWith(content)) {
|
|
756
|
+
throw new Error(`Append verification failed: appended content not found at end of file`);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
return {
|
|
761
|
+
success: true,
|
|
762
|
+
action: 'append',
|
|
763
|
+
filePath: relativePath,
|
|
764
|
+
fullPath: fullPath,
|
|
765
|
+
appendedBytes: contentSize,
|
|
766
|
+
totalSize: stats.size,
|
|
767
|
+
sizeBefore: sizeBefore,
|
|
768
|
+
encoding,
|
|
769
|
+
verified: true,
|
|
770
|
+
message: `Appended ${contentSize} bytes to ${fullPath} (verified)`
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
} catch (error) {
|
|
774
|
+
throw new Error(`Failed to append to file ${fullPath}: ${error.message}`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Delete file
|
|
780
|
+
* @private
|
|
781
|
+
*/
|
|
782
|
+
async deleteFile(filePath, accessConfig) {
|
|
783
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
784
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
785
|
+
|
|
786
|
+
// Validate write access for deletion
|
|
787
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
788
|
+
if (!accessResult.allowed) {
|
|
789
|
+
throw new Error(`Delete access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
try {
|
|
793
|
+
const stats = await fs.stat(fullPath);
|
|
794
|
+
|
|
795
|
+
// Create backup before deletion
|
|
796
|
+
const backupPath = `${fullPath}.deleted-backup-${Date.now()}`;
|
|
797
|
+
await fs.copyFile(fullPath, backupPath);
|
|
798
|
+
|
|
799
|
+
await fs.unlink(fullPath);
|
|
800
|
+
|
|
801
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
802
|
+
const backupRelativePath = this.directoryAccessManager.createRelativePath(backupPath, accessConfig);
|
|
803
|
+
|
|
804
|
+
return {
|
|
805
|
+
success: true,
|
|
806
|
+
action: 'delete',
|
|
807
|
+
filePath: relativePath,
|
|
808
|
+
fullPath: fullPath,
|
|
809
|
+
size: stats.size,
|
|
810
|
+
backupPath: backupRelativePath,
|
|
811
|
+
backupFullPath: backupPath,
|
|
812
|
+
message: `Deleted ${fullPath} (backup created)`
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
} catch (error) {
|
|
816
|
+
throw new Error(`Failed to delete file ${fullPath}: ${error.message}`);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Copy file
|
|
822
|
+
* @private
|
|
823
|
+
*/
|
|
824
|
+
async copyFile(sourcePath, destPath, accessConfig) {
|
|
825
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
826
|
+
const fullSourcePath = this.resolvePath(sourcePath, workingDir);
|
|
827
|
+
const fullDestPath = this.resolvePath(destPath, workingDir);
|
|
828
|
+
|
|
829
|
+
// Validate read access for source
|
|
830
|
+
const sourceAccessResult = this.directoryAccessManager.validateReadAccess(fullSourcePath, accessConfig);
|
|
831
|
+
if (!sourceAccessResult.allowed) {
|
|
832
|
+
throw new Error(`Source read access denied: ${sourceAccessResult.reason} (${sourceAccessResult.path})`);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Validate write access for destination
|
|
836
|
+
const destAccessResult = this.directoryAccessManager.validateWriteAccess(fullDestPath, accessConfig);
|
|
837
|
+
if (!destAccessResult.allowed) {
|
|
838
|
+
throw new Error(`Destination write access denied: ${destAccessResult.reason} (${destAccessResult.path})`);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
try {
|
|
842
|
+
const sourceStats = await fs.stat(fullSourcePath);
|
|
843
|
+
|
|
844
|
+
if (sourceStats.size > this.maxFileSize) {
|
|
845
|
+
throw new Error(`Source file too large: ${sourceStats.size} bytes`);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Create destination directory if needed
|
|
849
|
+
const destDir = path.dirname(fullDestPath);
|
|
850
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
851
|
+
|
|
852
|
+
await fs.copyFile(fullSourcePath, fullDestPath);
|
|
853
|
+
|
|
854
|
+
const sourceRelativePath = this.directoryAccessManager.createRelativePath(fullSourcePath, accessConfig);
|
|
855
|
+
const destRelativePath = this.directoryAccessManager.createRelativePath(fullDestPath, accessConfig);
|
|
856
|
+
|
|
857
|
+
return {
|
|
858
|
+
success: true,
|
|
859
|
+
action: 'copy',
|
|
860
|
+
sourcePath: sourceRelativePath,
|
|
861
|
+
destPath: destRelativePath,
|
|
862
|
+
sourceFullPath: fullSourcePath,
|
|
863
|
+
destFullPath: fullDestPath,
|
|
864
|
+
size: sourceStats.size,
|
|
865
|
+
message: `Copied ${fullSourcePath} to ${fullDestPath}`
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
} catch (error) {
|
|
869
|
+
throw new Error(`Failed to copy ${fullSourcePath} to ${fullDestPath}: ${error.message}`);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Move/rename file
|
|
875
|
+
* @private
|
|
876
|
+
*/
|
|
877
|
+
async moveFile(sourcePath, destPath, accessConfig) {
|
|
878
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
879
|
+
const fullSourcePath = this.resolvePath(sourcePath, workingDir);
|
|
880
|
+
const fullDestPath = this.resolvePath(destPath, workingDir);
|
|
881
|
+
|
|
882
|
+
// Validate read access for source
|
|
883
|
+
const readResult = this.directoryAccessManager.validateReadAccess(fullSourcePath, accessConfig);
|
|
884
|
+
if (!readResult.allowed) {
|
|
885
|
+
throw new Error(`Read access denied for source: ${readResult.reason} (${readResult.path})`);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Validate write access for destination
|
|
889
|
+
const writeResult = this.directoryAccessManager.validateWriteAccess(fullDestPath, accessConfig);
|
|
890
|
+
if (!writeResult.allowed) {
|
|
891
|
+
throw new Error(`Write access denied for destination: ${writeResult.reason} (${writeResult.path})`);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
try {
|
|
895
|
+
const sourceStats = await fs.stat(fullSourcePath);
|
|
896
|
+
|
|
897
|
+
// Create destination directory if needed
|
|
898
|
+
const destDir = path.dirname(fullDestPath);
|
|
899
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
900
|
+
|
|
901
|
+
await fs.rename(fullSourcePath, fullDestPath);
|
|
902
|
+
|
|
903
|
+
const relativeSource = this.directoryAccessManager.createRelativePath(fullSourcePath, accessConfig);
|
|
904
|
+
const relativeDest = this.directoryAccessManager.createRelativePath(fullDestPath, accessConfig);
|
|
905
|
+
|
|
906
|
+
return {
|
|
907
|
+
success: true,
|
|
908
|
+
action: 'move',
|
|
909
|
+
sourcePath: relativeSource,
|
|
910
|
+
destPath: relativeDest,
|
|
911
|
+
fullSourcePath: fullSourcePath,
|
|
912
|
+
fullDestPath: fullDestPath,
|
|
913
|
+
size: sourceStats.size,
|
|
914
|
+
message: `Moved ${sourcePath} to ${destPath}`
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
} catch (error) {
|
|
918
|
+
throw new Error(`Failed to move ${sourcePath} to ${destPath}: ${error.message}`);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Create directory
|
|
924
|
+
* @private
|
|
925
|
+
*/
|
|
926
|
+
async createDirectory(directory, accessConfig) {
|
|
927
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
928
|
+
const fullPath = this.resolvePath(directory, workingDir);
|
|
929
|
+
|
|
930
|
+
// Validate write access using DirectoryAccessManager
|
|
931
|
+
const accessResult = this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig);
|
|
932
|
+
if (!accessResult.allowed) {
|
|
933
|
+
throw new Error(`Write access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
try {
|
|
937
|
+
await fs.mkdir(fullPath, { recursive: true });
|
|
938
|
+
|
|
939
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
940
|
+
|
|
941
|
+
return {
|
|
942
|
+
success: true,
|
|
943
|
+
action: 'create-dir',
|
|
944
|
+
directory: relativePath,
|
|
945
|
+
fullPath: fullPath,
|
|
946
|
+
message: `Created directory ${directory}`
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
} catch (error) {
|
|
950
|
+
throw new Error(`Failed to create directory ${directory}: ${error.message}`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* List directory contents
|
|
956
|
+
* @private
|
|
957
|
+
*/
|
|
958
|
+
async listDirectory(directory, accessConfig) {
|
|
959
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
960
|
+
const fullPath = this.resolvePath(directory, workingDir);
|
|
961
|
+
|
|
962
|
+
// Validate read access using DirectoryAccessManager
|
|
963
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
964
|
+
if (!accessResult.allowed) {
|
|
965
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
try {
|
|
969
|
+
const entries = await fs.readdir(fullPath, { withFileTypes: true });
|
|
970
|
+
|
|
971
|
+
const contents = [];
|
|
972
|
+
for (const entry of entries) {
|
|
973
|
+
const entryPath = path.join(fullPath, entry.name);
|
|
974
|
+
const stats = await fs.stat(entryPath);
|
|
975
|
+
|
|
976
|
+
contents.push({
|
|
977
|
+
name: entry.name,
|
|
978
|
+
type: entry.isDirectory() ? 'directory' : 'file',
|
|
979
|
+
size: entry.isFile() ? stats.size : undefined,
|
|
980
|
+
lastModified: stats.mtime.toISOString(),
|
|
981
|
+
permissions: stats.mode,
|
|
982
|
+
isSymlink: entry.isSymbolicLink()
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
987
|
+
|
|
988
|
+
return {
|
|
989
|
+
success: true,
|
|
990
|
+
action: 'list',
|
|
991
|
+
directory: relativePath,
|
|
992
|
+
fullPath: fullPath,
|
|
993
|
+
contents,
|
|
994
|
+
totalItems: contents.length,
|
|
995
|
+
directories: contents.filter(item => item.type === 'directory').length,
|
|
996
|
+
files: contents.filter(item => item.type === 'file').length,
|
|
997
|
+
message: `Listed ${contents.length} items in ${directory}`
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
throw new Error(`Failed to list directory ${directory}: ${error.message}`);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Check if file/directory exists
|
|
1007
|
+
* @private
|
|
1008
|
+
*/
|
|
1009
|
+
async checkExists(filePath, accessConfig) {
|
|
1010
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1011
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
1012
|
+
|
|
1013
|
+
// Validate read access
|
|
1014
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1015
|
+
if (!accessResult.allowed) {
|
|
1016
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
try {
|
|
1020
|
+
const stats = await fs.stat(fullPath);
|
|
1021
|
+
|
|
1022
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1023
|
+
|
|
1024
|
+
return {
|
|
1025
|
+
success: true,
|
|
1026
|
+
action: 'exists',
|
|
1027
|
+
filePath: relativePath,
|
|
1028
|
+
fullPath: fullPath,
|
|
1029
|
+
exists: true,
|
|
1030
|
+
type: stats.isDirectory() ? 'directory' : 'file',
|
|
1031
|
+
message: `${filePath} exists as ${stats.isDirectory() ? 'directory' : 'file'}`
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
} catch (error) {
|
|
1035
|
+
if (error.code === 'ENOENT') {
|
|
1036
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1037
|
+
return {
|
|
1038
|
+
success: true,
|
|
1039
|
+
action: 'exists',
|
|
1040
|
+
filePath: relativePath,
|
|
1041
|
+
fullPath: fullPath,
|
|
1042
|
+
exists: false,
|
|
1043
|
+
message: `${filePath} does not exist`
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
throw new Error(`Failed to check existence of ${filePath}: ${error.message}`);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* Get file statistics
|
|
1053
|
+
* @private
|
|
1054
|
+
*/
|
|
1055
|
+
async getFileStats(filePath, accessConfig) {
|
|
1056
|
+
const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
|
|
1057
|
+
const fullPath = this.resolvePath(filePath, workingDir);
|
|
1058
|
+
|
|
1059
|
+
// Validate read access
|
|
1060
|
+
const accessResult = this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1061
|
+
if (!accessResult.allowed) {
|
|
1062
|
+
throw new Error(`Read access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
try {
|
|
1066
|
+
const stats = await fs.stat(fullPath);
|
|
1067
|
+
|
|
1068
|
+
const relativePath = this.directoryAccessManager.createRelativePath(fullPath, accessConfig);
|
|
1069
|
+
|
|
1070
|
+
return {
|
|
1071
|
+
success: true,
|
|
1072
|
+
action: 'stats',
|
|
1073
|
+
filePath: relativePath,
|
|
1074
|
+
fullPath: fullPath,
|
|
1075
|
+
stats: {
|
|
1076
|
+
size: stats.size,
|
|
1077
|
+
type: stats.isDirectory() ? 'directory' : 'file',
|
|
1078
|
+
lastModified: stats.mtime.toISOString(),
|
|
1079
|
+
lastAccessed: stats.atime.toISOString(),
|
|
1080
|
+
created: stats.birthtime.toISOString(),
|
|
1081
|
+
permissions: stats.mode,
|
|
1082
|
+
isSymlink: stats.isSymbolicLink()
|
|
1083
|
+
},
|
|
1084
|
+
message: `Retrieved stats for ${filePath}`
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
throw new Error(`Failed to get stats for ${filePath}: ${error.message}`);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Resolve file path safely (legacy method for compatibility)
|
|
1094
|
+
* @private
|
|
1095
|
+
*/
|
|
1096
|
+
resolvePath(filePath, workingDir) {
|
|
1097
|
+
if (path.isAbsolute(filePath)) {
|
|
1098
|
+
return path.normalize(filePath);
|
|
1099
|
+
}
|
|
1100
|
+
return path.resolve(workingDir, filePath);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* Validate path access using DirectoryAccessManager
|
|
1105
|
+
* @private
|
|
1106
|
+
*/
|
|
1107
|
+
validatePathAccess(fullPath, accessConfig, operation = 'read') {
|
|
1108
|
+
const accessResult = operation === 'write'
|
|
1109
|
+
? this.directoryAccessManager.validateWriteAccess(fullPath, accessConfig)
|
|
1110
|
+
: this.directoryAccessManager.validateReadAccess(fullPath, accessConfig);
|
|
1111
|
+
|
|
1112
|
+
if (!accessResult.allowed) {
|
|
1113
|
+
throw new Error(`${operation} access denied: ${accessResult.reason} (${accessResult.path})`);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return accessResult;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Check if file extension is allowed
|
|
1121
|
+
* @private
|
|
1122
|
+
*/
|
|
1123
|
+
isAllowedFileExtension(filePath) {
|
|
1124
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
1125
|
+
|
|
1126
|
+
if (this.blockedExtensions.includes(ext)) {
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (this.allowedExtensions && !this.allowedExtensions.includes(ext)) {
|
|
1131
|
+
return false;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
return true;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* Add operation to history
|
|
1139
|
+
* @private
|
|
1140
|
+
*/
|
|
1141
|
+
addToHistory(action, result, agentId) {
|
|
1142
|
+
const historyEntry = {
|
|
1143
|
+
timestamp: new Date().toISOString(),
|
|
1144
|
+
agentId,
|
|
1145
|
+
action: action.type,
|
|
1146
|
+
filePath: action.filePath || action.outputPath || action.directory,
|
|
1147
|
+
success: result.success,
|
|
1148
|
+
size: result.size
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
this.operationHistory.push(historyEntry);
|
|
1152
|
+
|
|
1153
|
+
// Keep only last 200 entries
|
|
1154
|
+
if (this.operationHistory.length > 200) {
|
|
1155
|
+
this.operationHistory = this.operationHistory.slice(-200);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Get supported actions for this tool
|
|
1161
|
+
* @returns {Array<string>} Array of supported action names
|
|
1162
|
+
*/
|
|
1163
|
+
getSupportedActions() {
|
|
1164
|
+
return [
|
|
1165
|
+
'read', 'write', 'append', 'delete', 'copy', 'move',
|
|
1166
|
+
'create-dir', 'list', 'exists', 'stats'
|
|
1167
|
+
];
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* Get parameter schema for validation
|
|
1172
|
+
* @returns {Object} Parameter schema
|
|
1173
|
+
*/
|
|
1174
|
+
getParameterSchema() {
|
|
1175
|
+
return {
|
|
1176
|
+
type: 'object',
|
|
1177
|
+
properties: {
|
|
1178
|
+
actions: {
|
|
1179
|
+
type: 'array',
|
|
1180
|
+
minItems: 1,
|
|
1181
|
+
items: {
|
|
1182
|
+
type: 'object',
|
|
1183
|
+
properties: {
|
|
1184
|
+
type: {
|
|
1185
|
+
type: 'string',
|
|
1186
|
+
enum: this.getSupportedActions()
|
|
1187
|
+
},
|
|
1188
|
+
filePath: { type: 'string' },
|
|
1189
|
+
outputPath: { type: 'string' },
|
|
1190
|
+
sourcePath: { type: 'string' },
|
|
1191
|
+
destPath: { type: 'string' },
|
|
1192
|
+
directory: { type: 'string' },
|
|
1193
|
+
content: { type: 'string' },
|
|
1194
|
+
encoding: { type: 'string' },
|
|
1195
|
+
createDirs: { type: 'boolean' }
|
|
1196
|
+
},
|
|
1197
|
+
required: ['type']
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
},
|
|
1201
|
+
required: ['actions']
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* Get operation history for debugging
|
|
1207
|
+
* @returns {Array} Operation history
|
|
1208
|
+
*/
|
|
1209
|
+
getOperationHistory(agentId = null) {
|
|
1210
|
+
if (agentId) {
|
|
1211
|
+
return this.operationHistory.filter(entry => entry.agentId === agentId);
|
|
1212
|
+
}
|
|
1213
|
+
return [...this.operationHistory];
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
export default FileSystemTool;
|