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.
Files changed (506) hide show
  1. package/LICENSE +267 -0
  2. package/README.md +425 -0
  3. package/bin/cli.js +556 -0
  4. package/bin/loxia-terminal-v2.js +162 -0
  5. package/bin/loxia-terminal.js +90 -0
  6. package/bin/start-with-terminal.js +200 -0
  7. package/node_modules/@isaacs/balanced-match/LICENSE.md +23 -0
  8. package/node_modules/@isaacs/balanced-match/README.md +60 -0
  9. package/node_modules/@isaacs/balanced-match/dist/commonjs/index.d.ts +9 -0
  10. package/node_modules/@isaacs/balanced-match/dist/commonjs/index.d.ts.map +1 -0
  11. package/node_modules/@isaacs/balanced-match/dist/commonjs/index.js +59 -0
  12. package/node_modules/@isaacs/balanced-match/dist/commonjs/index.js.map +1 -0
  13. package/node_modules/@isaacs/balanced-match/dist/commonjs/package.json +3 -0
  14. package/node_modules/@isaacs/balanced-match/dist/esm/index.d.ts +9 -0
  15. package/node_modules/@isaacs/balanced-match/dist/esm/index.d.ts.map +1 -0
  16. package/node_modules/@isaacs/balanced-match/dist/esm/index.js +54 -0
  17. package/node_modules/@isaacs/balanced-match/dist/esm/index.js.map +1 -0
  18. package/node_modules/@isaacs/balanced-match/dist/esm/package.json +3 -0
  19. package/node_modules/@isaacs/balanced-match/package.json +79 -0
  20. package/node_modules/@isaacs/brace-expansion/LICENSE +23 -0
  21. package/node_modules/@isaacs/brace-expansion/README.md +97 -0
  22. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.d.ts +6 -0
  23. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.d.ts.map +1 -0
  24. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js +199 -0
  25. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +1 -0
  26. package/node_modules/@isaacs/brace-expansion/dist/commonjs/package.json +3 -0
  27. package/node_modules/@isaacs/brace-expansion/dist/esm/index.d.ts +6 -0
  28. package/node_modules/@isaacs/brace-expansion/dist/esm/index.d.ts.map +1 -0
  29. package/node_modules/@isaacs/brace-expansion/dist/esm/index.js +195 -0
  30. package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +1 -0
  31. package/node_modules/@isaacs/brace-expansion/dist/esm/package.json +3 -0
  32. package/node_modules/@isaacs/brace-expansion/package.json +60 -0
  33. package/node_modules/glob/LICENSE.md +63 -0
  34. package/node_modules/glob/README.md +1177 -0
  35. package/node_modules/glob/dist/commonjs/glob.d.ts +388 -0
  36. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -0
  37. package/node_modules/glob/dist/commonjs/glob.js +247 -0
  38. package/node_modules/glob/dist/commonjs/glob.js.map +1 -0
  39. package/node_modules/glob/dist/commonjs/has-magic.d.ts +14 -0
  40. package/node_modules/glob/dist/commonjs/has-magic.d.ts.map +1 -0
  41. package/node_modules/glob/dist/commonjs/has-magic.js +27 -0
  42. package/node_modules/glob/dist/commonjs/has-magic.js.map +1 -0
  43. package/node_modules/glob/dist/commonjs/ignore.d.ts +24 -0
  44. package/node_modules/glob/dist/commonjs/ignore.d.ts.map +1 -0
  45. package/node_modules/glob/dist/commonjs/ignore.js +119 -0
  46. package/node_modules/glob/dist/commonjs/ignore.js.map +1 -0
  47. package/node_modules/glob/dist/commonjs/index.d.ts +97 -0
  48. package/node_modules/glob/dist/commonjs/index.d.ts.map +1 -0
  49. package/node_modules/glob/dist/commonjs/index.js +68 -0
  50. package/node_modules/glob/dist/commonjs/index.js.map +1 -0
  51. package/node_modules/glob/dist/commonjs/index.min.js +4 -0
  52. package/node_modules/glob/dist/commonjs/index.min.js.map +7 -0
  53. package/node_modules/glob/dist/commonjs/package.json +3 -0
  54. package/node_modules/glob/dist/commonjs/pattern.d.ts +76 -0
  55. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -0
  56. package/node_modules/glob/dist/commonjs/pattern.js +219 -0
  57. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -0
  58. package/node_modules/glob/dist/commonjs/processor.d.ts +59 -0
  59. package/node_modules/glob/dist/commonjs/processor.d.ts.map +1 -0
  60. package/node_modules/glob/dist/commonjs/processor.js +301 -0
  61. package/node_modules/glob/dist/commonjs/processor.js.map +1 -0
  62. package/node_modules/glob/dist/commonjs/walker.d.ts +97 -0
  63. package/node_modules/glob/dist/commonjs/walker.d.ts.map +1 -0
  64. package/node_modules/glob/dist/commonjs/walker.js +387 -0
  65. package/node_modules/glob/dist/commonjs/walker.js.map +1 -0
  66. package/node_modules/glob/dist/esm/glob.d.ts +388 -0
  67. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -0
  68. package/node_modules/glob/dist/esm/glob.js +243 -0
  69. package/node_modules/glob/dist/esm/glob.js.map +1 -0
  70. package/node_modules/glob/dist/esm/has-magic.d.ts +14 -0
  71. package/node_modules/glob/dist/esm/has-magic.d.ts.map +1 -0
  72. package/node_modules/glob/dist/esm/has-magic.js +23 -0
  73. package/node_modules/glob/dist/esm/has-magic.js.map +1 -0
  74. package/node_modules/glob/dist/esm/ignore.d.ts +24 -0
  75. package/node_modules/glob/dist/esm/ignore.d.ts.map +1 -0
  76. package/node_modules/glob/dist/esm/ignore.js +115 -0
  77. package/node_modules/glob/dist/esm/ignore.js.map +1 -0
  78. package/node_modules/glob/dist/esm/index.d.ts +97 -0
  79. package/node_modules/glob/dist/esm/index.d.ts.map +1 -0
  80. package/node_modules/glob/dist/esm/index.js +55 -0
  81. package/node_modules/glob/dist/esm/index.js.map +1 -0
  82. package/node_modules/glob/dist/esm/index.min.js +4 -0
  83. package/node_modules/glob/dist/esm/index.min.js.map +7 -0
  84. package/node_modules/glob/dist/esm/package.json +3 -0
  85. package/node_modules/glob/dist/esm/pattern.d.ts +76 -0
  86. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -0
  87. package/node_modules/glob/dist/esm/pattern.js +215 -0
  88. package/node_modules/glob/dist/esm/pattern.js.map +1 -0
  89. package/node_modules/glob/dist/esm/processor.d.ts +59 -0
  90. package/node_modules/glob/dist/esm/processor.d.ts.map +1 -0
  91. package/node_modules/glob/dist/esm/processor.js +294 -0
  92. package/node_modules/glob/dist/esm/processor.js.map +1 -0
  93. package/node_modules/glob/dist/esm/walker.d.ts +97 -0
  94. package/node_modules/glob/dist/esm/walker.d.ts.map +1 -0
  95. package/node_modules/glob/dist/esm/walker.js +381 -0
  96. package/node_modules/glob/dist/esm/walker.js.map +1 -0
  97. package/node_modules/glob/node_modules/minimatch/LICENSE.md +55 -0
  98. package/node_modules/glob/node_modules/minimatch/README.md +453 -0
  99. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +2 -0
  100. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -0
  101. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js +14 -0
  102. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -0
  103. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +20 -0
  104. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -0
  105. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +591 -0
  106. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -0
  107. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts +8 -0
  108. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -0
  109. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +152 -0
  110. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -0
  111. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +15 -0
  112. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -0
  113. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +30 -0
  114. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -0
  115. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +94 -0
  116. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -0
  117. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +1029 -0
  118. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -0
  119. package/node_modules/glob/node_modules/minimatch/dist/commonjs/package.json +3 -0
  120. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +22 -0
  121. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -0
  122. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +38 -0
  123. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -0
  124. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +2 -0
  125. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -0
  126. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js +10 -0
  127. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -0
  128. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +20 -0
  129. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -0
  130. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +587 -0
  131. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -0
  132. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts +8 -0
  133. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -0
  134. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +148 -0
  135. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -0
  136. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +15 -0
  137. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -0
  138. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +26 -0
  139. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -0
  140. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +94 -0
  141. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -0
  142. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +1016 -0
  143. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -0
  144. package/node_modules/glob/node_modules/minimatch/dist/esm/package.json +3 -0
  145. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +22 -0
  146. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -0
  147. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +34 -0
  148. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -0
  149. package/node_modules/glob/node_modules/minimatch/package.json +67 -0
  150. package/node_modules/glob/package.json +101 -0
  151. package/node_modules/minipass/LICENSE +15 -0
  152. package/node_modules/minipass/README.md +825 -0
  153. package/node_modules/minipass/dist/commonjs/index.d.ts +549 -0
  154. package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -0
  155. package/node_modules/minipass/dist/commonjs/index.js +1028 -0
  156. package/node_modules/minipass/dist/commonjs/index.js.map +1 -0
  157. package/node_modules/minipass/dist/commonjs/package.json +3 -0
  158. package/node_modules/minipass/dist/esm/index.d.ts +549 -0
  159. package/node_modules/minipass/dist/esm/index.d.ts.map +1 -0
  160. package/node_modules/minipass/dist/esm/index.js +1018 -0
  161. package/node_modules/minipass/dist/esm/index.js.map +1 -0
  162. package/node_modules/minipass/dist/esm/package.json +3 -0
  163. package/node_modules/minipass/package.json +82 -0
  164. package/node_modules/package-json-from-dist/LICENSE.md +63 -0
  165. package/node_modules/package-json-from-dist/README.md +110 -0
  166. package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts +89 -0
  167. package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts.map +1 -0
  168. package/node_modules/package-json-from-dist/dist/commonjs/index.js +134 -0
  169. package/node_modules/package-json-from-dist/dist/commonjs/index.js.map +1 -0
  170. package/node_modules/package-json-from-dist/dist/commonjs/package.json +3 -0
  171. package/node_modules/package-json-from-dist/dist/esm/index.d.ts +89 -0
  172. package/node_modules/package-json-from-dist/dist/esm/index.d.ts.map +1 -0
  173. package/node_modules/package-json-from-dist/dist/esm/index.js +129 -0
  174. package/node_modules/package-json-from-dist/dist/esm/index.js.map +1 -0
  175. package/node_modules/package-json-from-dist/dist/esm/package.json +3 -0
  176. package/node_modules/package-json-from-dist/package.json +68 -0
  177. package/node_modules/path-scurry/LICENSE.md +55 -0
  178. package/node_modules/path-scurry/README.md +636 -0
  179. package/node_modules/path-scurry/dist/commonjs/index.d.ts +1115 -0
  180. package/node_modules/path-scurry/dist/commonjs/index.d.ts.map +1 -0
  181. package/node_modules/path-scurry/dist/commonjs/index.js +2018 -0
  182. package/node_modules/path-scurry/dist/commonjs/index.js.map +1 -0
  183. package/node_modules/path-scurry/dist/commonjs/package.json +3 -0
  184. package/node_modules/path-scurry/dist/esm/index.d.ts +1115 -0
  185. package/node_modules/path-scurry/dist/esm/index.d.ts.map +1 -0
  186. package/node_modules/path-scurry/dist/esm/index.js +1983 -0
  187. package/node_modules/path-scurry/dist/esm/index.js.map +1 -0
  188. package/node_modules/path-scurry/dist/esm/package.json +3 -0
  189. package/node_modules/path-scurry/node_modules/lru-cache/LICENSE.md +55 -0
  190. package/node_modules/path-scurry/node_modules/lru-cache/README.md +383 -0
  191. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +1323 -0
  192. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -0
  193. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +1589 -0
  194. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -0
  195. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +2 -0
  196. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +7 -0
  197. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/package.json +3 -0
  198. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +1323 -0
  199. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -0
  200. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +1585 -0
  201. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -0
  202. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +2 -0
  203. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +7 -0
  204. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/package.json +3 -0
  205. package/node_modules/path-scurry/node_modules/lru-cache/package.json +101 -0
  206. package/node_modules/path-scurry/package.json +88 -0
  207. package/node_modules/rimraf/LICENSE.md +55 -0
  208. package/node_modules/rimraf/README.md +226 -0
  209. package/node_modules/rimraf/dist/commonjs/default-tmp.d.ts +3 -0
  210. package/node_modules/rimraf/dist/commonjs/default-tmp.d.ts.map +1 -0
  211. package/node_modules/rimraf/dist/commonjs/default-tmp.js +58 -0
  212. package/node_modules/rimraf/dist/commonjs/default-tmp.js.map +1 -0
  213. package/node_modules/rimraf/dist/commonjs/error.d.ts +6 -0
  214. package/node_modules/rimraf/dist/commonjs/error.d.ts.map +1 -0
  215. package/node_modules/rimraf/dist/commonjs/error.js +10 -0
  216. package/node_modules/rimraf/dist/commonjs/error.js.map +1 -0
  217. package/node_modules/rimraf/dist/commonjs/fix-eperm.d.ts +3 -0
  218. package/node_modules/rimraf/dist/commonjs/fix-eperm.d.ts.map +1 -0
  219. package/node_modules/rimraf/dist/commonjs/fix-eperm.js +38 -0
  220. package/node_modules/rimraf/dist/commonjs/fix-eperm.js.map +1 -0
  221. package/node_modules/rimraf/dist/commonjs/fs.d.ts +15 -0
  222. package/node_modules/rimraf/dist/commonjs/fs.d.ts.map +1 -0
  223. package/node_modules/rimraf/dist/commonjs/fs.js +33 -0
  224. package/node_modules/rimraf/dist/commonjs/fs.js.map +1 -0
  225. package/node_modules/rimraf/dist/commonjs/ignore-enoent.d.ts +3 -0
  226. package/node_modules/rimraf/dist/commonjs/ignore-enoent.d.ts.map +1 -0
  227. package/node_modules/rimraf/dist/commonjs/ignore-enoent.js +24 -0
  228. package/node_modules/rimraf/dist/commonjs/ignore-enoent.js.map +1 -0
  229. package/node_modules/rimraf/dist/commonjs/index.d.ts +50 -0
  230. package/node_modules/rimraf/dist/commonjs/index.d.ts.map +1 -0
  231. package/node_modules/rimraf/dist/commonjs/index.js +78 -0
  232. package/node_modules/rimraf/dist/commonjs/index.js.map +1 -0
  233. package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts +34 -0
  234. package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts.map +1 -0
  235. package/node_modules/rimraf/dist/commonjs/opt-arg.js +53 -0
  236. package/node_modules/rimraf/dist/commonjs/opt-arg.js.map +1 -0
  237. package/node_modules/rimraf/dist/commonjs/package.json +3 -0
  238. package/node_modules/rimraf/dist/commonjs/path-arg.d.ts +4 -0
  239. package/node_modules/rimraf/dist/commonjs/path-arg.d.ts.map +1 -0
  240. package/node_modules/rimraf/dist/commonjs/path-arg.js +48 -0
  241. package/node_modules/rimraf/dist/commonjs/path-arg.js.map +1 -0
  242. package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts +3 -0
  243. package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts.map +1 -0
  244. package/node_modules/rimraf/dist/commonjs/readdir-or-error.js +19 -0
  245. package/node_modules/rimraf/dist/commonjs/readdir-or-error.js.map +1 -0
  246. package/node_modules/rimraf/dist/commonjs/retry-busy.d.ts +8 -0
  247. package/node_modules/rimraf/dist/commonjs/retry-busy.d.ts.map +1 -0
  248. package/node_modules/rimraf/dist/commonjs/retry-busy.js +65 -0
  249. package/node_modules/rimraf/dist/commonjs/retry-busy.js.map +1 -0
  250. package/node_modules/rimraf/dist/commonjs/rimraf-manual.d.ts +3 -0
  251. package/node_modules/rimraf/dist/commonjs/rimraf-manual.d.ts.map +1 -0
  252. package/node_modules/rimraf/dist/commonjs/rimraf-manual.js +8 -0
  253. package/node_modules/rimraf/dist/commonjs/rimraf-manual.js.map +1 -0
  254. package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts +4 -0
  255. package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts.map +1 -0
  256. package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js +138 -0
  257. package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js.map +1 -0
  258. package/node_modules/rimraf/dist/commonjs/rimraf-native.d.ts +4 -0
  259. package/node_modules/rimraf/dist/commonjs/rimraf-native.d.ts.map +1 -0
  260. package/node_modules/rimraf/dist/commonjs/rimraf-native.js +24 -0
  261. package/node_modules/rimraf/dist/commonjs/rimraf-native.js.map +1 -0
  262. package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts +4 -0
  263. package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts.map +1 -0
  264. package/node_modules/rimraf/dist/commonjs/rimraf-posix.js +103 -0
  265. package/node_modules/rimraf/dist/commonjs/rimraf-posix.js.map +1 -0
  266. package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts +4 -0
  267. package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts.map +1 -0
  268. package/node_modules/rimraf/dist/commonjs/rimraf-windows.js +159 -0
  269. package/node_modules/rimraf/dist/commonjs/rimraf-windows.js.map +1 -0
  270. package/node_modules/rimraf/dist/commonjs/use-native.d.ts +4 -0
  271. package/node_modules/rimraf/dist/commonjs/use-native.d.ts.map +1 -0
  272. package/node_modules/rimraf/dist/commonjs/use-native.js +18 -0
  273. package/node_modules/rimraf/dist/commonjs/use-native.js.map +1 -0
  274. package/node_modules/rimraf/dist/esm/bin.d.mts +3 -0
  275. package/node_modules/rimraf/dist/esm/bin.d.mts.map +1 -0
  276. package/node_modules/rimraf/dist/esm/bin.mjs +250 -0
  277. package/node_modules/rimraf/dist/esm/bin.mjs.map +1 -0
  278. package/node_modules/rimraf/dist/esm/default-tmp.d.ts +3 -0
  279. package/node_modules/rimraf/dist/esm/default-tmp.d.ts.map +1 -0
  280. package/node_modules/rimraf/dist/esm/default-tmp.js +55 -0
  281. package/node_modules/rimraf/dist/esm/default-tmp.js.map +1 -0
  282. package/node_modules/rimraf/dist/esm/error.d.ts +6 -0
  283. package/node_modules/rimraf/dist/esm/error.d.ts.map +1 -0
  284. package/node_modules/rimraf/dist/esm/error.js +5 -0
  285. package/node_modules/rimraf/dist/esm/error.js.map +1 -0
  286. package/node_modules/rimraf/dist/esm/fix-eperm.d.ts +3 -0
  287. package/node_modules/rimraf/dist/esm/fix-eperm.d.ts.map +1 -0
  288. package/node_modules/rimraf/dist/esm/fix-eperm.js +33 -0
  289. package/node_modules/rimraf/dist/esm/fix-eperm.js.map +1 -0
  290. package/node_modules/rimraf/dist/esm/fs.d.ts +15 -0
  291. package/node_modules/rimraf/dist/esm/fs.d.ts.map +1 -0
  292. package/node_modules/rimraf/dist/esm/fs.js +18 -0
  293. package/node_modules/rimraf/dist/esm/fs.js.map +1 -0
  294. package/node_modules/rimraf/dist/esm/ignore-enoent.d.ts +3 -0
  295. package/node_modules/rimraf/dist/esm/ignore-enoent.d.ts.map +1 -0
  296. package/node_modules/rimraf/dist/esm/ignore-enoent.js +19 -0
  297. package/node_modules/rimraf/dist/esm/ignore-enoent.js.map +1 -0
  298. package/node_modules/rimraf/dist/esm/index.d.ts +50 -0
  299. package/node_modules/rimraf/dist/esm/index.d.ts.map +1 -0
  300. package/node_modules/rimraf/dist/esm/index.js +70 -0
  301. package/node_modules/rimraf/dist/esm/index.js.map +1 -0
  302. package/node_modules/rimraf/dist/esm/opt-arg.d.ts +34 -0
  303. package/node_modules/rimraf/dist/esm/opt-arg.d.ts.map +1 -0
  304. package/node_modules/rimraf/dist/esm/opt-arg.js +46 -0
  305. package/node_modules/rimraf/dist/esm/opt-arg.js.map +1 -0
  306. package/node_modules/rimraf/dist/esm/package.json +3 -0
  307. package/node_modules/rimraf/dist/esm/path-arg.d.ts +4 -0
  308. package/node_modules/rimraf/dist/esm/path-arg.d.ts.map +1 -0
  309. package/node_modules/rimraf/dist/esm/path-arg.js +46 -0
  310. package/node_modules/rimraf/dist/esm/path-arg.js.map +1 -0
  311. package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts +3 -0
  312. package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts.map +1 -0
  313. package/node_modules/rimraf/dist/esm/readdir-or-error.js +14 -0
  314. package/node_modules/rimraf/dist/esm/readdir-or-error.js.map +1 -0
  315. package/node_modules/rimraf/dist/esm/retry-busy.d.ts +8 -0
  316. package/node_modules/rimraf/dist/esm/retry-busy.d.ts.map +1 -0
  317. package/node_modules/rimraf/dist/esm/retry-busy.js +60 -0
  318. package/node_modules/rimraf/dist/esm/retry-busy.js.map +1 -0
  319. package/node_modules/rimraf/dist/esm/rimraf-manual.d.ts +3 -0
  320. package/node_modules/rimraf/dist/esm/rimraf-manual.d.ts.map +1 -0
  321. package/node_modules/rimraf/dist/esm/rimraf-manual.js +5 -0
  322. package/node_modules/rimraf/dist/esm/rimraf-manual.js.map +1 -0
  323. package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts +4 -0
  324. package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts.map +1 -0
  325. package/node_modules/rimraf/dist/esm/rimraf-move-remove.js +133 -0
  326. package/node_modules/rimraf/dist/esm/rimraf-move-remove.js.map +1 -0
  327. package/node_modules/rimraf/dist/esm/rimraf-native.d.ts +4 -0
  328. package/node_modules/rimraf/dist/esm/rimraf-native.d.ts.map +1 -0
  329. package/node_modules/rimraf/dist/esm/rimraf-native.js +19 -0
  330. package/node_modules/rimraf/dist/esm/rimraf-native.js.map +1 -0
  331. package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts +4 -0
  332. package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts.map +1 -0
  333. package/node_modules/rimraf/dist/esm/rimraf-posix.js +98 -0
  334. package/node_modules/rimraf/dist/esm/rimraf-posix.js.map +1 -0
  335. package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts +4 -0
  336. package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts.map +1 -0
  337. package/node_modules/rimraf/dist/esm/rimraf-windows.js +154 -0
  338. package/node_modules/rimraf/dist/esm/rimraf-windows.js.map +1 -0
  339. package/node_modules/rimraf/dist/esm/use-native.d.ts +4 -0
  340. package/node_modules/rimraf/dist/esm/use-native.d.ts.map +1 -0
  341. package/node_modules/rimraf/dist/esm/use-native.js +15 -0
  342. package/node_modules/rimraf/dist/esm/use-native.js.map +1 -0
  343. package/node_modules/rimraf/package.json +92 -0
  344. package/package.json +152 -0
  345. package/scripts/install-scanners.js +258 -0
  346. package/scripts/watchdog.js +147 -0
  347. package/src/analyzers/CSSAnalyzer.js +297 -0
  348. package/src/analyzers/ConfigValidator.js +690 -0
  349. package/src/analyzers/ESLintAnalyzer.js +320 -0
  350. package/src/analyzers/JavaScriptAnalyzer.js +261 -0
  351. package/src/analyzers/PrettierFormatter.js +247 -0
  352. package/src/analyzers/PythonAnalyzer.js +283 -0
  353. package/src/analyzers/SecurityAnalyzer.js +729 -0
  354. package/src/analyzers/SparrowAnalyzer.js +341 -0
  355. package/src/analyzers/TypeScriptAnalyzer.js +247 -0
  356. package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
  357. package/src/analyzers/codeCloneDetector/detector.js +250 -0
  358. package/src/analyzers/codeCloneDetector/index.js +192 -0
  359. package/src/analyzers/codeCloneDetector/parser.js +199 -0
  360. package/src/analyzers/codeCloneDetector/reporter.js +148 -0
  361. package/src/analyzers/codeCloneDetector/scanner.js +88 -0
  362. package/src/core/agentPool.js +1957 -0
  363. package/src/core/agentScheduler.js +3212 -0
  364. package/src/core/contextManager.js +709 -0
  365. package/src/core/flowExecutor.js +928 -0
  366. package/src/core/messageProcessor.js +808 -0
  367. package/src/core/orchestrator.js +584 -0
  368. package/src/core/stateManager.js +1500 -0
  369. package/src/index.js +972 -0
  370. package/src/interfaces/cli.js +553 -0
  371. package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +208 -0
  372. package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +236 -0
  373. package/src/interfaces/terminal/__tests__/smoke/agents.test.js +138 -0
  374. package/src/interfaces/terminal/__tests__/smoke/components.test.js +137 -0
  375. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +350 -0
  376. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -0
  377. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +332 -0
  378. package/src/interfaces/terminal/__tests__/smoke/messages.test.js +256 -0
  379. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +388 -0
  380. package/src/interfaces/terminal/api/apiClient.js +299 -0
  381. package/src/interfaces/terminal/api/messageRouter.js +262 -0
  382. package/src/interfaces/terminal/api/session.js +266 -0
  383. package/src/interfaces/terminal/api/websocket.js +497 -0
  384. package/src/interfaces/terminal/components/AgentCreator.js +705 -0
  385. package/src/interfaces/terminal/components/AgentEditor.js +678 -0
  386. package/src/interfaces/terminal/components/AgentSwitcher.js +330 -0
  387. package/src/interfaces/terminal/components/ErrorBoundary.js +92 -0
  388. package/src/interfaces/terminal/components/ErrorPanel.js +264 -0
  389. package/src/interfaces/terminal/components/Header.js +28 -0
  390. package/src/interfaces/terminal/components/HelpPanel.js +231 -0
  391. package/src/interfaces/terminal/components/InputBox.js +118 -0
  392. package/src/interfaces/terminal/components/Layout.js +603 -0
  393. package/src/interfaces/terminal/components/LoadingSpinner.js +71 -0
  394. package/src/interfaces/terminal/components/MessageList.js +281 -0
  395. package/src/interfaces/terminal/components/MultilineTextInput.js +251 -0
  396. package/src/interfaces/terminal/components/SearchPanel.js +265 -0
  397. package/src/interfaces/terminal/components/SettingsPanel.js +415 -0
  398. package/src/interfaces/terminal/components/StatusBar.js +65 -0
  399. package/src/interfaces/terminal/components/TextInput.js +127 -0
  400. package/src/interfaces/terminal/config/agentEditorConstants.js +227 -0
  401. package/src/interfaces/terminal/config/constants.js +393 -0
  402. package/src/interfaces/terminal/index.js +168 -0
  403. package/src/interfaces/terminal/state/useAgentControl.js +496 -0
  404. package/src/interfaces/terminal/state/useAgents.js +537 -0
  405. package/src/interfaces/terminal/state/useConnection.js +444 -0
  406. package/src/interfaces/terminal/state/useMessages.js +630 -0
  407. package/src/interfaces/terminal/state/useTools.js +554 -0
  408. package/src/interfaces/terminal/utils/debugLogger.js +44 -0
  409. package/src/interfaces/terminal/utils/settingsStorage.js +232 -0
  410. package/src/interfaces/terminal/utils/theme.js +85 -0
  411. package/src/interfaces/webServer.js +5457 -0
  412. package/src/modules/fileExplorer/controller.js +413 -0
  413. package/src/modules/fileExplorer/index.js +37 -0
  414. package/src/modules/fileExplorer/middleware.js +92 -0
  415. package/src/modules/fileExplorer/routes.js +158 -0
  416. package/src/modules/fileExplorer/types.js +44 -0
  417. package/src/services/agentActivityService.js +399 -0
  418. package/src/services/aiService.js +2618 -0
  419. package/src/services/apiKeyManager.js +334 -0
  420. package/src/services/benchmarkService.js +196 -0
  421. package/src/services/budgetService.js +565 -0
  422. package/src/services/contextInjectionService.js +268 -0
  423. package/src/services/conversationCompactionService.js +1103 -0
  424. package/src/services/credentialVault.js +685 -0
  425. package/src/services/errorHandler.js +810 -0
  426. package/src/services/fileAttachmentService.js +547 -0
  427. package/src/services/flowContextService.js +189 -0
  428. package/src/services/memoryService.js +521 -0
  429. package/src/services/modelRouterService.js +365 -0
  430. package/src/services/modelsService.js +323 -0
  431. package/src/services/ollamaService.js +452 -0
  432. package/src/services/portRegistry.js +336 -0
  433. package/src/services/portTracker.js +223 -0
  434. package/src/services/projectDetector.js +404 -0
  435. package/src/services/promptService.js +372 -0
  436. package/src/services/qualityInspector.js +796 -0
  437. package/src/services/scheduleService.js +725 -0
  438. package/src/services/serviceRegistry.js +386 -0
  439. package/src/services/skillsService.js +486 -0
  440. package/src/services/telegramService.js +920 -0
  441. package/src/services/tokenCountingService.js +316 -0
  442. package/src/services/visualEditorBridge.js +1033 -0
  443. package/src/services/visualEditorServer.js +1727 -0
  444. package/src/services/whatsappService.js +663 -0
  445. package/src/tools/__tests__/webTool.e2e.test.js +569 -0
  446. package/src/tools/__tests__/webTool.unit.test.js +195 -0
  447. package/src/tools/agentCommunicationTool.js +1343 -0
  448. package/src/tools/agentDelayTool.js +498 -0
  449. package/src/tools/asyncToolManager.js +604 -0
  450. package/src/tools/baseTool.js +887 -0
  451. package/src/tools/browserTool.js +897 -0
  452. package/src/tools/cloneDetectionTool.js +581 -0
  453. package/src/tools/codeMapTool.js +857 -0
  454. package/src/tools/dependencyResolverTool.js +1212 -0
  455. package/src/tools/docxTool.js +623 -0
  456. package/src/tools/excelTool.js +636 -0
  457. package/src/tools/fileContentReplaceTool.js +840 -0
  458. package/src/tools/fileTreeTool.js +833 -0
  459. package/src/tools/filesystemTool.js +1217 -0
  460. package/src/tools/helpTool.js +198 -0
  461. package/src/tools/imageTool.js +1034 -0
  462. package/src/tools/importAnalyzerTool.js +1056 -0
  463. package/src/tools/jobDoneTool.js +388 -0
  464. package/src/tools/memoryTool.js +554 -0
  465. package/src/tools/pdfTool.js +627 -0
  466. package/src/tools/seekTool.js +883 -0
  467. package/src/tools/skillsTool.js +276 -0
  468. package/src/tools/staticAnalysisTool.js +2146 -0
  469. package/src/tools/taskManagerTool.js +2836 -0
  470. package/src/tools/terminalTool.js +2486 -0
  471. package/src/tools/userPromptTool.js +474 -0
  472. package/src/tools/videoTool.js +1139 -0
  473. package/src/tools/visionTool.js +507 -0
  474. package/src/tools/visualEditorTool.js +1175 -0
  475. package/src/tools/webTool.js +3114 -0
  476. package/src/tools/whatsappTool.js +457 -0
  477. package/src/types/agent.js +519 -0
  478. package/src/types/contextReference.js +972 -0
  479. package/src/types/conversation.js +730 -0
  480. package/src/types/toolCommand.js +747 -0
  481. package/src/utilities/attachmentValidator.js +288 -0
  482. package/src/utilities/browserStealth.js +630 -0
  483. package/src/utilities/configManager.js +618 -0
  484. package/src/utilities/constants.js +870 -0
  485. package/src/utilities/directoryAccessManager.js +566 -0
  486. package/src/utilities/fileProcessor.js +307 -0
  487. package/src/utilities/humanBehavior.js +453 -0
  488. package/src/utilities/jsonRepair.js +242 -0
  489. package/src/utilities/logger.js +436 -0
  490. package/src/utilities/platformUtils.js +255 -0
  491. package/src/utilities/platformUtils.test.js +98 -0
  492. package/src/utilities/stealthConstants.js +377 -0
  493. package/src/utilities/structuredFileValidator.js +699 -0
  494. package/src/utilities/tagParser.js +878 -0
  495. package/src/utilities/toolConstants.js +415 -0
  496. package/src/utilities/userDataDir.js +300 -0
  497. package/web-ui/build/brands/autopilot/favicon.svg +1 -0
  498. package/web-ui/build/brands/autopilot/logo.webp +0 -0
  499. package/web-ui/build/brands/onbuzz/favicon.svg +1 -0
  500. package/web-ui/build/brands/onbuzz/logo-text.webp +0 -0
  501. package/web-ui/build/brands/onbuzz/logo.webp +0 -0
  502. package/web-ui/build/index.html +15 -0
  503. package/web-ui/build/logo.png +0 -0
  504. package/web-ui/build/logo2.png +0 -0
  505. package/web-ui/build/static/index-SmQFfvBs.js +746 -0
  506. 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;