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,1033 @@
1
+ /**
2
+ * Visual Editor Bridge Service
3
+ *
4
+ * Manages visual editor instances per agent, enabling users to interact
5
+ * with their web applications visually and give the AI agent pointers
6
+ * to code parts of interest.
7
+ *
8
+ * Key responsibilities:
9
+ * - Instance registry (one editor per agent)
10
+ * - Visual context storage (element selections)
11
+ * - Lifecycle management (create/stop/cleanup)
12
+ * - Multi-instance coordination
13
+ * - WebSocket connection to visual editor (Phase 3)
14
+ *
15
+ * @see VISUAL-EDITOR-INTEGRATION-PLAN.md for full architecture
16
+ */
17
+
18
+ import { EventEmitter } from 'events';
19
+ import WebSocket from 'ws';
20
+ import { getVisualEditorPort } from './visualEditorServer.js';
21
+
22
+ // Configuration defaults - port can be configured via config file, env var, or fallback
23
+ const DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
24
+ const DEFAULT_MAX_INSTANCES = 3;
25
+ const DEFAULT_RECONNECT_INTERVAL_MS = 3000;
26
+ const DEFAULT_MAX_RECONNECT_ATTEMPTS = 5;
27
+
28
+ /**
29
+ * Get the WebSocket URL for the visual editor (computed at runtime)
30
+ * Uses getVisualEditorPort which respects config file and env var settings
31
+ */
32
+ function getVisualEditorWsUrl() {
33
+ const port = getVisualEditorPort();
34
+ return `ws://localhost:${port}/ws`;
35
+ }
36
+
37
+ /**
38
+ * WebSocket message types from visual editor
39
+ */
40
+ export const MessageTypes = {
41
+ // Incoming from editor
42
+ ELEMENT_SELECTED: 'element-selected',
43
+ FILE_CHANGED: 'file-changed',
44
+ EDITOR_READY: 'editor-ready',
45
+ ERROR: 'error',
46
+ PONG: 'pong',
47
+
48
+ // Outgoing to editor
49
+ HIGHLIGHT: 'highlight',
50
+ SCROLL_TO: 'scroll-to',
51
+ RELOAD: 'reload',
52
+ SET_MODE: 'set-mode',
53
+ PING: 'ping',
54
+ SUBSCRIBE: 'subscribe',
55
+ UNSUBSCRIBE: 'unsubscribe'
56
+ };
57
+
58
+ /**
59
+ * Instance status enum
60
+ */
61
+ export const InstanceStatus = {
62
+ INITIALIZED: 'initialized',
63
+ CONNECTING: 'connecting',
64
+ READY: 'ready',
65
+ ERROR: 'error',
66
+ STOPPED: 'stopped'
67
+ };
68
+
69
+ /**
70
+ * Visual Editor Bridge Service
71
+ * Manages visual editor instances and coordinates communication
72
+ */
73
+ class VisualEditorBridge extends EventEmitter {
74
+ /**
75
+ * @param {Object} config - Configuration options
76
+ * @param {number} config.maxInstances - Maximum concurrent editors (default: 3)
77
+ * @param {number} config.idleTimeoutMs - Idle timeout in ms (default: 10 min)
78
+ * @param {string} config.visualEditorUrl - WebSocket URL for visual editor
79
+ * @param {number} config.reconnectIntervalMs - Reconnection interval
80
+ * @param {number} config.maxReconnectAttempts - Max reconnection attempts
81
+ * @param {Object} config.logger - Logger instance
82
+ */
83
+ constructor(config = {}) {
84
+ super();
85
+
86
+ // Instance registry: agentId → InstanceRecord
87
+ this.instances = new Map();
88
+
89
+ // Configuration
90
+ this.maxInstances = config.maxInstances || DEFAULT_MAX_INSTANCES;
91
+ this.idleTimeoutMs = config.idleTimeoutMs || DEFAULT_IDLE_TIMEOUT_MS;
92
+ this.visualEditorUrl = config.visualEditorUrl || getVisualEditorWsUrl();
93
+ this.reconnectIntervalMs = config.reconnectIntervalMs || DEFAULT_RECONNECT_INTERVAL_MS;
94
+ this.maxReconnectAttempts = config.maxReconnectAttempts || DEFAULT_MAX_RECONNECT_ATTEMPTS;
95
+ this.logger = config.logger || console;
96
+ this.enabled = config.enabled !== false;
97
+
98
+ // Cleanup interval for orphaned instances
99
+ this.cleanupInterval = null;
100
+ if (this.enabled) {
101
+ this.cleanupInterval = setInterval(() => this._cleanupIdle(), 60000);
102
+ }
103
+
104
+ this.logger.info?.('[VisualEditorBridge] Initialized', {
105
+ maxInstances: this.maxInstances,
106
+ idleTimeoutMs: this.idleTimeoutMs,
107
+ visualEditorUrl: this.visualEditorUrl,
108
+ enabled: this.enabled
109
+ }) || this.logger.log('[VisualEditorBridge] Initialized');
110
+ }
111
+
112
+ /**
113
+ * Check if bridge is enabled
114
+ * @returns {boolean}
115
+ */
116
+ isEnabled() {
117
+ return this.enabled;
118
+ }
119
+
120
+ /**
121
+ * Get or create instance for agent
122
+ * @param {string} agentId - Agent identifier
123
+ * @param {Object} options - Instance options
124
+ * @param {string} options.projectRoot - Project root directory
125
+ * @param {string} options.appUrl - User's app URL to proxy
126
+ * @returns {Object} Instance record
127
+ * @throws {Error} If max instances reached
128
+ */
129
+ async getInstance(agentId, options = {}) {
130
+ if (!agentId) {
131
+ throw new Error('agentId is required');
132
+ }
133
+
134
+ // Return existing instance
135
+ if (this.instances.has(agentId)) {
136
+ const instance = this.instances.get(agentId);
137
+ instance.lastActivity = Date.now();
138
+ this._resetIdleTimer(agentId);
139
+
140
+ // Update options if provided
141
+ if (options.projectRoot) instance.projectRoot = options.projectRoot;
142
+ if (options.appUrl) instance.appUrl = options.appUrl;
143
+
144
+ return instance;
145
+ }
146
+
147
+ // Check instance limit
148
+ if (this.instances.size >= this.maxInstances) {
149
+ // Try to evict oldest idle instance
150
+ const evicted = this._evictOldestIdle();
151
+ if (!evicted) {
152
+ throw new Error(
153
+ `Maximum visual editor instances (${this.maxInstances}) reached. ` +
154
+ `Stop an existing editor first.`
155
+ );
156
+ }
157
+ }
158
+
159
+ // Create new instance record
160
+ const instance = {
161
+ agentId,
162
+ projectRoot: options.projectRoot || null,
163
+ appUrl: options.appUrl || null,
164
+ status: InstanceStatus.INITIALIZED,
165
+ wsConnection: null,
166
+ editorUrl: null,
167
+ lastActivity: Date.now(),
168
+ createdAt: Date.now(),
169
+ uiSubscribers: new Set(),
170
+ visualContext: null,
171
+ idleTimer: null,
172
+ error: null,
173
+ // WebSocket connection state (Phase 3)
174
+ reconnectAttempts: 0,
175
+ reconnectTimer: null,
176
+ pingInterval: null,
177
+ lastPong: null,
178
+ isConnecting: false
179
+ };
180
+
181
+ this.instances.set(agentId, instance);
182
+ this._resetIdleTimer(agentId);
183
+
184
+ this.logger.info?.(`[VisualEditorBridge] Created instance for agent: ${agentId}`, {
185
+ projectRoot: instance.projectRoot,
186
+ appUrl: instance.appUrl
187
+ }) || this.logger.log(`[VisualEditorBridge] Created instance: ${agentId}`);
188
+
189
+ this.emit('instance-created', { agentId, instance: this._sanitizeInstance(instance) });
190
+
191
+ return instance;
192
+ }
193
+
194
+ /**
195
+ * Check if instance exists for agent
196
+ * @param {string} agentId - Agent identifier
197
+ * @returns {boolean}
198
+ */
199
+ hasInstance(agentId) {
200
+ return this.instances.has(agentId);
201
+ }
202
+
203
+ /**
204
+ * Store visual context (element selection) for agent
205
+ * @param {string} agentId - Agent identifier
206
+ * @param {Object} elementReference - Element reference from visual editor
207
+ * @returns {boolean} Success
208
+ */
209
+ setVisualContext(agentId, elementReference) {
210
+ const instance = this.instances.get(agentId);
211
+ if (!instance) {
212
+ this.logger.warn?.(`[VisualEditorBridge] No instance for agent: ${agentId}`) ||
213
+ this.logger.log(`[VisualEditorBridge] No instance: ${agentId}`);
214
+ return false;
215
+ }
216
+
217
+ instance.visualContext = {
218
+ ...elementReference,
219
+ receivedAt: new Date().toISOString()
220
+ };
221
+ instance.lastActivity = Date.now();
222
+ this._resetIdleTimer(agentId);
223
+
224
+ this.logger.info?.(`[VisualEditorBridge] Visual context set for agent: ${agentId}`, {
225
+ selector: elementReference.selector,
226
+ sourceFile: elementReference.sourceHint?.file
227
+ }) || this.logger.log(`[VisualEditorBridge] Context set: ${agentId}`);
228
+
229
+ this.emit('visual-context-updated', {
230
+ agentId,
231
+ context: instance.visualContext
232
+ });
233
+
234
+ return true;
235
+ }
236
+
237
+ /**
238
+ * Get visual context for agent
239
+ * @param {string} agentId - Agent identifier
240
+ * @returns {Object|null} Visual context or null
241
+ */
242
+ getVisualContext(agentId) {
243
+ const instance = this.instances.get(agentId);
244
+ return instance?.visualContext || null;
245
+ }
246
+
247
+ /**
248
+ * Clear visual context for agent
249
+ * @param {string} agentId - Agent identifier
250
+ * @returns {boolean} Success
251
+ */
252
+ clearVisualContext(agentId) {
253
+ const instance = this.instances.get(agentId);
254
+ if (instance && instance.visualContext) {
255
+ instance.visualContext = null;
256
+ this.emit('visual-context-cleared', { agentId });
257
+ return true;
258
+ }
259
+ return false;
260
+ }
261
+
262
+ /**
263
+ * Get instance status
264
+ * @param {string} agentId - Agent identifier
265
+ * @returns {Object} Status object
266
+ */
267
+ getStatus(agentId) {
268
+ const instance = this.instances.get(agentId);
269
+ if (!instance) {
270
+ return {
271
+ exists: false,
272
+ agentId
273
+ };
274
+ }
275
+
276
+ return {
277
+ exists: true,
278
+ agentId: instance.agentId,
279
+ status: instance.status,
280
+ projectRoot: instance.projectRoot,
281
+ appUrl: instance.appUrl,
282
+ editorUrl: instance.editorUrl,
283
+ hasVisualContext: !!instance.visualContext,
284
+ visualContext: instance.visualContext,
285
+ subscriberCount: instance.uiSubscribers.size,
286
+ createdAt: instance.createdAt,
287
+ lastActivity: instance.lastActivity,
288
+ idleMs: Date.now() - instance.lastActivity,
289
+ error: instance.error
290
+ };
291
+ }
292
+
293
+ /**
294
+ * Update instance status
295
+ * @param {string} agentId - Agent identifier
296
+ * @param {string} status - New status
297
+ * @param {Object} extra - Additional fields to update
298
+ * @returns {boolean} Success
299
+ */
300
+ updateStatus(agentId, status, extra = {}) {
301
+ const instance = this.instances.get(agentId);
302
+ if (!instance) {
303
+ return false;
304
+ }
305
+
306
+ instance.status = status;
307
+ instance.lastActivity = Date.now();
308
+
309
+ if (extra.editorUrl) instance.editorUrl = extra.editorUrl;
310
+ if (extra.wsConnection) instance.wsConnection = extra.wsConnection;
311
+ if (extra.error) instance.error = extra.error;
312
+
313
+ this.emit('instance-status-changed', {
314
+ agentId,
315
+ status,
316
+ ...extra
317
+ });
318
+
319
+ return true;
320
+ }
321
+
322
+ /**
323
+ * Add UI subscriber to instance
324
+ * @param {string} agentId - Agent identifier
325
+ * @param {string} connectionId - UI connection identifier
326
+ * @returns {boolean} Success
327
+ */
328
+ addSubscriber(agentId, connectionId) {
329
+ const instance = this.instances.get(agentId);
330
+ if (!instance) {
331
+ return false;
332
+ }
333
+
334
+ instance.uiSubscribers.add(connectionId);
335
+ instance.lastActivity = Date.now();
336
+ return true;
337
+ }
338
+
339
+ /**
340
+ * Remove UI subscriber from instance
341
+ * @param {string} agentId - Agent identifier
342
+ * @param {string} connectionId - UI connection identifier
343
+ * @returns {boolean} Success
344
+ */
345
+ removeSubscriber(agentId, connectionId) {
346
+ const instance = this.instances.get(agentId);
347
+ if (!instance) {
348
+ return false;
349
+ }
350
+
351
+ return instance.uiSubscribers.delete(connectionId);
352
+ }
353
+
354
+ /**
355
+ * Stop and remove instance for agent
356
+ * @param {string} agentId - Agent identifier
357
+ * @returns {boolean} Success
358
+ */
359
+ async stopInstance(agentId) {
360
+ const instance = this.instances.get(agentId);
361
+ if (!instance) {
362
+ return false;
363
+ }
364
+
365
+ // Mark as stopped to prevent reconnection attempts
366
+ instance.status = InstanceStatus.STOPPED;
367
+
368
+ // Clear idle timer
369
+ if (instance.idleTimer) {
370
+ clearTimeout(instance.idleTimer);
371
+ instance.idleTimer = null;
372
+ }
373
+
374
+ // Cleanup WebSocket connection (including ping interval and reconnect timer)
375
+ this._cleanupConnection(agentId);
376
+
377
+ // Remove from registry
378
+ this.instances.delete(agentId);
379
+
380
+ this.logger.info?.(`[VisualEditorBridge] Stopped instance for agent: ${agentId}`) ||
381
+ this.logger.log(`[VisualEditorBridge] Stopped: ${agentId}`);
382
+
383
+ this.emit('instance-stopped', { agentId });
384
+
385
+ return true;
386
+ }
387
+
388
+ /**
389
+ * Handle agent deletion - cleanup instance
390
+ * @param {string} agentId - Agent identifier
391
+ * @returns {boolean} Success
392
+ */
393
+ onAgentDeleted(agentId) {
394
+ this.logger.info?.(`[VisualEditorBridge] Agent deleted, cleaning up: ${agentId}`);
395
+ return this.stopInstance(agentId);
396
+ }
397
+
398
+ /**
399
+ * Handle agent unload - cleanup instance
400
+ * @param {string} agentId - Agent identifier
401
+ * @returns {boolean} Success
402
+ */
403
+ onAgentUnloaded(agentId) {
404
+ this.logger.info?.(`[VisualEditorBridge] Agent unloaded, cleaning up: ${agentId}`);
405
+ return this.stopInstance(agentId);
406
+ }
407
+
408
+ /**
409
+ * Check if project is used by another agent
410
+ * @param {string} agentId - Current agent identifier
411
+ * @param {string} projectRoot - Project root to check
412
+ * @returns {Object} Collision info
413
+ */
414
+ checkProjectCollision(agentId, projectRoot) {
415
+ if (!projectRoot) {
416
+ return { collision: false };
417
+ }
418
+
419
+ for (const [otherId, instance] of this.instances) {
420
+ if (otherId !== agentId && instance.projectRoot === projectRoot) {
421
+ return {
422
+ collision: true,
423
+ otherAgentId: otherId,
424
+ message: `Project "${projectRoot}" is already being edited by agent "${otherId}"`
425
+ };
426
+ }
427
+ }
428
+ return { collision: false };
429
+ }
430
+
431
+ /**
432
+ * List all instances
433
+ * @returns {Array} Array of instance info objects
434
+ */
435
+ listInstances() {
436
+ return Array.from(this.instances.entries()).map(([agentId, instance]) => ({
437
+ agentId,
438
+ status: instance.status,
439
+ projectRoot: instance.projectRoot,
440
+ appUrl: instance.appUrl,
441
+ hasContext: !!instance.visualContext,
442
+ subscriberCount: instance.uiSubscribers.size,
443
+ createdAt: instance.createdAt,
444
+ lastActivity: instance.lastActivity,
445
+ idleMs: Date.now() - instance.lastActivity
446
+ }));
447
+ }
448
+
449
+ /**
450
+ * Get count of active instances
451
+ * @returns {number}
452
+ */
453
+ getInstanceCount() {
454
+ return this.instances.size;
455
+ }
456
+
457
+ /**
458
+ * Touch instance to reset idle timer
459
+ * @param {string} agentId - Agent identifier
460
+ */
461
+ touchInstance(agentId) {
462
+ const instance = this.instances.get(agentId);
463
+ if (instance) {
464
+ instance.lastActivity = Date.now();
465
+ this._resetIdleTimer(agentId);
466
+ }
467
+ }
468
+
469
+ // === WebSocket Methods (Phase 3) ===
470
+
471
+ /**
472
+ * Connect to visual editor WebSocket
473
+ * @param {string} agentId - Agent identifier
474
+ * @param {Object} options - Connection options
475
+ * @param {string} options.editorUrl - Override editor URL
476
+ * @returns {Promise<boolean>} Connection success
477
+ */
478
+ async connectToEditor(agentId, options = {}) {
479
+ const instance = this.instances.get(agentId);
480
+ if (!instance) {
481
+ throw new Error(`No instance for agent: ${agentId}`);
482
+ }
483
+
484
+ // Already connected or connecting
485
+ if (instance.wsConnection?.readyState === WebSocket.OPEN) {
486
+ return true;
487
+ }
488
+
489
+ if (instance.isConnecting) {
490
+ return false;
491
+ }
492
+
493
+ instance.isConnecting = true;
494
+ instance.status = InstanceStatus.CONNECTING;
495
+ this.emit('instance-status-changed', { agentId, status: InstanceStatus.CONNECTING });
496
+
497
+ const editorUrl = options.editorUrl || this.visualEditorUrl;
498
+
499
+ return new Promise((resolve) => {
500
+ try {
501
+ this.logger.info?.(`[VisualEditorBridge] Connecting to editor for agent: ${agentId}`, {
502
+ url: editorUrl
503
+ });
504
+
505
+ const ws = new WebSocket(editorUrl);
506
+
507
+ ws.on('open', () => {
508
+ instance.wsConnection = ws;
509
+ instance.status = InstanceStatus.READY;
510
+ instance.editorUrl = editorUrl;
511
+ instance.isConnecting = false;
512
+ instance.reconnectAttempts = 0;
513
+ instance.error = null;
514
+ instance.lastActivity = Date.now();
515
+
516
+ this.logger.info?.(`[VisualEditorBridge] Connected to editor for agent: ${agentId}`);
517
+
518
+ // Start heartbeat
519
+ this._startPingInterval(agentId);
520
+
521
+ // Subscribe to editor events for this agent
522
+ this.sendCommand(agentId, MessageTypes.SUBSCRIBE, {
523
+ agentId,
524
+ projectRoot: instance.projectRoot,
525
+ appUrl: instance.appUrl
526
+ });
527
+
528
+ this.emit('editor-connected', { agentId, editorUrl });
529
+ this.emit('instance-status-changed', { agentId, status: InstanceStatus.READY });
530
+
531
+ resolve(true);
532
+ });
533
+
534
+ ws.on('message', (data) => {
535
+ try {
536
+ const message = JSON.parse(data.toString());
537
+ this._handleEditorMessage(agentId, message);
538
+ } catch (err) {
539
+ this.logger.warn?.(`[VisualEditorBridge] Invalid message from editor: ${err.message}`);
540
+ }
541
+ });
542
+
543
+ ws.on('close', (code, reason) => {
544
+ this.logger.info?.(`[VisualEditorBridge] Editor connection closed for agent: ${agentId}`, {
545
+ code,
546
+ reason: reason?.toString()
547
+ });
548
+
549
+ this._cleanupConnection(agentId);
550
+
551
+ // Schedule reconnect if instance still exists and wasn't manually stopped
552
+ if (this.instances.has(agentId) && instance.status !== InstanceStatus.STOPPED) {
553
+ this._scheduleReconnect(agentId);
554
+ }
555
+ });
556
+
557
+ ws.on('error', (error) => {
558
+ this.logger.error?.(`[VisualEditorBridge] Editor connection error for agent: ${agentId}`, {
559
+ error: error.message
560
+ });
561
+
562
+ instance.error = error.message;
563
+ instance.isConnecting = false;
564
+
565
+ if (instance.status === InstanceStatus.CONNECTING) {
566
+ instance.status = InstanceStatus.ERROR;
567
+ this.emit('instance-status-changed', { agentId, status: InstanceStatus.ERROR, error: error.message });
568
+ }
569
+
570
+ this.emit('editor-error', { agentId, error: error.message });
571
+ resolve(false);
572
+ });
573
+
574
+ } catch (error) {
575
+ instance.isConnecting = false;
576
+ instance.status = InstanceStatus.ERROR;
577
+ instance.error = error.message;
578
+ this.logger.error?.(`[VisualEditorBridge] Failed to create WebSocket: ${error.message}`);
579
+ resolve(false);
580
+ }
581
+ });
582
+ }
583
+
584
+ /**
585
+ * Disconnect from visual editor
586
+ * @param {string} agentId - Agent identifier
587
+ * @returns {boolean} Success
588
+ */
589
+ disconnectFromEditor(agentId) {
590
+ const instance = this.instances.get(agentId);
591
+ if (!instance) {
592
+ return false;
593
+ }
594
+
595
+ // Send unsubscribe before closing
596
+ if (instance.wsConnection?.readyState === WebSocket.OPEN) {
597
+ this.sendCommand(agentId, MessageTypes.UNSUBSCRIBE, { agentId });
598
+ }
599
+
600
+ this._cleanupConnection(agentId);
601
+
602
+ this.logger.info?.(`[VisualEditorBridge] Disconnected from editor for agent: ${agentId}`);
603
+ this.emit('editor-disconnected', { agentId });
604
+
605
+ return true;
606
+ }
607
+
608
+ /**
609
+ * Send command to visual editor
610
+ * @param {string} agentId - Agent identifier
611
+ * @param {string} type - Message type
612
+ * @param {Object} data - Message data
613
+ * @returns {boolean} Success
614
+ */
615
+ sendCommand(agentId, type, data = {}) {
616
+ const instance = this.instances.get(agentId);
617
+ if (!instance?.wsConnection || instance.wsConnection.readyState !== WebSocket.OPEN) {
618
+ this.logger.warn?.(`[VisualEditorBridge] Cannot send command - not connected: ${agentId}`);
619
+ return false;
620
+ }
621
+
622
+ try {
623
+ const message = JSON.stringify({
624
+ type,
625
+ agentId,
626
+ timestamp: Date.now(),
627
+ ...data
628
+ });
629
+
630
+ instance.wsConnection.send(message);
631
+ instance.lastActivity = Date.now();
632
+ this._resetIdleTimer(agentId);
633
+
634
+ this.logger.debug?.(`[VisualEditorBridge] Sent command: ${type} for agent: ${agentId}`);
635
+ return true;
636
+
637
+ } catch (error) {
638
+ this.logger.error?.(`[VisualEditorBridge] Failed to send command: ${error.message}`);
639
+ return false;
640
+ }
641
+ }
642
+
643
+ /**
644
+ * Highlight element in visual editor preview
645
+ * @param {string} agentId - Agent identifier
646
+ * @param {string} selector - CSS selector to highlight
647
+ * @param {number} durationMs - Highlight duration (default: 2000ms)
648
+ * @returns {boolean} Success
649
+ */
650
+ highlightElement(agentId, selector, durationMs = 2000) {
651
+ return this.sendCommand(agentId, MessageTypes.HIGHLIGHT, {
652
+ selector,
653
+ duration: durationMs
654
+ });
655
+ }
656
+
657
+ /**
658
+ * Scroll to element in visual editor preview
659
+ * @param {string} agentId - Agent identifier
660
+ * @param {string} selector - CSS selector to scroll to
661
+ * @returns {boolean} Success
662
+ */
663
+ scrollToElement(agentId, selector) {
664
+ return this.sendCommand(agentId, MessageTypes.SCROLL_TO, { selector });
665
+ }
666
+
667
+ /**
668
+ * Reload the visual editor preview
669
+ * @param {string} agentId - Agent identifier
670
+ * @returns {boolean} Success
671
+ */
672
+ reloadPreview(agentId) {
673
+ return this.sendCommand(agentId, MessageTypes.RELOAD, {});
674
+ }
675
+
676
+ /**
677
+ * Set visual editor mode
678
+ * @param {string} agentId - Agent identifier
679
+ * @param {string} mode - Mode ('edit' or 'preview')
680
+ * @returns {boolean} Success
681
+ */
682
+ setEditorMode(agentId, mode) {
683
+ if (!['edit', 'preview'].includes(mode)) {
684
+ throw new Error(`Invalid mode: ${mode}. Must be 'edit' or 'preview'`);
685
+ }
686
+ return this.sendCommand(agentId, MessageTypes.SET_MODE, { mode });
687
+ }
688
+
689
+ /**
690
+ * Check if instance is connected to editor
691
+ * @param {string} agentId - Agent identifier
692
+ * @returns {boolean}
693
+ */
694
+ isConnected(agentId) {
695
+ const instance = this.instances.get(agentId);
696
+ return instance?.wsConnection?.readyState === WebSocket.OPEN;
697
+ }
698
+
699
+ // === Private methods ===
700
+
701
+ /**
702
+ * Reset idle timer for instance
703
+ * @private
704
+ */
705
+ _resetIdleTimer(agentId) {
706
+ const instance = this.instances.get(agentId);
707
+ if (!instance) return;
708
+
709
+ if (instance.idleTimer) {
710
+ clearTimeout(instance.idleTimer);
711
+ }
712
+
713
+ instance.idleTimer = setTimeout(() => {
714
+ this.logger.info?.(`[VisualEditorBridge] Idle timeout for agent: ${agentId}`);
715
+ this.stopInstance(agentId);
716
+ }, this.idleTimeoutMs);
717
+ }
718
+
719
+ /**
720
+ * Evict the oldest idle instance to make room
721
+ * @private
722
+ * @returns {boolean} Whether an instance was evicted
723
+ */
724
+ _evictOldestIdle() {
725
+ let oldest = null;
726
+ let oldestTime = Infinity;
727
+
728
+ // First pass: prefer instances without active subscribers
729
+ for (const [agentId, instance] of this.instances) {
730
+ const hasSubscribers = instance.uiSubscribers.size > 0;
731
+
732
+ if (!hasSubscribers && instance.lastActivity < oldestTime) {
733
+ oldest = agentId;
734
+ oldestTime = instance.lastActivity;
735
+ }
736
+ }
737
+
738
+ // Second pass: if no instance without subscribers, evict oldest overall
739
+ if (!oldest) {
740
+ oldestTime = Infinity;
741
+ for (const [agentId, instance] of this.instances) {
742
+ if (instance.lastActivity < oldestTime) {
743
+ oldest = agentId;
744
+ oldestTime = instance.lastActivity;
745
+ }
746
+ }
747
+ }
748
+
749
+ if (oldest) {
750
+ this.logger.info?.(`[VisualEditorBridge] Evicting idle instance: ${oldest}`);
751
+ this.stopInstance(oldest);
752
+ return true;
753
+ }
754
+
755
+ return false;
756
+ }
757
+
758
+ /**
759
+ * Cleanup idle instances (called periodically)
760
+ * @private
761
+ */
762
+ _cleanupIdle() {
763
+ const now = Date.now();
764
+ const toCleanup = [];
765
+
766
+ for (const [agentId, instance] of this.instances) {
767
+ if (now - instance.lastActivity > this.idleTimeoutMs) {
768
+ toCleanup.push(agentId);
769
+ }
770
+ }
771
+
772
+ for (const agentId of toCleanup) {
773
+ this.logger.info?.(`[VisualEditorBridge] Cleanup idle instance: ${agentId}`);
774
+ this.stopInstance(agentId);
775
+ }
776
+ }
777
+
778
+ /**
779
+ * Sanitize instance for external exposure (remove internals)
780
+ * @private
781
+ */
782
+ _sanitizeInstance(instance) {
783
+ return {
784
+ agentId: instance.agentId,
785
+ status: instance.status,
786
+ projectRoot: instance.projectRoot,
787
+ appUrl: instance.appUrl,
788
+ editorUrl: instance.editorUrl,
789
+ hasVisualContext: !!instance.visualContext,
790
+ subscriberCount: instance.uiSubscribers.size,
791
+ createdAt: instance.createdAt,
792
+ lastActivity: instance.lastActivity,
793
+ isConnected: instance.wsConnection?.readyState === WebSocket.OPEN
794
+ };
795
+ }
796
+
797
+ /**
798
+ * Handle incoming message from visual editor
799
+ * @private
800
+ */
801
+ _handleEditorMessage(agentId, message) {
802
+ const instance = this.instances.get(agentId);
803
+ if (!instance) return;
804
+
805
+ instance.lastActivity = Date.now();
806
+ this._resetIdleTimer(agentId);
807
+
808
+ const { type } = message;
809
+
810
+ switch (type) {
811
+ case MessageTypes.ELEMENT_SELECTED:
812
+ // User selected an element in the visual editor
813
+ this.logger.info?.(`[VisualEditorBridge] Element selected for agent: ${agentId}`, {
814
+ selector: message.selector,
815
+ sourceFile: message.sourceHint?.file
816
+ });
817
+
818
+ // Store visual context
819
+ this.setVisualContext(agentId, {
820
+ selector: message.selector,
821
+ tagName: message.tagName,
822
+ text: message.text,
823
+ attributes: message.attributes,
824
+ boundingRect: message.boundingRect,
825
+ sourceHint: message.sourceHint
826
+ });
827
+
828
+ // Emit event for UI subscribers
829
+ this.emit('element-selected', {
830
+ agentId,
831
+ element: message
832
+ });
833
+ break;
834
+
835
+ case MessageTypes.FILE_CHANGED:
836
+ // File changed in the project
837
+ this.logger.info?.(`[VisualEditorBridge] File changed for agent: ${agentId}`, {
838
+ file: message.file,
839
+ type: message.changeType
840
+ });
841
+
842
+ this.emit('file-changed', {
843
+ agentId,
844
+ file: message.file,
845
+ changeType: message.changeType
846
+ });
847
+ break;
848
+
849
+ case MessageTypes.EDITOR_READY:
850
+ // Editor is ready and connected
851
+ this.logger.info?.(`[VisualEditorBridge] Editor ready for agent: ${agentId}`);
852
+ this.emit('editor-ready', { agentId });
853
+ break;
854
+
855
+ case MessageTypes.PONG:
856
+ // Heartbeat response
857
+ instance.lastPong = Date.now();
858
+ break;
859
+
860
+ case MessageTypes.ERROR:
861
+ // Error from editor
862
+ this.logger.error?.(`[VisualEditorBridge] Editor error for agent: ${agentId}`, {
863
+ error: message.error
864
+ });
865
+
866
+ instance.error = message.error;
867
+ this.emit('editor-error', {
868
+ agentId,
869
+ error: message.error
870
+ });
871
+ break;
872
+
873
+ default:
874
+ this.logger.debug?.(`[VisualEditorBridge] Unknown message type: ${type}`);
875
+ }
876
+ }
877
+
878
+ /**
879
+ * Cleanup WebSocket connection resources
880
+ * @private
881
+ */
882
+ _cleanupConnection(agentId) {
883
+ const instance = this.instances.get(agentId);
884
+ if (!instance) return;
885
+
886
+ // Stop ping interval
887
+ if (instance.pingInterval) {
888
+ clearInterval(instance.pingInterval);
889
+ instance.pingInterval = null;
890
+ }
891
+
892
+ // Cancel reconnect timer
893
+ if (instance.reconnectTimer) {
894
+ clearTimeout(instance.reconnectTimer);
895
+ instance.reconnectTimer = null;
896
+ }
897
+
898
+ // Close WebSocket
899
+ if (instance.wsConnection) {
900
+ try {
901
+ instance.wsConnection.close();
902
+ } catch (err) {
903
+ // Ignore
904
+ }
905
+ instance.wsConnection = null;
906
+ }
907
+
908
+ instance.isConnecting = false;
909
+ instance.lastPong = null;
910
+ }
911
+
912
+ /**
913
+ * Schedule reconnection with exponential backoff
914
+ * @private
915
+ */
916
+ _scheduleReconnect(agentId) {
917
+ const instance = this.instances.get(agentId);
918
+ if (!instance) return;
919
+
920
+ if (instance.reconnectAttempts >= this.maxReconnectAttempts) {
921
+ this.logger.error?.(`[VisualEditorBridge] Max reconnect attempts reached for agent: ${agentId}`);
922
+ instance.status = InstanceStatus.ERROR;
923
+ instance.error = 'Max reconnection attempts reached';
924
+ this.emit('instance-status-changed', {
925
+ agentId,
926
+ status: InstanceStatus.ERROR,
927
+ error: instance.error
928
+ });
929
+ return;
930
+ }
931
+
932
+ instance.reconnectAttempts++;
933
+
934
+ // Exponential backoff: base * 2^attempts (capped at 30s)
935
+ const delay = Math.min(
936
+ this.reconnectIntervalMs * Math.pow(2, instance.reconnectAttempts - 1),
937
+ 30000
938
+ );
939
+
940
+ this.logger.info?.(`[VisualEditorBridge] Scheduling reconnect for agent: ${agentId}`, {
941
+ attempt: instance.reconnectAttempts,
942
+ delayMs: delay
943
+ });
944
+
945
+ instance.reconnectTimer = setTimeout(() => {
946
+ if (this.instances.has(agentId)) {
947
+ this.connectToEditor(agentId).catch(err => {
948
+ this.logger.error?.(`[VisualEditorBridge] Reconnect failed: ${err.message}`);
949
+ });
950
+ }
951
+ }, delay);
952
+ }
953
+
954
+ /**
955
+ * Start ping/pong heartbeat interval
956
+ * @private
957
+ */
958
+ _startPingInterval(agentId) {
959
+ const instance = this.instances.get(agentId);
960
+ if (!instance) return;
961
+
962
+ // Clear existing interval
963
+ if (instance.pingInterval) {
964
+ clearInterval(instance.pingInterval);
965
+ }
966
+
967
+ // Ping every 30 seconds
968
+ instance.pingInterval = setInterval(() => {
969
+ if (instance.wsConnection?.readyState === WebSocket.OPEN) {
970
+ // Check if last pong was too long ago (60s timeout)
971
+ if (instance.lastPong && Date.now() - instance.lastPong > 60000) {
972
+ this.logger.warn?.(`[VisualEditorBridge] Ping timeout for agent: ${agentId}`);
973
+ this._cleanupConnection(agentId);
974
+ this._scheduleReconnect(agentId);
975
+ return;
976
+ }
977
+
978
+ this.sendCommand(agentId, MessageTypes.PING, {});
979
+ }
980
+ }, 30000);
981
+ }
982
+
983
+ /**
984
+ * Graceful shutdown - stop all instances
985
+ */
986
+ async shutdown() {
987
+ this.logger.info?.('[VisualEditorBridge] Shutting down...');
988
+
989
+ // Stop cleanup interval
990
+ if (this.cleanupInterval) {
991
+ clearInterval(this.cleanupInterval);
992
+ this.cleanupInterval = null;
993
+ }
994
+
995
+ // Stop all instances
996
+ const stopPromises = [];
997
+ for (const agentId of this.instances.keys()) {
998
+ stopPromises.push(this.stopInstance(agentId));
999
+ }
1000
+
1001
+ await Promise.all(stopPromises);
1002
+
1003
+ this.logger.info?.('[VisualEditorBridge] Shutdown complete');
1004
+ this.emit('shutdown');
1005
+ }
1006
+ }
1007
+
1008
+ // Export singleton factory
1009
+ let bridgeInstance = null;
1010
+
1011
+ /**
1012
+ * Get or create the bridge singleton
1013
+ * @param {Object} config - Configuration (only used on first call)
1014
+ * @returns {VisualEditorBridge}
1015
+ */
1016
+ export function getVisualEditorBridge(config = {}) {
1017
+ if (!bridgeInstance) {
1018
+ bridgeInstance = new VisualEditorBridge(config);
1019
+ }
1020
+ return bridgeInstance;
1021
+ }
1022
+
1023
+ /**
1024
+ * Reset the singleton (for testing)
1025
+ */
1026
+ export function resetVisualEditorBridge() {
1027
+ if (bridgeInstance) {
1028
+ bridgeInstance.shutdown();
1029
+ bridgeInstance = null;
1030
+ }
1031
+ }
1032
+
1033
+ export default VisualEditorBridge;