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,920 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TelegramService — Remote agent interface via Telegram Bot
|
|
3
|
+
*
|
|
4
|
+
* Purpose:
|
|
5
|
+
* - Full conversational interface with agents from phone
|
|
6
|
+
* - @agent-name prefix routing (sticky session for no-prefix)
|
|
7
|
+
* - Smart response formatting (markdown, code blocks, images, inline keyboards)
|
|
8
|
+
* - On-demand notifications (/watch)
|
|
9
|
+
* - Prompt/credential relay for interactive agent flows
|
|
10
|
+
*
|
|
11
|
+
* Architecture:
|
|
12
|
+
* - Long polling (no webhook, works behind NAT)
|
|
13
|
+
* - Intercepts WebSocket broadcasts to capture agent responses
|
|
14
|
+
* - Routes user messages to agents via orchestrator.processRequest()
|
|
15
|
+
* - Optional dependency — system works without it
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { promises as fs } from 'fs';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { getUserDataPaths, ensureUserDataDirs } from '../utilities/userDataDir.js';
|
|
21
|
+
|
|
22
|
+
const TELEGRAM_STATUS = {
|
|
23
|
+
DISCONNECTED: 'disconnected',
|
|
24
|
+
CONNECTING: 'connecting',
|
|
25
|
+
CONNECTED: 'connected',
|
|
26
|
+
FAILED: 'failed'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const MAX_MESSAGE_LENGTH = 4000; // Telegram limit is 4096, leave room for formatting
|
|
30
|
+
const NOTIFICATION_BATCH_INTERVAL_MS = 10000;
|
|
31
|
+
const PROMPT_TIMEOUT_MS = 300000; // 5 minutes
|
|
32
|
+
const PROMPT_REMINDER_MS = 180000; // 3 minutes
|
|
33
|
+
|
|
34
|
+
class TelegramService {
|
|
35
|
+
constructor(logger = null) {
|
|
36
|
+
this.logger = logger;
|
|
37
|
+
|
|
38
|
+
// Dependencies (set via setters)
|
|
39
|
+
this.orchestrator = null;
|
|
40
|
+
this.agentPool = null;
|
|
41
|
+
this.webSocketManager = null;
|
|
42
|
+
this.flowExecutor = null;
|
|
43
|
+
|
|
44
|
+
// Bot state
|
|
45
|
+
this.bot = null;
|
|
46
|
+
this.status = TELEGRAM_STATUS.DISCONNECTED;
|
|
47
|
+
this.chatId = null;
|
|
48
|
+
this.lastAgentId = null;
|
|
49
|
+
this.activeAgentIds = new Set(); // all agents user has addressed from Telegram
|
|
50
|
+
|
|
51
|
+
// Relay state
|
|
52
|
+
this.pendingRelays = new Map();
|
|
53
|
+
this.replyContext = null; // current expected reply
|
|
54
|
+
|
|
55
|
+
// Notifications
|
|
56
|
+
this.watchEnabled = false;
|
|
57
|
+
this.notificationQueue = [];
|
|
58
|
+
this.notificationTimer = null;
|
|
59
|
+
|
|
60
|
+
// Config
|
|
61
|
+
this.dataDir = null;
|
|
62
|
+
this.configPath = null;
|
|
63
|
+
this.config = {};
|
|
64
|
+
|
|
65
|
+
// Original broadcast (saved before wrapping)
|
|
66
|
+
this._originalBroadcast = null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- Dependency Injection ---
|
|
70
|
+
|
|
71
|
+
setOrchestrator(orchestrator) { this.orchestrator = orchestrator; }
|
|
72
|
+
setAgentPool(agentPool) { this.agentPool = agentPool; }
|
|
73
|
+
setWebSocketManager(wsManager) {
|
|
74
|
+
this.webSocketManager = wsManager;
|
|
75
|
+
this._interceptBroadcasts(wsManager);
|
|
76
|
+
}
|
|
77
|
+
setFlowExecutor(flowExecutor) { this.flowExecutor = flowExecutor; }
|
|
78
|
+
|
|
79
|
+
// --- Config Persistence ---
|
|
80
|
+
|
|
81
|
+
async _ensureDataDir() {
|
|
82
|
+
if (!this.dataDir) {
|
|
83
|
+
await ensureUserDataDirs();
|
|
84
|
+
const paths = getUserDataPaths();
|
|
85
|
+
this.dataDir = path.join(paths.base, 'telegram');
|
|
86
|
+
this.configPath = path.join(this.dataDir, 'telegram-config.json');
|
|
87
|
+
await fs.mkdir(this.dataDir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async _loadConfig() {
|
|
92
|
+
await this._ensureDataDir();
|
|
93
|
+
try {
|
|
94
|
+
const data = await fs.readFile(this.configPath, 'utf8');
|
|
95
|
+
this.config = JSON.parse(data);
|
|
96
|
+
this.chatId = this.config.chatId || null;
|
|
97
|
+
this.watchEnabled = this.config.watchEnabled || false;
|
|
98
|
+
} catch {
|
|
99
|
+
this.config = {};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async _saveConfig() {
|
|
104
|
+
await this._ensureDataDir();
|
|
105
|
+
this.config.chatId = this.chatId;
|
|
106
|
+
this.config.watchEnabled = this.watchEnabled;
|
|
107
|
+
this.config.updatedAt = new Date().toISOString();
|
|
108
|
+
await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2), 'utf8');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// --- Lifecycle ---
|
|
112
|
+
|
|
113
|
+
async autoConnect() {
|
|
114
|
+
await this._loadConfig();
|
|
115
|
+
if (this.config.botToken) {
|
|
116
|
+
try {
|
|
117
|
+
await this.connect(this.config.botToken);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
this.logger?.warn('[TelegramService] Auto-connect failed', { error: error.message });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async connect(botToken) {
|
|
125
|
+
if (this.status === TELEGRAM_STATUS.CONNECTED) {
|
|
126
|
+
await this.disconnect();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.status = TELEGRAM_STATUS.CONNECTING;
|
|
130
|
+
this.logger?.info('[TelegramService] Connecting...');
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const TelegramBot = (await import('node-telegram-bot-api')).default;
|
|
134
|
+
this.bot = new TelegramBot(botToken, { polling: true });
|
|
135
|
+
|
|
136
|
+
// Verify token by getting bot info
|
|
137
|
+
const me = await this.bot.getMe();
|
|
138
|
+
this.logger?.info('[TelegramService] Connected', { botName: me.username });
|
|
139
|
+
|
|
140
|
+
this.config.botToken = botToken;
|
|
141
|
+
this.config.botUsername = me.username;
|
|
142
|
+
await this._saveConfig();
|
|
143
|
+
|
|
144
|
+
this._setupHandlers();
|
|
145
|
+
this.status = TELEGRAM_STATUS.CONNECTED;
|
|
146
|
+
|
|
147
|
+
return { username: me.username, id: me.id };
|
|
148
|
+
} catch (error) {
|
|
149
|
+
this.status = TELEGRAM_STATUS.FAILED;
|
|
150
|
+
this.logger?.error('[TelegramService] Connection failed', { error: error.message });
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async disconnect() {
|
|
156
|
+
if (this.bot) {
|
|
157
|
+
try { await this.bot.stopPolling(); } catch {}
|
|
158
|
+
this.bot = null;
|
|
159
|
+
}
|
|
160
|
+
this.status = TELEGRAM_STATUS.DISCONNECTED;
|
|
161
|
+
this._clearNotificationTimer();
|
|
162
|
+
this.logger?.info('[TelegramService] Disconnected');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
getStatus() {
|
|
166
|
+
return {
|
|
167
|
+
status: this.status,
|
|
168
|
+
connected: this.status === TELEGRAM_STATUS.CONNECTED,
|
|
169
|
+
chatId: this.chatId,
|
|
170
|
+
botUsername: this.config.botUsername || null,
|
|
171
|
+
watchEnabled: this.watchEnabled
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// --- Command & Message Handlers ---
|
|
176
|
+
|
|
177
|
+
_setupHandlers() {
|
|
178
|
+
if (!this.bot) return;
|
|
179
|
+
|
|
180
|
+
this.bot.onText(/\/start/, (msg) => this._cmdStart(msg));
|
|
181
|
+
this.bot.onText(/\/help/, (msg) => this._cmdHelp(msg));
|
|
182
|
+
this.bot.onText(/\/status/, (msg) => this._cmdStatus(msg));
|
|
183
|
+
this.bot.onText(/\/agents/, (msg) => this._cmdAgents(msg));
|
|
184
|
+
this.bot.onText(/\/agent (.+)/, (msg, match) => this._cmdAgentDetail(msg, match[1].trim()));
|
|
185
|
+
this.bot.onText(/\/flows/, (msg) => this._cmdFlows(msg));
|
|
186
|
+
this.bot.onText(/\/run (.+)/, (msg, match) => this._cmdRunFlow(msg, match[1].trim()));
|
|
187
|
+
this.bot.onText(/\/stop (.+)/, (msg, match) => this._cmdStopAgent(msg, match[1].trim()));
|
|
188
|
+
this.bot.onText(/\/following/, (msg) => this._cmdFollowing(msg));
|
|
189
|
+
this.bot.onText(/\/unfollow (.+)/, (msg, match) => this._cmdUnfollow(msg, match[1].trim()));
|
|
190
|
+
this.bot.onText(/\/watch/, (msg) => this._cmdWatch(msg));
|
|
191
|
+
this.bot.onText(/\/unwatch/, (msg) => this._cmdUnwatch(msg));
|
|
192
|
+
this.bot.onText(/\/watching/, (msg) => this._cmdWatching(msg));
|
|
193
|
+
|
|
194
|
+
// Handle non-command text (agent messages)
|
|
195
|
+
this.bot.on('message', (msg) => {
|
|
196
|
+
if (msg.text && !msg.text.startsWith('/')) {
|
|
197
|
+
this._handleTextMessage(msg);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Handle inline keyboard callbacks
|
|
202
|
+
this.bot.on('callback_query', (query) => this._handleCallbackQuery(query));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
_isAuthorized(msg) {
|
|
206
|
+
return this.chatId && String(msg.chat.id) === String(this.chatId);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async _cmdStart(msg) {
|
|
210
|
+
const chatId = String(msg.chat.id);
|
|
211
|
+
|
|
212
|
+
if (!this.chatId) {
|
|
213
|
+
this.chatId = chatId;
|
|
214
|
+
await this._saveConfig();
|
|
215
|
+
await this._send(chatId, this._escapeMarkdown('*Loxia Autopilot connected!* 🚀\n\nThis chat is now linked. Use /help to see available commands.\n\nAddress agents with @agent-name your message.'));
|
|
216
|
+
} else if (chatId === this.chatId) {
|
|
217
|
+
await this._send(chatId, this._escapeMarkdown('Already connected. Use /help for commands.'));
|
|
218
|
+
} else {
|
|
219
|
+
await this._send(chatId, this._escapeMarkdown('⛔ Another chat is already registered. Disconnect from the web UI first.'));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async _cmdHelp(msg) {
|
|
224
|
+
if (!this._isAuthorized(msg)) return;
|
|
225
|
+
const help = [
|
|
226
|
+
'*Loxia Autopilot — Telegram Remote*\n',
|
|
227
|
+
'*Chat with agents:*',
|
|
228
|
+
'`@agent-name your message` — send to specific agent',
|
|
229
|
+
'Type without prefix — sends to last used agent\n',
|
|
230
|
+
'*Commands:*',
|
|
231
|
+
'/agents — list all agents',
|
|
232
|
+
'/agent <name> — agent detail',
|
|
233
|
+
'/status — system overview',
|
|
234
|
+
'/following — agents you\'re following',
|
|
235
|
+
'/unfollow <name> — stop following an agent',
|
|
236
|
+
'/flows — list flows',
|
|
237
|
+
'/run <flow> — start a flow',
|
|
238
|
+
'/stop <agent> — stop agent execution',
|
|
239
|
+
'/watch — subscribe to notifications',
|
|
240
|
+
'/unwatch — unsubscribe',
|
|
241
|
+
'/watching — notification status',
|
|
242
|
+
'/help — this message'
|
|
243
|
+
];
|
|
244
|
+
await this._send(msg.chat.id, this._escapeMarkdown(help.join('\n')));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async _cmdStatus(msg) {
|
|
248
|
+
if (!this._isAuthorized(msg)) return;
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
252
|
+
const active = agents.filter(a => a.status === 'active' || a.mode === 'auto');
|
|
253
|
+
const idle = agents.filter(a => a.mode === 'chat' || a.status === 'idle');
|
|
254
|
+
|
|
255
|
+
let text = `*System Status*\n\n`;
|
|
256
|
+
text += `Agents: ${agents.length} total, ${active.length} active, ${idle.length} idle\n`;
|
|
257
|
+
text += `Notifications: ${this.watchEnabled ? '🔔 On' : '🔕 Off'}`;
|
|
258
|
+
|
|
259
|
+
await this._send(msg.chat.id, this._escapeMarkdown(text));
|
|
260
|
+
} catch (error) {
|
|
261
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Error: ${error.message}`));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async _cmdAgents(msg) {
|
|
266
|
+
if (!this._isAuthorized(msg)) return;
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
270
|
+
if (agents.length === 0) {
|
|
271
|
+
await this._send(msg.chat.id, this._escapeMarkdown('No agents loaded.'));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let text = `*Agents (${agents.length}):*\n\n`;
|
|
276
|
+
const buttons = [];
|
|
277
|
+
|
|
278
|
+
for (const agent of agents) {
|
|
279
|
+
const status = agent.mode === 'auto' ? '🟢' : agent.status === 'active' ? '🟡' : '⚪';
|
|
280
|
+
const mode = agent.mode === 'auto' ? 'autonomous' : 'chat';
|
|
281
|
+
text += `${status} *${this._escapeMarkdown(agent.name)}* — ${mode}\n`;
|
|
282
|
+
buttons.push([{ text: agent.name, callback_data: `agent_detail:${agent.id}` }]);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
await this._send(msg.chat.id, text, {
|
|
286
|
+
reply_markup: { inline_keyboard: buttons }
|
|
287
|
+
});
|
|
288
|
+
} catch (error) {
|
|
289
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Error: ${error.message}`));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async _cmdAgentDetail(msg, agentName) {
|
|
294
|
+
if (!this._isAuthorized(msg)) return;
|
|
295
|
+
await this._showAgentDetail(msg.chat.id, agentName);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async _showAgentDetail(chatId, agentNameOrId) {
|
|
299
|
+
try {
|
|
300
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
301
|
+
const agent = agents.find(a =>
|
|
302
|
+
a.name.toLowerCase() === agentNameOrId.toLowerCase() ||
|
|
303
|
+
a.id === agentNameOrId
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
if (!agent) {
|
|
307
|
+
await this._send(chatId, this._escapeMarkdown(`Agent "${agentNameOrId}" not found.`));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const status = agent.mode === 'auto' ? '🟢 Autonomous' : '🟡 Chat';
|
|
312
|
+
let text = `*${this._escapeMarkdown(agent.name)}*\n\n`;
|
|
313
|
+
text += `Status: ${status}\n`;
|
|
314
|
+
text += `Model: \`${this._escapeMarkdown(agent.currentModel || 'unknown')}\`\n`;
|
|
315
|
+
if (agent.lastActivity) {
|
|
316
|
+
text += `Last active: ${new Date(agent.lastActivity).toLocaleTimeString()}\n`;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const buttons = [
|
|
320
|
+
[
|
|
321
|
+
{ text: '💬 Send Message', callback_data: `msg_agent:${agent.id}` },
|
|
322
|
+
{ text: '⏹ Stop', callback_data: `stop_agent:${agent.id}` }
|
|
323
|
+
]
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
await this._send(chatId, text, { reply_markup: { inline_keyboard: buttons } });
|
|
327
|
+
} catch (error) {
|
|
328
|
+
await this._send(chatId, this._escapeMarkdown(`❌ Error: ${error.message}`));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async _cmdFlows(msg) {
|
|
333
|
+
if (!this._isAuthorized(msg)) return;
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
if (!this.orchestrator?.stateManager) {
|
|
337
|
+
await this._send(msg.chat.id, this._escapeMarkdown('Flows not available.'));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const projectDir = this.orchestrator.config?.project?.directory || process.cwd();
|
|
342
|
+
const flowIndex = await this.orchestrator.stateManager.loadFlowIndex?.(projectDir) || {};
|
|
343
|
+
const flows = Object.entries(flowIndex);
|
|
344
|
+
|
|
345
|
+
if (flows.length === 0) {
|
|
346
|
+
await this._send(msg.chat.id, this._escapeMarkdown('No flows defined.'));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
let text = `*Flows (${flows.length}):*\n\n`;
|
|
351
|
+
const buttons = [];
|
|
352
|
+
|
|
353
|
+
for (const [id, flow] of flows) {
|
|
354
|
+
text += `📋 *${this._escapeMarkdown(flow.name || id)}*\n`;
|
|
355
|
+
buttons.push([{ text: `▶️ Run ${flow.name || id}`, callback_data: `run_flow:${id}` }]);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
await this._send(msg.chat.id, text, { reply_markup: { inline_keyboard: buttons } });
|
|
359
|
+
} catch (error) {
|
|
360
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Error: ${error.message}`));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async _cmdRunFlow(msg, flowName) {
|
|
365
|
+
if (!this._isAuthorized(msg)) return;
|
|
366
|
+
await this._runFlow(msg.chat.id, flowName);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async _runFlow(chatId, flowNameOrId) {
|
|
370
|
+
try {
|
|
371
|
+
if (!this.flowExecutor) {
|
|
372
|
+
await this._send(chatId, this._escapeMarkdown('Flow executor not available.'));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
await this._send(chatId, this._escapeMarkdown(`▶️ Starting flow: ${flowNameOrId}...`));
|
|
377
|
+
// Flow execution is async — completion will be captured by broadcast listener
|
|
378
|
+
const projectDir = this.orchestrator?.config?.project?.directory || process.cwd();
|
|
379
|
+
await this.flowExecutor.executeFlow(flowNameOrId, { projectDir });
|
|
380
|
+
} catch (error) {
|
|
381
|
+
await this._send(chatId, this._escapeMarkdown(`❌ Flow error: ${error.message}`));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async _cmdStopAgent(msg, agentName) {
|
|
386
|
+
if (!this._isAuthorized(msg)) return;
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
390
|
+
const agent = agents.find(a => a.name.toLowerCase() === agentName.toLowerCase());
|
|
391
|
+
if (!agent) {
|
|
392
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`Agent "${agentName}" not found.`));
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (this.orchestrator?.messageProcessor) {
|
|
397
|
+
await this.orchestrator.messageProcessor.stopAutonomousExecution(agent.id);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`⏹ Stopped ${agent.name}`));
|
|
401
|
+
} catch (error) {
|
|
402
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Error: ${error.message}`));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async _cmdFollowing(msg) {
|
|
407
|
+
if (!this._isAuthorized(msg)) return;
|
|
408
|
+
|
|
409
|
+
if (this.activeAgentIds.size === 0) {
|
|
410
|
+
await this._send(msg.chat.id, this._escapeMarkdown('Not following any agents. Send @agent-name to start chatting.'));
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
415
|
+
let text = `*Following ${this.activeAgentIds.size} agent(s):*\n\n`;
|
|
416
|
+
const buttons = [];
|
|
417
|
+
|
|
418
|
+
for (const id of this.activeAgentIds) {
|
|
419
|
+
const agent = agents.find(a => a.id === id);
|
|
420
|
+
const name = agent?.name || id;
|
|
421
|
+
const isLast = id === this.lastAgentId;
|
|
422
|
+
text += `${isLast ? '💬' : '👁'} *${this._escapeMarkdown(name)}*${isLast ? ' \\(active\\)' : ''}\n`;
|
|
423
|
+
buttons.push([{ text: `❌ Unfollow ${name}`, callback_data: `unfollow:${id}` }]);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
text += '\n_Active = default for messages without @prefix_';
|
|
427
|
+
await this._send(msg.chat.id, text, { reply_markup: { inline_keyboard: buttons } });
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async _cmdUnfollow(msg, agentName) {
|
|
431
|
+
if (!this._isAuthorized(msg)) return;
|
|
432
|
+
|
|
433
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
434
|
+
const agent = agents.find(a => a.name.toLowerCase() === agentName.toLowerCase());
|
|
435
|
+
if (!agent || !this.activeAgentIds.has(agent.id)) {
|
|
436
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`Not following "${agentName}".`));
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
this.activeAgentIds.delete(agent.id);
|
|
441
|
+
if (this.lastAgentId === agent.id) {
|
|
442
|
+
// Switch lastAgentId to another active agent, or null
|
|
443
|
+
this.lastAgentId = this.activeAgentIds.size > 0 ? [...this.activeAgentIds][this.activeAgentIds.size - 1] : null;
|
|
444
|
+
}
|
|
445
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`Unfollowed ${agent.name}. Responses will no longer be relayed.`));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
async _cmdWatch(msg) {
|
|
449
|
+
if (!this._isAuthorized(msg)) return;
|
|
450
|
+
this.watchEnabled = true;
|
|
451
|
+
await this._saveConfig();
|
|
452
|
+
await this._send(msg.chat.id, this._escapeMarkdown('🔔 Notifications enabled. You\'ll receive alerts for errors, completions and prompts.'));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
async _cmdUnwatch(msg) {
|
|
456
|
+
if (!this._isAuthorized(msg)) return;
|
|
457
|
+
this.watchEnabled = false;
|
|
458
|
+
this._clearNotificationTimer();
|
|
459
|
+
await this._saveConfig();
|
|
460
|
+
await this._send(msg.chat.id, this._escapeMarkdown('🔕 Notifications disabled.'));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
async _cmdWatching(msg) {
|
|
464
|
+
if (!this._isAuthorized(msg)) return;
|
|
465
|
+
await this._send(msg.chat.id, this._escapeMarkdown(this.watchEnabled
|
|
466
|
+
? '🔔 Notifications are ON. Use /unwatch to disable.'
|
|
467
|
+
: '🔕 Notifications are OFF. Use /watch to enable.'
|
|
468
|
+
));
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// --- Agent Conversation ---
|
|
472
|
+
|
|
473
|
+
async _handleTextMessage(msg) {
|
|
474
|
+
if (!this._isAuthorized(msg)) return;
|
|
475
|
+
const text = msg.text?.trim();
|
|
476
|
+
if (!text) return;
|
|
477
|
+
|
|
478
|
+
// Check if this is a reply to a pending prompt relay
|
|
479
|
+
if (this.replyContext) {
|
|
480
|
+
await this._handlePromptReply(msg);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Parse @agent-name prefix
|
|
485
|
+
let agentName = null;
|
|
486
|
+
let messageText = text;
|
|
487
|
+
|
|
488
|
+
const atMatch = text.match(/^@(\S+)\s+([\s\S]+)/);
|
|
489
|
+
if (atMatch) {
|
|
490
|
+
agentName = atMatch[1];
|
|
491
|
+
messageText = atMatch[2].trim();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Resolve agent
|
|
495
|
+
let targetAgent = null;
|
|
496
|
+
if (agentName) {
|
|
497
|
+
const agents = this.agentPool ? await this.agentPool.getAllAgents() : [];
|
|
498
|
+
targetAgent = agents.find(a => a.name.toLowerCase() === agentName.toLowerCase());
|
|
499
|
+
if (!targetAgent) {
|
|
500
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Agent "${agentName}" not found. Use /agents to see available agents.`));
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
this.lastAgentId = targetAgent.id;
|
|
504
|
+
this.activeAgentIds.add(targetAgent.id);
|
|
505
|
+
} else if (this.lastAgentId) {
|
|
506
|
+
// Sticky session
|
|
507
|
+
targetAgent = this.agentPool ? await this.agentPool.getAgent(this.lastAgentId) : null;
|
|
508
|
+
if (!targetAgent) {
|
|
509
|
+
await this._send(msg.chat.id, this._escapeMarkdown('No agent selected. Use @agent-name message to address one.'));
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
} else {
|
|
513
|
+
await this._send(msg.chat.id, this._escapeMarkdown('No agent selected. Use @agent-name message to address one.'));
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Send to agent
|
|
518
|
+
try {
|
|
519
|
+
await this._send(msg.chat.id, `📨 → *${this._escapeMarkdown(targetAgent.name)}*`);
|
|
520
|
+
|
|
521
|
+
if (this.orchestrator) {
|
|
522
|
+
const sessionId = `telegram-${this.chatId}`;
|
|
523
|
+
await this.orchestrator.processRequest({
|
|
524
|
+
interface: 'telegram',
|
|
525
|
+
sessionId,
|
|
526
|
+
action: 'send_message',
|
|
527
|
+
payload: {
|
|
528
|
+
agentId: targetAgent.id,
|
|
529
|
+
message: messageText,
|
|
530
|
+
streamingEnabled: false
|
|
531
|
+
},
|
|
532
|
+
projectDir: this.orchestrator.config?.project?.directory || process.cwd()
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
} catch (error) {
|
|
536
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Failed to send: ${error.message}`));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// --- Callback Query Handler (Inline Keyboards) ---
|
|
541
|
+
|
|
542
|
+
async _handleCallbackQuery(query) {
|
|
543
|
+
if (!this.chatId || String(query.message.chat.id) !== String(this.chatId)) return;
|
|
544
|
+
|
|
545
|
+
const data = query.data;
|
|
546
|
+
try {
|
|
547
|
+
await this.bot.answerCallbackQuery(query.id);
|
|
548
|
+
} catch {}
|
|
549
|
+
|
|
550
|
+
if (data.startsWith('agent_detail:')) {
|
|
551
|
+
const agentId = data.replace('agent_detail:', '');
|
|
552
|
+
await this._showAgentDetail(query.message.chat.id, agentId);
|
|
553
|
+
} else if (data.startsWith('msg_agent:')) {
|
|
554
|
+
const agentId = data.replace('msg_agent:', '');
|
|
555
|
+
this.lastAgentId = agentId;
|
|
556
|
+
this.activeAgentIds.add(agentId);
|
|
557
|
+
const agent = this.agentPool ? await this.agentPool.getAgent(agentId) : null;
|
|
558
|
+
const name = agent?.name || agentId;
|
|
559
|
+
await this._send(query.message.chat.id, this._escapeMarkdown(`💬 Now chatting with ${name}. Type your message.`));
|
|
560
|
+
} else if (data.startsWith('stop_agent:')) {
|
|
561
|
+
const agentId = data.replace('stop_agent:', '');
|
|
562
|
+
if (this.orchestrator?.messageProcessor) {
|
|
563
|
+
await this.orchestrator.messageProcessor.stopAutonomousExecution(agentId);
|
|
564
|
+
}
|
|
565
|
+
await this._send(query.message.chat.id, this._escapeMarkdown('⏹ Agent stopped.'));
|
|
566
|
+
} else if (data.startsWith('run_flow:')) {
|
|
567
|
+
const flowId = data.replace('run_flow:', '');
|
|
568
|
+
await this._runFlow(query.message.chat.id, flowId);
|
|
569
|
+
} else if (data.startsWith('unfollow:')) {
|
|
570
|
+
const agentId = data.replace('unfollow:', '');
|
|
571
|
+
this.activeAgentIds.delete(agentId);
|
|
572
|
+
if (this.lastAgentId === agentId) {
|
|
573
|
+
this.lastAgentId = this.activeAgentIds.size > 0 ? [...this.activeAgentIds][this.activeAgentIds.size - 1] : null;
|
|
574
|
+
}
|
|
575
|
+
const agent = this.agentPool ? await this.agentPool.getAgent(agentId) : null;
|
|
576
|
+
await this._send(query.message.chat.id, this._escapeMarkdown(`Unfollowed ${agent?.name || agentId}.`));
|
|
577
|
+
} else if (data.startsWith('prompt_reply:')) {
|
|
578
|
+
// Handle prompt option selection
|
|
579
|
+
const [, requestId, answerIndex] = data.match(/prompt_reply:(.+):(\d+)/) || [];
|
|
580
|
+
if (requestId && this.pendingRelays.has(requestId)) {
|
|
581
|
+
await this._submitPromptReply(requestId, answerIndex);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// --- Broadcast Interceptor ---
|
|
587
|
+
|
|
588
|
+
_interceptBroadcasts(wsManager) {
|
|
589
|
+
if (!wsManager || this._originalBroadcast) return;
|
|
590
|
+
|
|
591
|
+
const originalBroadcast = wsManager.broadcastToSession.bind(wsManager);
|
|
592
|
+
this._originalBroadcast = originalBroadcast;
|
|
593
|
+
|
|
594
|
+
wsManager.broadcastToSession = (sessionId, message) => {
|
|
595
|
+
// Call original
|
|
596
|
+
originalBroadcast(sessionId, message);
|
|
597
|
+
// Forward to Telegram
|
|
598
|
+
this._handleBroadcastEvent(message);
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
async _handleBroadcastEvent(message) {
|
|
603
|
+
if (!this.bot || !this.chatId || this.status !== TELEGRAM_STATUS.CONNECTED) return;
|
|
604
|
+
|
|
605
|
+
const type = message?.type;
|
|
606
|
+
if (!type) return;
|
|
607
|
+
|
|
608
|
+
// Always relay prompt/credential requests (they block agent progress)
|
|
609
|
+
if (type === 'user_prompt_request') {
|
|
610
|
+
await this._relayPromptRequest(message);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
if (type === 'credential_request') {
|
|
614
|
+
await this._relayCredentialRequest(message);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Agent responses — only relay stream_complete (message_added is a duplicate of the same content)
|
|
619
|
+
if (type === 'stream_complete') {
|
|
620
|
+
await this._relayAgentResponse(message);
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// Notifications — only if watching
|
|
625
|
+
if (!this.watchEnabled) return;
|
|
626
|
+
|
|
627
|
+
const notificationTypes = {
|
|
628
|
+
'agent_error': '⚠️ *Agent Error*',
|
|
629
|
+
'flow_run_failed': '❌ *Flow Failed*',
|
|
630
|
+
'agent_timeout': '⏰ *Agent Timeout*',
|
|
631
|
+
'execution_stopped': '✅ *Agent Finished*',
|
|
632
|
+
'flow_run_completed': '✅ *Flow Completed*',
|
|
633
|
+
'criticalError': '🔴 *Critical Error*'
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
if (notificationTypes[type]) {
|
|
637
|
+
const header = notificationTypes[type];
|
|
638
|
+
let text = `${header}\n`;
|
|
639
|
+
|
|
640
|
+
if (message.agentName || message.data?.agentName) {
|
|
641
|
+
text += `Agent: \`${message.agentName || message.data?.agentName}\`\n`;
|
|
642
|
+
}
|
|
643
|
+
if (message.message || message.data?.message || message.error) {
|
|
644
|
+
text += `${message.message || message.data?.message || message.error}\n`;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
this._queueNotification(text);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
async _relayAgentResponse(message) {
|
|
652
|
+
const agentId = message.agentId || message.data?.agentId;
|
|
653
|
+
if (!agentId) return;
|
|
654
|
+
|
|
655
|
+
// Only relay responses for agents the user has addressed from Telegram
|
|
656
|
+
if (!this.activeAgentIds.has(agentId)) return;
|
|
657
|
+
|
|
658
|
+
const content = message.content || message.data?.content ||
|
|
659
|
+
message.message?.content || message.data?.message?.content;
|
|
660
|
+
if (!content) return;
|
|
661
|
+
|
|
662
|
+
// Skip tool-result messages and internal messages
|
|
663
|
+
const role = message.role || message.data?.role || message.message?.role;
|
|
664
|
+
if (role === 'user' || role === 'tool') return;
|
|
665
|
+
|
|
666
|
+
const agent = this.agentPool ? await this.agentPool.getAgent(agentId) : null;
|
|
667
|
+
const agentName = agent?.name || agentId;
|
|
668
|
+
|
|
669
|
+
await this._sendFormattedResponse(this.chatId, agentName, content);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// --- Smart Response Formatting ---
|
|
673
|
+
|
|
674
|
+
async _sendFormattedResponse(chatId, agentName, content) {
|
|
675
|
+
const header = `*${this._escapeMarkdown(agentName)}:*\n\n`;
|
|
676
|
+
|
|
677
|
+
// Check for code blocks
|
|
678
|
+
const hasCode = content.includes('```');
|
|
679
|
+
|
|
680
|
+
if (content.length + header.length <= MAX_MESSAGE_LENGTH) {
|
|
681
|
+
if (hasCode) {
|
|
682
|
+
// Send as-is with code blocks — Telegram handles ``` natively
|
|
683
|
+
await this._send(chatId, header + this._escapeMarkdownPreserveCode(content));
|
|
684
|
+
} else {
|
|
685
|
+
await this._send(chatId, header + this._escapeMarkdown(content));
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
// Split long messages
|
|
689
|
+
await this._send(chatId, header + this._escapeMarkdown(content.slice(0, MAX_MESSAGE_LENGTH - 100) + '\n\n… (truncated)'));
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// --- Prompt Relay ---
|
|
694
|
+
|
|
695
|
+
async _relayPromptRequest(message) {
|
|
696
|
+
if (!this.chatId) return;
|
|
697
|
+
|
|
698
|
+
const data = message.data || message;
|
|
699
|
+
const requestId = data.requestId;
|
|
700
|
+
const agentId = data.agentId;
|
|
701
|
+
const questions = data.questions || [];
|
|
702
|
+
|
|
703
|
+
if (!requestId || questions.length === 0) return;
|
|
704
|
+
|
|
705
|
+
const agent = this.agentPool ? await this.agentPool.getAgent(agentId) : null;
|
|
706
|
+
const agentName = agent?.name || agentId;
|
|
707
|
+
|
|
708
|
+
this.pendingRelays.set(requestId, { type: 'user_prompt', agentId, questions, timestamp: Date.now() });
|
|
709
|
+
|
|
710
|
+
for (const q of questions) {
|
|
711
|
+
let text = `🔔 *${this._escapeMarkdown(agentName)}* needs your input:\n\n`;
|
|
712
|
+
text += this._escapeMarkdown(q.question) + '\n';
|
|
713
|
+
|
|
714
|
+
const options = q.options || [];
|
|
715
|
+
if (options.length > 0) {
|
|
716
|
+
const buttons = options.map((opt, i) => ([{
|
|
717
|
+
text: opt.label,
|
|
718
|
+
callback_data: `prompt_reply:${requestId}:${i}`
|
|
719
|
+
}]));
|
|
720
|
+
await this._send(this.chatId, text, { reply_markup: { inline_keyboard: buttons } });
|
|
721
|
+
} else {
|
|
722
|
+
text += '\n_Type your reply:_';
|
|
723
|
+
this.replyContext = { type: 'user_prompt', requestId, agentId };
|
|
724
|
+
await this._send(this.chatId, text);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// Set timeout reminder
|
|
729
|
+
setTimeout(() => {
|
|
730
|
+
if (this.pendingRelays.has(requestId)) {
|
|
731
|
+
this._send(this.chatId, this._escapeMarkdown(`⏰ Reminder: ${agentName} is still waiting for your input.`)).catch(() => {});
|
|
732
|
+
}
|
|
733
|
+
}, PROMPT_REMINDER_MS);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
async _relayCredentialRequest(message) {
|
|
737
|
+
if (!this.chatId) return;
|
|
738
|
+
|
|
739
|
+
const data = message.data || message;
|
|
740
|
+
const requestId = data.requestId;
|
|
741
|
+
const agentId = data.agentId;
|
|
742
|
+
|
|
743
|
+
const agent = this.agentPool ? await this.agentPool.getAgent(agentId) : null;
|
|
744
|
+
const agentName = agent?.name || agentId;
|
|
745
|
+
|
|
746
|
+
this.pendingRelays.set(requestId, { type: 'credential', agentId, timestamp: Date.now() });
|
|
747
|
+
this.replyContext = { type: 'credential', requestId, agentId };
|
|
748
|
+
|
|
749
|
+
let text = `🔐 *${this._escapeMarkdown(agentName)}* needs credentials:\n\n`;
|
|
750
|
+
text += this._escapeMarkdown(data.message || 'Please provide the requested credentials.');
|
|
751
|
+
text += '\n\n_Type your reply:_';
|
|
752
|
+
|
|
753
|
+
await this._send(this.chatId, text);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
async _handlePromptReply(msg) {
|
|
757
|
+
if (!this.replyContext) return;
|
|
758
|
+
|
|
759
|
+
const { type, requestId, agentId } = this.replyContext;
|
|
760
|
+
const text = msg.text?.trim();
|
|
761
|
+
if (!text) return;
|
|
762
|
+
|
|
763
|
+
this.replyContext = null;
|
|
764
|
+
this.pendingRelays.delete(requestId);
|
|
765
|
+
|
|
766
|
+
try {
|
|
767
|
+
if (type === 'user_prompt' && this.webSocketManager) {
|
|
768
|
+
// Submit prompt response via the same path the web UI uses
|
|
769
|
+
this.webSocketManager._handleUserPromptResult?.({
|
|
770
|
+
requestId,
|
|
771
|
+
answers: { default: text }
|
|
772
|
+
});
|
|
773
|
+
} else if (type === 'credential' && this.webSocketManager) {
|
|
774
|
+
this.webSocketManager._handleCredentialResponse?.({
|
|
775
|
+
requestId,
|
|
776
|
+
credentials: { value: text },
|
|
777
|
+
saveForFuture: false
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
await this._send(msg.chat.id, this._escapeMarkdown('✅ Response submitted.'));
|
|
782
|
+
} catch (error) {
|
|
783
|
+
await this._send(msg.chat.id, this._escapeMarkdown(`❌ Failed to submit: ${error.message}`));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
async _submitPromptReply(requestId, answerIndex) {
|
|
788
|
+
const relay = this.pendingRelays.get(requestId);
|
|
789
|
+
if (!relay) return;
|
|
790
|
+
|
|
791
|
+
this.pendingRelays.delete(requestId);
|
|
792
|
+
this.replyContext = null;
|
|
793
|
+
|
|
794
|
+
try {
|
|
795
|
+
const question = relay.questions[0];
|
|
796
|
+
const option = question?.options?.[parseInt(answerIndex)];
|
|
797
|
+
const answer = option?.label || String(answerIndex);
|
|
798
|
+
|
|
799
|
+
if (this.webSocketManager?._handleUserPromptResult) {
|
|
800
|
+
this.webSocketManager._handleUserPromptResult({
|
|
801
|
+
requestId,
|
|
802
|
+
answers: { [question.question]: answer }
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
await this._send(this.chatId, this._escapeMarkdown(`✅ Selected: ${answer}`));
|
|
807
|
+
} catch (error) {
|
|
808
|
+
await this._send(this.chatId, this._escapeMarkdown(`❌ Failed: ${error.message}`));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// --- Notification Batching ---
|
|
813
|
+
|
|
814
|
+
_queueNotification(text) {
|
|
815
|
+
this.notificationQueue.push(text);
|
|
816
|
+
if (!this.notificationTimer) {
|
|
817
|
+
this.notificationTimer = setTimeout(() => this._flushNotifications(), NOTIFICATION_BATCH_INTERVAL_MS);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
async _flushNotifications() {
|
|
822
|
+
this.notificationTimer = null;
|
|
823
|
+
if (this.notificationQueue.length === 0 || !this.chatId) return;
|
|
824
|
+
|
|
825
|
+
const messages = this.notificationQueue.splice(0);
|
|
826
|
+
const combined = messages.join('\n\n');
|
|
827
|
+
|
|
828
|
+
if (combined.length <= MAX_MESSAGE_LENGTH) {
|
|
829
|
+
await this._send(this.chatId, combined);
|
|
830
|
+
} else {
|
|
831
|
+
await this._send(this.chatId, messages[0] + (messages.length > 1
|
|
832
|
+
? `\n\n_…and ${messages.length - 1} more events_`
|
|
833
|
+
: ''));
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
_clearNotificationTimer() {
|
|
838
|
+
if (this.notificationTimer) {
|
|
839
|
+
clearTimeout(this.notificationTimer);
|
|
840
|
+
this.notificationTimer = null;
|
|
841
|
+
}
|
|
842
|
+
this.notificationQueue = [];
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// --- Telegram API Helpers ---
|
|
846
|
+
|
|
847
|
+
async _send(chatId, text, options = {}) {
|
|
848
|
+
if (!this.bot || !chatId) return;
|
|
849
|
+
try {
|
|
850
|
+
return await this.bot.sendMessage(chatId, text, {
|
|
851
|
+
parse_mode: 'MarkdownV2',
|
|
852
|
+
...options
|
|
853
|
+
});
|
|
854
|
+
} catch (error) {
|
|
855
|
+
// Fallback: send without formatting if markdown fails
|
|
856
|
+
this.logger?.warn('[TelegramService] Markdown send failed, retrying plain', { error: error.message });
|
|
857
|
+
try {
|
|
858
|
+
return await this.bot.sendMessage(chatId, text.replace(/[\\*_`\[\]()~>#+\-=|{}.!]/g, ''), options);
|
|
859
|
+
} catch (e2) {
|
|
860
|
+
this.logger?.error('[TelegramService] Send failed', { error: e2.message });
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
async sendPhoto(chatId, photoPath, caption = '') {
|
|
866
|
+
if (!this.bot || !chatId) return;
|
|
867
|
+
try {
|
|
868
|
+
return await this.bot.sendPhoto(chatId, photoPath, { caption });
|
|
869
|
+
} catch (error) {
|
|
870
|
+
this.logger?.error('[TelegramService] Send photo failed', { error: error.message });
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
async sendDocument(chatId, docPath, caption = '') {
|
|
875
|
+
if (!this.bot || !chatId) return;
|
|
876
|
+
try {
|
|
877
|
+
return await this.bot.sendDocument(chatId, docPath, { caption });
|
|
878
|
+
} catch (error) {
|
|
879
|
+
this.logger?.error('[TelegramService] Send document failed', { error: error.message });
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
async sendTestMessage() {
|
|
884
|
+
if (!this.chatId) throw new Error('No chat registered. Send /start from Telegram first.');
|
|
885
|
+
await this._send(this.chatId, this._escapeMarkdown('✅ Loxia Autopilot — test message received!'));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// --- Markdown Escaping ---
|
|
889
|
+
|
|
890
|
+
_escapeMarkdown(text) {
|
|
891
|
+
if (!text) return '';
|
|
892
|
+
// Escape MarkdownV2 special chars
|
|
893
|
+
return text.replace(/([_*\[\]()~`>#+\-=|{}.!\\])/g, '\\$1');
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
_escapeMarkdownPreserveCode(text) {
|
|
897
|
+
if (!text) return '';
|
|
898
|
+
// Split by code blocks, escape non-code parts
|
|
899
|
+
const parts = text.split(/(```[\s\S]*?```)/g);
|
|
900
|
+
return parts.map(part => {
|
|
901
|
+
if (part.startsWith('```')) {
|
|
902
|
+
return part; // Don't escape code blocks
|
|
903
|
+
}
|
|
904
|
+
return this._escapeMarkdown(part);
|
|
905
|
+
}).join('');
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Singleton
|
|
910
|
+
let instance = null;
|
|
911
|
+
|
|
912
|
+
export function getTelegramService(logger = null) {
|
|
913
|
+
if (!instance) {
|
|
914
|
+
instance = new TelegramService(logger);
|
|
915
|
+
}
|
|
916
|
+
return instance;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
export { TelegramService, TELEGRAM_STATUS };
|
|
920
|
+
export default TelegramService;
|