@monoes/monobrowse 1.0.11 → 1.0.13

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 (380) hide show
  1. package/dist/src/__tests__/adapters.test.js +5 -2
  2. package/dist/src/__tests__/adapters.test.js.map +1 -1
  3. package/dist/src/__tests__/batch-eval-parsing.test.js +4 -2
  4. package/dist/src/__tests__/batch-eval-parsing.test.js.map +1 -1
  5. package/dist/src/__tests__/box-model.test.js +9 -5
  6. package/dist/src/__tests__/box-model.test.js.map +1 -1
  7. package/dist/src/__tests__/browser-launch.test.d.ts +10 -0
  8. package/dist/src/__tests__/browser-launch.test.d.ts.map +1 -1
  9. package/dist/src/__tests__/browser-launch.test.js +17 -10
  10. package/dist/src/__tests__/browser-launch.test.js.map +1 -1
  11. package/dist/src/__tests__/cdp-client.test.js +9 -3
  12. package/dist/src/__tests__/cdp-client.test.js.map +1 -1
  13. package/dist/src/__tests__/close-browser.test.d.ts +13 -0
  14. package/dist/src/__tests__/close-browser.test.d.ts.map +1 -1
  15. package/dist/src/__tests__/close-browser.test.js +5 -5
  16. package/dist/src/__tests__/close-browser.test.js.map +1 -1
  17. package/dist/src/__tests__/console-log.test.js +17 -6
  18. package/dist/src/__tests__/console-log.test.js.map +1 -1
  19. package/dist/src/__tests__/find.test.js +26 -6
  20. package/dist/src/__tests__/find.test.js.map +1 -1
  21. package/dist/src/__tests__/frame-command.test.js +9 -3
  22. package/dist/src/__tests__/frame-command.test.js.map +1 -1
  23. package/dist/src/__tests__/open-url-navigate-error.test.js +1 -3
  24. package/dist/src/__tests__/open-url-navigate-error.test.js.map +1 -1
  25. package/dist/src/__tests__/output.test.js +1 -1
  26. package/dist/src/__tests__/output.test.js.map +1 -1
  27. package/dist/src/__tests__/profiler-heap.test.d.ts +2 -0
  28. package/dist/src/__tests__/profiler-heap.test.d.ts.map +1 -0
  29. package/dist/src/__tests__/profiler-heap.test.js +154 -0
  30. package/dist/src/__tests__/profiler-heap.test.js.map +1 -0
  31. package/dist/src/__tests__/reap-idle-browser.test.d.ts +15 -0
  32. package/dist/src/__tests__/reap-idle-browser.test.d.ts.map +1 -0
  33. package/dist/src/__tests__/reap-idle-browser.test.js +238 -0
  34. package/dist/src/__tests__/reap-idle-browser.test.js.map +1 -0
  35. package/dist/src/__tests__/ref-cache.test.js +18 -10
  36. package/dist/src/__tests__/ref-cache.test.js.map +1 -1
  37. package/dist/src/__tests__/report-a11y.test.d.ts +2 -0
  38. package/dist/src/__tests__/report-a11y.test.d.ts.map +1 -0
  39. package/dist/src/__tests__/report-a11y.test.js +147 -0
  40. package/dist/src/__tests__/report-a11y.test.js.map +1 -0
  41. package/dist/src/__tests__/report-analyze.test.d.ts +2 -0
  42. package/dist/src/__tests__/report-analyze.test.d.ts.map +1 -0
  43. package/dist/src/__tests__/report-analyze.test.js +157 -0
  44. package/dist/src/__tests__/report-analyze.test.js.map +1 -0
  45. package/dist/src/__tests__/report-budget.test.d.ts +2 -0
  46. package/dist/src/__tests__/report-budget.test.d.ts.map +1 -0
  47. package/dist/src/__tests__/report-budget.test.js +80 -0
  48. package/dist/src/__tests__/report-budget.test.js.map +1 -0
  49. package/dist/src/__tests__/report-diff.test.d.ts +2 -0
  50. package/dist/src/__tests__/report-diff.test.d.ts.map +1 -0
  51. package/dist/src/__tests__/report-diff.test.js +231 -0
  52. package/dist/src/__tests__/report-diff.test.js.map +1 -0
  53. package/dist/src/__tests__/report-evidence.test.d.ts +2 -0
  54. package/dist/src/__tests__/report-evidence.test.d.ts.map +1 -0
  55. package/dist/src/__tests__/report-evidence.test.js +214 -0
  56. package/dist/src/__tests__/report-evidence.test.js.map +1 -0
  57. package/dist/src/__tests__/report-flake.test.d.ts +2 -0
  58. package/dist/src/__tests__/report-flake.test.d.ts.map +1 -0
  59. package/dist/src/__tests__/report-flake.test.js +182 -0
  60. package/dist/src/__tests__/report-flake.test.js.map +1 -0
  61. package/dist/src/__tests__/report-history.test.d.ts +2 -0
  62. package/dist/src/__tests__/report-history.test.d.ts.map +1 -0
  63. package/dist/src/__tests__/report-history.test.js +229 -0
  64. package/dist/src/__tests__/report-history.test.js.map +1 -0
  65. package/dist/src/__tests__/report-output.test.d.ts +2 -0
  66. package/dist/src/__tests__/report-output.test.d.ts.map +1 -0
  67. package/dist/src/__tests__/report-output.test.js +169 -0
  68. package/dist/src/__tests__/report-output.test.js.map +1 -0
  69. package/dist/src/__tests__/report-png.test.d.ts +2 -0
  70. package/dist/src/__tests__/report-png.test.d.ts.map +1 -0
  71. package/dist/src/__tests__/report-png.test.js +84 -0
  72. package/dist/src/__tests__/report-png.test.js.map +1 -0
  73. package/dist/src/__tests__/report-render-extras.test.d.ts +2 -0
  74. package/dist/src/__tests__/report-render-extras.test.d.ts.map +1 -0
  75. package/dist/src/__tests__/report-render-extras.test.js +285 -0
  76. package/dist/src/__tests__/report-render-extras.test.js.map +1 -0
  77. package/dist/src/__tests__/report-render.test.d.ts +2 -0
  78. package/dist/src/__tests__/report-render.test.d.ts.map +1 -0
  79. package/dist/src/__tests__/report-render.test.js +143 -0
  80. package/dist/src/__tests__/report-render.test.js.map +1 -0
  81. package/dist/src/__tests__/report-run.test.d.ts +2 -0
  82. package/dist/src/__tests__/report-run.test.d.ts.map +1 -0
  83. package/dist/src/__tests__/report-run.test.js +234 -0
  84. package/dist/src/__tests__/report-run.test.js.map +1 -0
  85. package/dist/src/__tests__/session-state.test.d.ts +8 -0
  86. package/dist/src/__tests__/session-state.test.d.ts.map +1 -1
  87. package/dist/src/__tests__/session-state.test.js +10 -10
  88. package/dist/src/__tests__/session-state.test.js.map +1 -1
  89. package/dist/src/__tests__/snapshot.test.js +44 -14
  90. package/dist/src/__tests__/snapshot.test.js.map +1 -1
  91. package/dist/src/__tests__/storage-eval.test.js +14 -6
  92. package/dist/src/__tests__/storage-eval.test.js.map +1 -1
  93. package/dist/src/__tests__/tabs.test.js +25 -9
  94. package/dist/src/__tests__/tabs.test.js.map +1 -1
  95. package/dist/src/browser/action-builder/analyzer.d.ts +1 -1
  96. package/dist/src/browser/action-builder/analyzer.d.ts.map +1 -1
  97. package/dist/src/browser/action-builder/analyzer.js +25 -9
  98. package/dist/src/browser/action-builder/analyzer.js.map +1 -1
  99. package/dist/src/browser/action-builder/types.d.ts.map +1 -1
  100. package/dist/src/browser/actions.d.ts +1 -1
  101. package/dist/src/browser/actions.d.ts.map +1 -1
  102. package/dist/src/browser/actions.js +16 -6
  103. package/dist/src/browser/actions.js.map +1 -1
  104. package/dist/src/browser/adapters/gemini.d.ts.map +1 -1
  105. package/dist/src/browser/adapters/gemini.js.map +1 -1
  106. package/dist/src/browser/adapters/google.d.ts.map +1 -1
  107. package/dist/src/browser/adapters/google.js.map +1 -1
  108. package/dist/src/browser/adapters/index.d.ts.map +1 -1
  109. package/dist/src/browser/adapters/index.js +3 -3
  110. package/dist/src/browser/adapters/index.js.map +1 -1
  111. package/dist/src/browser/adapters/instagram.d.ts.map +1 -1
  112. package/dist/src/browser/adapters/instagram.js.map +1 -1
  113. package/dist/src/browser/adapters/linkedin.d.ts.map +1 -1
  114. package/dist/src/browser/adapters/linkedin.js.map +1 -1
  115. package/dist/src/browser/adapters/microsoft.d.ts.map +1 -1
  116. package/dist/src/browser/adapters/microsoft.js.map +1 -1
  117. package/dist/src/browser/adapters/x.d.ts.map +1 -1
  118. package/dist/src/browser/adapters/x.js.map +1 -1
  119. package/dist/src/browser/browser.d.ts +30 -0
  120. package/dist/src/browser/browser.d.ts.map +1 -1
  121. package/dist/src/browser/browser.js +122 -15
  122. package/dist/src/browser/browser.js.map +1 -1
  123. package/dist/src/browser/cdp.d.ts.map +1 -1
  124. package/dist/src/browser/cdp.js +21 -8
  125. package/dist/src/browser/cdp.js.map +1 -1
  126. package/dist/src/browser/console-log.d.ts.map +1 -1
  127. package/dist/src/browser/console-log.js +2 -2
  128. package/dist/src/browser/console-log.js.map +1 -1
  129. package/dist/src/browser/dashboard/server.d.ts.map +1 -1
  130. package/dist/src/browser/dashboard/server.js +29 -19
  131. package/dist/src/browser/dashboard/server.js.map +1 -1
  132. package/dist/src/browser/dashboard/ui.html +153 -165
  133. package/dist/src/browser/dialog.d.ts.map +1 -1
  134. package/dist/src/browser/dialog.js +3 -1
  135. package/dist/src/browser/dialog.js.map +1 -1
  136. package/dist/src/browser/emulation.d.ts.map +1 -1
  137. package/dist/src/browser/emulation.js +21 -6
  138. package/dist/src/browser/emulation.js.map +1 -1
  139. package/dist/src/browser/find.d.ts +4 -4
  140. package/dist/src/browser/find.d.ts.map +1 -1
  141. package/dist/src/browser/find.js +14 -6
  142. package/dist/src/browser/find.js.map +1 -1
  143. package/dist/src/browser/har.d.ts.map +1 -1
  144. package/dist/src/browser/har.js +14 -7
  145. package/dist/src/browser/har.js.map +1 -1
  146. package/dist/src/browser/index.d.ts +17 -16
  147. package/dist/src/browser/index.d.ts.map +1 -1
  148. package/dist/src/browser/index.js +17 -16
  149. package/dist/src/browser/index.js.map +1 -1
  150. package/dist/src/browser/network.d.ts.map +1 -1
  151. package/dist/src/browser/network.js +14 -4
  152. package/dist/src/browser/network.js.map +1 -1
  153. package/dist/src/browser/pdf.d.ts.map +1 -1
  154. package/dist/src/browser/pdf.js +3 -3
  155. package/dist/src/browser/pdf.js.map +1 -1
  156. package/dist/src/browser/profiler.d.ts.map +1 -1
  157. package/dist/src/browser/profiler.js +22 -20
  158. package/dist/src/browser/profiler.js.map +1 -1
  159. package/dist/src/browser/record.d.ts +1 -1
  160. package/dist/src/browser/record.d.ts.map +1 -1
  161. package/dist/src/browser/record.js +18 -7
  162. package/dist/src/browser/record.js.map +1 -1
  163. package/dist/src/browser/ref-cache.d.ts.map +1 -1
  164. package/dist/src/browser/ref-cache.js +9 -4
  165. package/dist/src/browser/ref-cache.js.map +1 -1
  166. package/dist/src/browser/screenshot.d.ts.map +1 -1
  167. package/dist/src/browser/screenshot.js +11 -7
  168. package/dist/src/browser/screenshot.js.map +1 -1
  169. package/dist/src/browser/session.d.ts +1 -1
  170. package/dist/src/browser/session.d.ts.map +1 -1
  171. package/dist/src/browser/session.js +27 -8
  172. package/dist/src/browser/session.js.map +1 -1
  173. package/dist/src/browser/snapshot.d.ts +1 -1
  174. package/dist/src/browser/snapshot.d.ts.map +1 -1
  175. package/dist/src/browser/snapshot.js +8 -4
  176. package/dist/src/browser/snapshot.js.map +1 -1
  177. package/dist/src/browser/storage.d.ts.map +1 -1
  178. package/dist/src/browser/storage.js.map +1 -1
  179. package/dist/src/browser/tabs.d.ts.map +1 -1
  180. package/dist/src/browser/tabs.js +9 -3
  181. package/dist/src/browser/tabs.js.map +1 -1
  182. package/dist/src/browser/trace.d.ts.map +1 -1
  183. package/dist/src/browser/trace.js +3 -3
  184. package/dist/src/browser/trace.js.map +1 -1
  185. package/dist/src/browser/types.d.ts.map +1 -1
  186. package/dist/src/browser/types.js +23 -4
  187. package/dist/src/browser/types.js.map +1 -1
  188. package/dist/src/browser/vitals.d.ts.map +1 -1
  189. package/dist/src/browser/vitals.js +1 -1
  190. package/dist/src/browser/vitals.js.map +1 -1
  191. package/dist/src/browser/wait.d.ts.map +1 -1
  192. package/dist/src/browser/wait.js +11 -5
  193. package/dist/src/browser/wait.js.map +1 -1
  194. package/dist/src/cli/action.d.ts.map +1 -1
  195. package/dist/src/cli/action.js +14 -11
  196. package/dist/src/cli/action.js.map +1 -1
  197. package/dist/src/cli/commands.d.ts.map +1 -1
  198. package/dist/src/cli/commands.js +707 -159
  199. package/dist/src/cli/commands.js.map +1 -1
  200. package/dist/src/cli/output.js +5 -5
  201. package/dist/src/cli/output.js.map +1 -1
  202. package/dist/src/cli/platform.d.ts.map +1 -1
  203. package/dist/src/cli/platform.js +15 -11
  204. package/dist/src/cli/platform.js.map +1 -1
  205. package/dist/src/cli/types.d.ts +1 -1
  206. package/dist/src/cli/types.d.ts.map +1 -1
  207. package/dist/src/cli.js +21 -9
  208. package/dist/src/cli.js.map +1 -1
  209. package/dist/src/index.d.ts +2 -2
  210. package/dist/src/index.d.ts.map +1 -1
  211. package/dist/src/index.js +2 -2
  212. package/dist/src/index.js.map +1 -1
  213. package/dist/src/report/a11y.d.ts +52 -0
  214. package/dist/src/report/a11y.d.ts.map +1 -0
  215. package/dist/src/report/a11y.js +231 -0
  216. package/dist/src/report/a11y.js.map +1 -0
  217. package/dist/src/report/analyze.d.ts +20 -0
  218. package/dist/src/report/analyze.d.ts.map +1 -0
  219. package/dist/src/report/analyze.js +136 -0
  220. package/dist/src/report/analyze.js.map +1 -0
  221. package/dist/src/report/budget.d.ts +27 -0
  222. package/dist/src/report/budget.d.ts.map +1 -0
  223. package/dist/src/report/budget.js +143 -0
  224. package/dist/src/report/budget.js.map +1 -0
  225. package/dist/src/report/collect-a11y.d.ts +25 -0
  226. package/dist/src/report/collect-a11y.d.ts.map +1 -0
  227. package/dist/src/report/collect-a11y.js +154 -0
  228. package/dist/src/report/collect-a11y.js.map +1 -0
  229. package/dist/src/report/collect.d.ts +45 -0
  230. package/dist/src/report/collect.d.ts.map +1 -0
  231. package/dist/src/report/collect.js +275 -0
  232. package/dist/src/report/collect.js.map +1 -0
  233. package/dist/src/report/evidence.d.ts +80 -0
  234. package/dist/src/report/evidence.d.ts.map +1 -0
  235. package/dist/src/report/evidence.js +279 -0
  236. package/dist/src/report/evidence.js.map +1 -0
  237. package/dist/src/report/flake.d.ts +88 -0
  238. package/dist/src/report/flake.d.ts.map +1 -0
  239. package/dist/src/report/flake.js +232 -0
  240. package/dist/src/report/flake.js.map +1 -0
  241. package/dist/src/report/history.d.ts +85 -0
  242. package/dist/src/report/history.d.ts.map +1 -0
  243. package/dist/src/report/history.js +176 -0
  244. package/dist/src/report/history.js.map +1 -0
  245. package/dist/src/report/index.d.ts +102 -0
  246. package/dist/src/report/index.d.ts.map +1 -0
  247. package/dist/src/report/index.js +216 -0
  248. package/dist/src/report/index.js.map +1 -0
  249. package/dist/src/report/pixel-diff.d.ts +30 -0
  250. package/dist/src/report/pixel-diff.d.ts.map +1 -0
  251. package/dist/src/report/pixel-diff.js +175 -0
  252. package/dist/src/report/pixel-diff.js.map +1 -0
  253. package/dist/src/report/png.d.ts +28 -0
  254. package/dist/src/report/png.d.ts.map +1 -0
  255. package/dist/src/report/png.js +259 -0
  256. package/dist/src/report/png.js.map +1 -0
  257. package/dist/src/report/render-evidence.d.ts +16 -0
  258. package/dist/src/report/render-evidence.d.ts.map +1 -0
  259. package/dist/src/report/render-evidence.js +174 -0
  260. package/dist/src/report/render-evidence.js.map +1 -0
  261. package/dist/src/report/render-trend.d.ts +16 -0
  262. package/dist/src/report/render-trend.d.ts.map +1 -0
  263. package/dist/src/report/render-trend.js +194 -0
  264. package/dist/src/report/render-trend.js.map +1 -0
  265. package/dist/src/report/render.d.ts +21 -0
  266. package/dist/src/report/render.d.ts.map +1 -0
  267. package/dist/src/report/render.js +286 -0
  268. package/dist/src/report/render.js.map +1 -0
  269. package/dist/src/report/run-diff.d.ts +18 -0
  270. package/dist/src/report/run-diff.d.ts.map +1 -0
  271. package/dist/src/report/run-diff.js +51 -0
  272. package/dist/src/report/run-diff.js.map +1 -0
  273. package/dist/src/report/structure.d.ts +41 -0
  274. package/dist/src/report/structure.d.ts.map +1 -0
  275. package/dist/src/report/structure.js +210 -0
  276. package/dist/src/report/structure.js.map +1 -0
  277. package/dist/src/report/trend.d.ts +26 -0
  278. package/dist/src/report/trend.d.ts.map +1 -0
  279. package/dist/src/report/trend.js +164 -0
  280. package/dist/src/report/trend.js.map +1 -0
  281. package/dist/src/report/types.d.ts +320 -0
  282. package/dist/src/report/types.d.ts.map +1 -0
  283. package/dist/src/report/types.js +11 -0
  284. package/dist/src/report/types.js.map +1 -0
  285. package/dist/src/report/util.d.ts +17 -0
  286. package/dist/src/report/util.d.ts.map +1 -0
  287. package/dist/src/report/util.js +45 -0
  288. package/dist/src/report/util.js.map +1 -0
  289. package/dist/tsconfig.tsbuildinfo +1 -1
  290. package/package.json +1 -1
  291. package/src/__tests__/adapters.test.ts +15 -8
  292. package/src/__tests__/batch-eval-parsing.test.ts +4 -2
  293. package/src/__tests__/box-model.test.ts +9 -5
  294. package/src/__tests__/browser-launch.test.ts +26 -15
  295. package/src/__tests__/cdp-client.test.ts +25 -9
  296. package/src/__tests__/close-browser.test.ts +11 -6
  297. package/src/__tests__/console-log.test.ts +36 -13
  298. package/src/__tests__/find.test.ts +58 -20
  299. package/src/__tests__/frame-command.test.ts +12 -6
  300. package/src/__tests__/open-url-navigate-error.test.ts +2 -4
  301. package/src/__tests__/output.test.ts +1 -1
  302. package/src/__tests__/profiler-heap.test.ts +191 -0
  303. package/src/__tests__/reap-idle-browser.test.ts +276 -0
  304. package/src/__tests__/ref-cache.test.ts +25 -12
  305. package/src/__tests__/report-a11y.test.ts +180 -0
  306. package/src/__tests__/report-analyze.test.ts +202 -0
  307. package/src/__tests__/report-budget.test.ts +92 -0
  308. package/src/__tests__/report-diff.test.ts +272 -0
  309. package/src/__tests__/report-evidence.test.ts +276 -0
  310. package/src/__tests__/report-flake.test.ts +214 -0
  311. package/src/__tests__/report-history.test.ts +293 -0
  312. package/src/__tests__/report-output.test.ts +210 -0
  313. package/src/__tests__/report-png.test.ts +95 -0
  314. package/src/__tests__/report-render-extras.test.ts +315 -0
  315. package/src/__tests__/report-render.test.ts +175 -0
  316. package/src/__tests__/report-run.test.ts +264 -0
  317. package/src/__tests__/session-state.test.ts +40 -28
  318. package/src/__tests__/snapshot.test.ts +60 -21
  319. package/src/__tests__/storage-eval.test.ts +30 -16
  320. package/src/__tests__/tabs.test.ts +26 -10
  321. package/src/browser/action-builder/analyzer.ts +39 -15
  322. package/src/browser/action-builder/types.ts +45 -8
  323. package/src/browser/actions.ts +288 -123
  324. package/src/browser/adapters/gemini.ts +7 -3
  325. package/src/browser/adapters/google.ts +5 -3
  326. package/src/browser/adapters/index.ts +5 -4
  327. package/src/browser/adapters/instagram.ts +4 -2
  328. package/src/browser/adapters/linkedin.ts +4 -2
  329. package/src/browser/adapters/microsoft.ts +9 -5
  330. package/src/browser/adapters/x.ts +7 -3
  331. package/src/browser/browser.ts +188 -42
  332. package/src/browser/cdp.ts +43 -11
  333. package/src/browser/console-log.ts +24 -7
  334. package/src/browser/dashboard/server.ts +44 -25
  335. package/src/browser/dashboard/ui.html +153 -165
  336. package/src/browser/dialog.ts +25 -8
  337. package/src/browser/emulation.ts +86 -36
  338. package/src/browser/find.ts +110 -47
  339. package/src/browser/har.ts +58 -26
  340. package/src/browser/index.ts +17 -16
  341. package/src/browser/network.ts +147 -46
  342. package/src/browser/pdf.ts +4 -4
  343. package/src/browser/profiler.ts +39 -19
  344. package/src/browser/record.ts +38 -19
  345. package/src/browser/ref-cache.ts +38 -17
  346. package/src/browser/screenshot.ts +58 -32
  347. package/src/browser/session.ts +51 -18
  348. package/src/browser/snapshot.ts +34 -20
  349. package/src/browser/storage.ts +73 -17
  350. package/src/browser/tabs.ts +29 -17
  351. package/src/browser/trace.ts +14 -10
  352. package/src/browser/types.ts +23 -4
  353. package/src/browser/vitals.ts +33 -16
  354. package/src/browser/wait.ts +47 -21
  355. package/src/cli/action.ts +52 -21
  356. package/src/cli/commands.ts +1365 -385
  357. package/src/cli/output.ts +5 -5
  358. package/src/cli/platform.ts +44 -23
  359. package/src/cli/types.ts +1 -1
  360. package/src/cli.ts +34 -18
  361. package/src/index.ts +2 -2
  362. package/src/report/a11y.ts +242 -0
  363. package/src/report/analyze.ts +181 -0
  364. package/src/report/budget.ts +155 -0
  365. package/src/report/collect-a11y.ts +200 -0
  366. package/src/report/collect.ts +408 -0
  367. package/src/report/evidence.ts +379 -0
  368. package/src/report/flake.ts +303 -0
  369. package/src/report/history.ts +219 -0
  370. package/src/report/index.ts +307 -0
  371. package/src/report/pixel-diff.ts +197 -0
  372. package/src/report/png.ts +290 -0
  373. package/src/report/render-evidence.ts +194 -0
  374. package/src/report/render-trend.ts +225 -0
  375. package/src/report/render.ts +314 -0
  376. package/src/report/run-diff.ts +63 -0
  377. package/src/report/structure.ts +212 -0
  378. package/src/report/trend.ts +189 -0
  379. package/src/report/types.ts +356 -0
  380. package/src/report/util.ts +48 -0
@@ -569,33 +569,33 @@ body { background: #0b0b14; color: #ccc; font-family: system-ui,-apple-system,sa
569
569
  // NAV
570
570
  // ═══════════════════════════════════════════════════════════════════
571
571
  function navigateToPanel(target) {
572
- document.querySelectorAll('.nav-item').forEach(function(n) { n.classList.remove('active'); });
573
- var navItem = document.querySelector('[data-panel="' + target + '"]');
572
+ document.querySelectorAll('.nav-item').forEach((n) => { n.classList.remove('active'); });
573
+ var navItem = document.querySelector(`[data-panel="${target}"]`);
574
574
  if (navItem) navItem.classList.add('active');
575
- document.querySelectorAll('.panel').forEach(function(p) { p.classList.remove('active'); });
575
+ document.querySelectorAll('.panel').forEach((p) => { p.classList.remove('active'); });
576
576
  var panelId = target === 'playbooks' ? 'pb-panel'
577
577
  : target === 'builder' ? 'builder-panel'
578
- : target + '-panel';
578
+ : `${target}-panel`;
579
579
  var panel = document.getElementById(panelId);
580
580
  if (panel) panel.classList.add('active');
581
581
  if (target === 'builder') renderEdges();
582
582
  location.hash = target;
583
583
  }
584
584
 
585
- document.querySelectorAll('.nav-item').forEach(function(item) {
586
- item.addEventListener('click', function() {
585
+ document.querySelectorAll('.nav-item').forEach((item) => {
586
+ item.addEventListener('click', () => {
587
587
  var target = item.getAttribute('data-panel');
588
588
  navigateToPanel(target);
589
589
  });
590
590
  });
591
591
 
592
592
  // Hash-based routing on load
593
- (function() {
593
+ (() => {
594
594
  var hash = location.hash.replace('#', '');
595
595
  var validPanels = ['playbooks', 'builder', 'agents', 'memory', 'sessions'];
596
596
  if (hash && validPanels.indexOf(hash) !== -1) {
597
597
  // defer until after renderEdges is defined
598
- window.addEventListener('load', function() { navigateToPanel(hash); });
598
+ window.addEventListener('load', () => { navigateToPanel(hash); });
599
599
  }
600
600
  })();
601
601
 
@@ -620,11 +620,11 @@ function updateHeader() {
620
620
  else if (s === 'completed') done++;
621
621
  else if (s === 'failed') fail++;
622
622
  }
623
- document.getElementById('p-run').textContent = '● ' + running;
624
- document.getElementById('p-done').textContent = '✓ ' + done;
625
- document.getElementById('p-fail').textContent = '✗ ' + fail;
623
+ document.getElementById('p-run').textContent = `● ${running}`;
624
+ document.getElementById('p-done').textContent = `✓ ${done}`;
625
+ document.getElementById('p-fail').textContent = `✗ ${fail}`;
626
626
  document.getElementById('nb-run').textContent = String(running || Object.keys(runs).length);
627
- document.getElementById('nb-run').className = 'nav-badge' + (running ? '' : ' green');
627
+ document.getElementById('nb-run').className = `nav-badge${running ? '' : ' green'}`;
628
628
  var total = Object.keys(runs).length;
629
629
  document.getElementById('pb-subtitle').textContent = total + (total === 1 ? ' run' : ' runs');
630
630
  }
@@ -641,25 +641,25 @@ function statusLabel(r) {
641
641
  }
642
642
  function elapsed(r) {
643
643
  var ms = (r.endedAt || r.completedAt || Date.now()) - r.startedAt;
644
- if (ms < 1000) return ms + 'ms';
645
- if (ms < 60000) return (ms / 1000).toFixed(1) + 's';
646
- return Math.floor(ms / 60000) + 'm ' + Math.floor((ms % 60000) / 1000) + 's';
644
+ if (ms < 1000) return `${ms}ms`;
645
+ if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
646
+ return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
647
647
  }
648
648
  function renderCards() {
649
649
  var cards = document.getElementById('pb-cards');
650
650
  var empty = document.getElementById('pb-empty');
651
- var sorted = Object.values(runs).sort(function(a, b) { return b.startedAt - a.startedAt; });
651
+ var sorted = Object.values(runs).sort((a, b) => b.startedAt - a.startedAt);
652
652
  if (!sorted.length) { cards.innerHTML = ''; empty.style.display = 'flex'; return; }
653
653
  empty.style.display = 'none';
654
- cards.innerHTML = sorted.map(function(r) {
654
+ cards.innerHTML = sorted.map((r) => {
655
655
  var sl = statusLabel(r);
656
656
  var isRunning = r.status === 'running';
657
657
  var pct = progressPct(r);
658
658
  var logLines = (runLogs[r.id] || []).slice(-4);
659
659
  var logHtml = logLines.length
660
- ? logLines.map(function(l) {
660
+ ? logLines.map((l) => {
661
661
  var cls = l.type === 'ok' ? 'log-ok' : l.type === 'err' ? 'log-err' : 'log-info';
662
- return '<div><span class="log-ts">' + esc(l.ts) + '</span> <span class="' + cls + '">' + esc(l.text) + '</span></div>';
662
+ return `<div><span class="log-ts">${esc(l.ts)}</span> <span class="${cls}">${esc(l.text)}</span></div>`;
663
663
  }).join('')
664
664
  : '<div style="color:#2a2a3a">no events yet</div>';
665
665
  return '<div class="card' + (!isRunning ? ' done' : '') + '">' +
@@ -671,14 +671,14 @@ function renderCards() {
671
671
  '<span class="mitem">⏱ ' + esc(elapsed(r)) + '</span>' +
672
672
  '<span class="mitem">📦 ' + esc(r.itemsProcessed) + '/' + esc(r.itemsTotal || '?') + '</span>' +
673
673
  '<span class="mitem" style="color:#3a3a5a">id: ' + esc(r.id.slice(0,8)) + '</span>' +
674
- (isRunning ? '<button class="stop-btn" onclick="stopRun(\'' + esc(r.id) + '\')">■ stop</button>' : '') +
674
+ (isRunning ? `<button class="stop-btn" onclick="stopRun('${esc(r.id)}')">■ stop</button>` : '') +
675
675
  '</div>' +
676
676
  '<div class="progress-track"><div class="progress-fill" style="width:' + pct + '%"></div></div>' +
677
677
  '<div class="log-area">' + logHtml + '</div>' +
678
678
  '</div>';
679
679
  }).join('');
680
680
  }
681
- function stopRun(id) { fetch('/stop/' + id, { method: 'POST', headers: { 'x-monobrowse-token': (window.__MONOBROWSE_TOKEN__ || '') } }).catch(function() {}); }
681
+ function _stopRun(id) { fetch(`/stop/${id}`, { method: 'POST', headers: { 'x-monobrowse-token': (window.__MONOBROWSE_TOKEN__ || '') } }).catch(() => {}); }
682
682
 
683
683
  // ═══════════════════════════════════════════════════════════════════
684
684
  // NODE PALETTE DEFINITIONS
@@ -921,11 +921,11 @@ var canvas = {
921
921
  };
922
922
  var _nodeSeq = 1;
923
923
 
924
- function uid() { return 'n' + (_nodeSeq++) + '_' + Date.now().toString(36); }
924
+ function uid() { return `n${_nodeSeq++}_${Date.now().toString(36)}`; }
925
925
 
926
926
  // Find node type def
927
927
  function getNodeDef(type) {
928
- return NODE_TYPES.find(function(t) { return t.type === type; }) || null;
928
+ return NODE_TYPES.find((t) => t.type === type) || null;
929
929
  }
930
930
 
931
931
  // ═══════════════════════════════════════════════════════════════════
@@ -935,13 +935,11 @@ function buildPalette(filter) {
935
935
  filter = (filter || '').toLowerCase();
936
936
  var list = document.getElementById('palette-list');
937
937
  var html = '';
938
- CAT_ORDER.forEach(function(cat) {
939
- var nodes = NODE_TYPES.filter(function(n) {
940
- return n.cat === cat && (!filter || n.label.toLowerCase().includes(filter) || n.type.toLowerCase().includes(filter));
941
- });
938
+ CAT_ORDER.forEach((cat) => {
939
+ var nodes = NODE_TYPES.filter((n) => n.cat === cat && (!filter || n.label.toLowerCase().includes(filter) || n.type.toLowerCase().includes(filter)));
942
940
  if (!nodes.length) return;
943
- html += '<div class="palette-cat-label">' + cat + '</div>';
944
- nodes.forEach(function(n) {
941
+ html += `<div class="palette-cat-label">${cat}</div>`;
942
+ nodes.forEach((n) => {
945
943
  html += '<div class="palette-node" draggable="true" data-type="' + n.type + '" data-label="' + esc(n.label) + '">' +
946
944
  '<div class="palette-dot" style="background:' + n.color + '"></div>' +
947
945
  '<span>' + esc(n.label) + '</span></div>';
@@ -949,15 +947,15 @@ function buildPalette(filter) {
949
947
  });
950
948
  list.innerHTML = html;
951
949
 
952
- list.querySelectorAll('.palette-node').forEach(function(el) {
953
- el.addEventListener('dragstart', function(e) {
950
+ list.querySelectorAll('.palette-node').forEach((el) => {
951
+ el.addEventListener('dragstart', (e) => {
954
952
  e.dataTransfer.setData('text/plain', el.getAttribute('data-type'));
955
953
  e.dataTransfer.effectAllowed = 'copy';
956
954
  });
957
955
  });
958
956
  }
959
957
 
960
- document.getElementById('palette-search').addEventListener('input', function(e) {
958
+ document.getElementById('palette-search').addEventListener('input', (e) => {
961
959
  buildPalette(e.target.value);
962
960
  });
963
961
  buildPalette('');
@@ -967,7 +965,7 @@ buildPalette('');
967
965
  // ═══════════════════════════════════════════════════════════════════
968
966
  function applyTransform() {
969
967
  document.getElementById('canvas-nodes').style.transform =
970
- 'translate(' + canvas.panX + 'px,' + canvas.panY + 'px) scale(' + canvas.zoom + ')';
968
+ `translate(${canvas.panX}px,${canvas.panY}px) scale(${canvas.zoom})`;
971
969
  renderEdges();
972
970
  }
973
971
 
@@ -995,7 +993,7 @@ document.getElementById('canvas-wrap').addEventListener('mousedown', function(e)
995
993
  e.preventDefault();
996
994
  }
997
995
  });
998
- document.addEventListener('mousemove', function(e) {
996
+ document.addEventListener('mousemove', (e) => {
999
997
  if (_panning) {
1000
998
  canvas.panX = e.clientX - _panStart.x;
1001
999
  canvas.panY = e.clientY - _panStart.y;
@@ -1004,7 +1002,7 @@ document.addEventListener('mousemove', function(e) {
1004
1002
  if (_dragEdge.active) updateDragEdge(e);
1005
1003
  if (_draggingNode) updateNodeDrag(e);
1006
1004
  });
1007
- document.addEventListener('mouseup', function(e) {
1005
+ document.addEventListener('mouseup', (e) => {
1008
1006
  _panning = false;
1009
1007
  if (_draggingNode) endNodeDrag(e);
1010
1008
  if (_dragEdge.active) endDragEdge(e);
@@ -1020,7 +1018,7 @@ document.getElementById('canvas-wrap').addEventListener('mousedown', function(e)
1020
1018
  });
1021
1019
 
1022
1020
  // Drop from palette
1023
- document.getElementById('canvas-wrap').addEventListener('dragover', function(e) { e.preventDefault(); });
1021
+ document.getElementById('canvas-wrap').addEventListener('dragover', (e) => { e.preventDefault(); });
1024
1022
  document.getElementById('canvas-wrap').addEventListener('drop', function(e) {
1025
1023
  e.preventDefault();
1026
1024
  var type = e.dataTransfer.getData('text/plain');
@@ -1034,15 +1032,15 @@ document.getElementById('canvas-wrap').addEventListener('drop', function(e) {
1034
1032
  });
1035
1033
 
1036
1034
  // Zoom buttons
1037
- document.getElementById('btn-zoom-in').addEventListener('click', function() {
1035
+ document.getElementById('btn-zoom-in').addEventListener('click', () => {
1038
1036
  canvas.zoom = Math.min(3, canvas.zoom * 1.2);
1039
1037
  applyTransform();
1040
1038
  });
1041
- document.getElementById('btn-zoom-out').addEventListener('click', function() {
1039
+ document.getElementById('btn-zoom-out').addEventListener('click', () => {
1042
1040
  canvas.zoom = Math.max(0.2, canvas.zoom / 1.2);
1043
1041
  applyTransform();
1044
1042
  });
1045
- document.getElementById('btn-fit').addEventListener('click', function() {
1043
+ document.getElementById('btn-fit').addEventListener('click', () => {
1046
1044
  fitCanvas();
1047
1045
  });
1048
1046
 
@@ -1051,7 +1049,7 @@ function fitCanvas() {
1051
1049
  var wrap = document.getElementById('canvas-wrap');
1052
1050
  var W = wrap.clientWidth, H = wrap.clientHeight;
1053
1051
  var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
1054
- canvas.nodes.forEach(function(n) {
1052
+ canvas.nodes.forEach((n) => {
1055
1053
  minX = Math.min(minX, n.x); minY = Math.min(minY, n.y);
1056
1054
  maxX = Math.max(maxX, n.x + 200); maxY = Math.max(maxY, n.y + nodeH(n));
1057
1055
  });
@@ -1096,8 +1094,8 @@ function addNode(type, x, y) {
1096
1094
  }
1097
1095
 
1098
1096
  function removeNode(id) {
1099
- canvas.nodes = canvas.nodes.filter(function(n) { return n.id !== id; });
1100
- canvas.edges = canvas.edges.filter(function(e) { return e.from !== id && e.to !== id; });
1097
+ canvas.nodes = canvas.nodes.filter((n) => n.id !== id);
1098
+ canvas.edges = canvas.edges.filter((e) => e.from !== id && e.to !== id);
1101
1099
  if (canvas.selectedId === id) { canvas.selectedId = null; renderPropsPanel(); }
1102
1100
  renderNodes();
1103
1101
  renderEdges();
@@ -1112,7 +1110,7 @@ var _dragNodeStart = null;
1112
1110
  function startNodeDrag(e, nodeId) {
1113
1111
  e.stopPropagation();
1114
1112
  _draggingNode = nodeId;
1115
- var n = canvas.nodes.find(function(n) { return n.id === nodeId; });
1113
+ var n = canvas.nodes.find((n) => n.id === nodeId);
1116
1114
  _dragNodeStart = {
1117
1115
  mx: e.clientX, my: e.clientY,
1118
1116
  nx: n.x, ny: n.y,
@@ -1125,7 +1123,7 @@ function updateNodeDrag(e) {
1125
1123
  if (!_draggingNode) return;
1126
1124
  var dx = (e.clientX - _dragNodeStart.mx) / canvas.zoom;
1127
1125
  var dy = (e.clientY - _dragNodeStart.my) / canvas.zoom;
1128
- var n = canvas.nodes.find(function(n) { return n.id === _draggingNode; });
1126
+ var n = canvas.nodes.find((n) => n.id === _draggingNode);
1129
1127
  if (n) { n.x = _dragNodeStart.nx + dx; n.y = _dragNodeStart.ny + dy; }
1130
1128
  renderNodePosition(_draggingNode);
1131
1129
  renderEdges();
@@ -1135,9 +1133,9 @@ function endNodeDrag(e) {
1135
1133
  _dragNodeStart = null;
1136
1134
  }
1137
1135
  function renderNodePosition(id) {
1138
- var el = document.querySelector('[data-node-id="' + id + '"]');
1139
- var n = canvas.nodes.find(function(n) { return n.id === id; });
1140
- if (el && n) { el.style.left = n.x + 'px'; el.style.top = n.y + 'px'; }
1136
+ var el = document.querySelector(`[data-node-id="${id}"]`);
1137
+ var n = canvas.nodes.find((n) => n.id === id);
1138
+ if (el && n) { el.style.left = `${n.x}px`; el.style.top = `${n.y}px`; }
1141
1139
  }
1142
1140
 
1143
1141
  // ═══════════════════════════════════════════════════════════════════
@@ -1164,7 +1162,7 @@ function updateDragEdge(e) {
1164
1162
  var sx = _dragEdge.x, sy = _dragEdge.y;
1165
1163
  var dx = Math.max(60, Math.abs(tx - sx) * 0.5);
1166
1164
  document.getElementById('drag-edge').setAttribute('d',
1167
- 'M' + sx + ',' + sy + ' C' + (sx+dx) + ',' + sy + ' ' + (tx-dx) + ',' + ty + ' ' + tx + ',' + ty);
1165
+ `M${sx},${sy} C${sx+dx},${sy} ${tx-dx},${ty} ${tx},${ty}`);
1168
1166
  }
1169
1167
  function endDragEdge(e) {
1170
1168
  document.getElementById('drag-edge').style.display = 'none';
@@ -1174,13 +1172,11 @@ function dropOnInputPort(e, toNodeId, toPortIdx) {
1174
1172
  if (!_dragEdge.active) return;
1175
1173
  e.stopPropagation();
1176
1174
  if (_dragEdge.fromNodeId === toNodeId) { endDragEdge(e); return; }
1177
- var fromNode = canvas.nodes.find(function(n) { return n.id === _dragEdge.fromNodeId; });
1175
+ var fromNode = canvas.nodes.find((n) => n.id === _dragEdge.fromNodeId);
1178
1176
  var def = fromNode && (fromNode._def || getNodeDef(fromNode.type));
1179
- var handle = def && def.outputs[_dragEdge.fromPortIdx] ? def.outputs[_dragEdge.fromPortIdx].label : undefined;
1177
+ var handle = def?.outputs[_dragEdge.fromPortIdx] ? def.outputs[_dragEdge.fromPortIdx].label : undefined;
1180
1178
  // Remove existing edge from same out port if any
1181
- canvas.edges = canvas.edges.filter(function(ed) {
1182
- return !(ed.from === _dragEdge.fromNodeId && ed.fromPort === _dragEdge.fromPortIdx && ed.to === toNodeId && ed.toPort === toPortIdx);
1183
- });
1179
+ canvas.edges = canvas.edges.filter((ed) => !(ed.from === _dragEdge.fromNodeId && ed.fromPort === _dragEdge.fromPortIdx && ed.to === toNodeId && ed.toPort === toPortIdx));
1184
1180
  canvas.edges.push({
1185
1181
  id: uid(),
1186
1182
  from: _dragEdge.fromNodeId,
@@ -1194,12 +1190,12 @@ function dropOnInputPort(e, toNodeId, toPortIdx) {
1194
1190
  }
1195
1191
 
1196
1192
  function getOutPortPos(nodeId, portIdx) {
1197
- var n = canvas.nodes.find(function(n) { return n.id === nodeId; });
1193
+ var n = canvas.nodes.find((n) => n.id === nodeId);
1198
1194
  if (!n) return {x:0,y:0};
1199
1195
  return { x: n.x + 200, y: n.y + 40 + 6 + portIdx * 26 + 13 };
1200
1196
  }
1201
- function getInPortPos(nodeId, portIdx) {
1202
- var n = canvas.nodes.find(function(n) { return n.id === nodeId; });
1197
+ function _getInPortPos(nodeId, portIdx) {
1198
+ var n = canvas.nodes.find((n) => n.id === nodeId);
1203
1199
  if (!n) return {x:0,y:0};
1204
1200
  return { x: n.x, y: n.y + 40 + 6 + portIdx * 26 + 13 };
1205
1201
  }
@@ -1210,14 +1206,14 @@ function getInPortPos(nodeId, portIdx) {
1210
1206
  function renderNodes() {
1211
1207
  var container = document.getElementById('canvas-nodes');
1212
1208
  var existingIds = new Set();
1213
- canvas.nodes.forEach(function(n) { existingIds.add(n.id); });
1209
+ canvas.nodes.forEach((n) => { existingIds.add(n.id); });
1214
1210
  // Remove nodes that no longer exist
1215
- container.querySelectorAll('[data-node-id]').forEach(function(el) {
1211
+ container.querySelectorAll('[data-node-id]').forEach((el) => {
1216
1212
  if (!existingIds.has(el.getAttribute('data-node-id'))) el.remove();
1217
1213
  });
1218
1214
  // Add or update each node
1219
- canvas.nodes.forEach(function(n) {
1220
- var existing = container.querySelector('[data-node-id="' + n.id + '"]');
1215
+ canvas.nodes.forEach((n) => {
1216
+ var existing = container.querySelector(`[data-node-id="${n.id}"]`);
1221
1217
  var def = n._def || getNodeDef(n.type) || { inputs:[{label:'in'}], outputs:[{label:'out'}], color:'#7c3aed' };
1222
1218
  var color = def.color || '#7c3aed';
1223
1219
  var rows = Math.max(def.inputs.length, def.outputs.length, 1);
@@ -1226,21 +1222,21 @@ function renderNodes() {
1226
1222
 
1227
1223
  if (!existing) {
1228
1224
  var el = document.createElement('div');
1229
- el.className = 'cn' + (isSelected ? ' selected' : '') + (n.runStatus === 'running' ? ' running' : '');
1225
+ el.className = `cn${isSelected ? ' selected' : ''}${n.runStatus === 'running' ? ' running' : ''}`;
1230
1226
  el.setAttribute('data-node-id', n.id);
1231
- el.style.left = n.x + 'px';
1232
- el.style.top = n.y + 'px';
1233
- el.style.height = h + 'px';
1227
+ el.style.left = `${n.x}px`;
1228
+ el.style.top = `${n.y}px`;
1229
+ el.style.height = `${h}px`;
1234
1230
  el.style.borderColor = isSelected ? color : (n.runStatus === 'error' ? '#ef444444' : n.runStatus === 'ok' ? '#10b98133' : 'rgba(124,58,237,0.15)');
1235
1231
 
1236
1232
  // Status badge
1237
1233
  var statusHtml = '';
1238
1234
  if (n.runStatus) {
1239
- var statusText = n.runStatus === 'ok' ? '✓ ' + n.runItems + ' item' + (n.runItems !== 1 ? 's' : '') + (n.runDuration ? ' · ' + n.runDuration + 'ms' : '')
1235
+ var statusText = n.runStatus === 'ok' ? `✓ ${n.runItems} item${n.runItems !== 1 ? 's' : ''}${n.runDuration ? ` · ${n.runDuration}ms` : ''}`
1240
1236
  : n.runStatus === 'running' ? '⏳ running'
1241
1237
  : n.runStatus === 'error' ? '✕ error'
1242
1238
  : '— skipped';
1243
- statusHtml = '<div class="cn-status ' + n.runStatus + '">' + esc(statusText) + '</div>';
1239
+ statusHtml = `<div class="cn-status ${n.runStatus}">${esc(statusText)}</div>`;
1244
1240
  }
1245
1241
 
1246
1242
  // Header
@@ -1279,11 +1275,11 @@ function renderNodes() {
1279
1275
  el.innerHTML = statusHtml + headerHtml + portsHtml;
1280
1276
 
1281
1277
  // Events
1282
- el.querySelector('.cn-header').addEventListener('mousedown', function(e) {
1278
+ el.querySelector('.cn-header').addEventListener('mousedown', (e) => {
1283
1279
  if (e.target.closest('.cn-del')) return;
1284
1280
  startNodeDrag(e, n.id);
1285
1281
  });
1286
- el.addEventListener('mousedown', function(e) {
1282
+ el.addEventListener('mousedown', (e) => {
1287
1283
  if (e.target.closest('.cn-del') || e.target.closest('.cn-port')) return;
1288
1284
  e.stopPropagation();
1289
1285
  canvas.selectedId = n.id;
@@ -1291,47 +1287,47 @@ function renderNodes() {
1291
1287
  renderNodes();
1292
1288
  });
1293
1289
  var delBtn = el.querySelector('.cn-del');
1294
- if (delBtn) delBtn.addEventListener('mousedown', function(e) {
1290
+ if (delBtn) delBtn.addEventListener('mousedown', (e) => {
1295
1291
  e.stopPropagation();
1296
1292
  removeNode(n.id);
1297
1293
  });
1298
- el.querySelectorAll('.cn-port.out').forEach(function(port) {
1299
- port.addEventListener('mousedown', function(e) {
1294
+ el.querySelectorAll('.cn-port.out').forEach((port) => {
1295
+ port.addEventListener('mousedown', (e) => {
1300
1296
  e.stopPropagation();
1301
1297
  var portIdx = parseInt(port.getAttribute('data-out-port'), 10);
1302
1298
  startDragEdge(e, n.id, portIdx);
1303
1299
  });
1304
1300
  });
1305
- el.querySelectorAll('.cn-port.in').forEach(function(port) {
1306
- port.addEventListener('mouseup', function(e) {
1301
+ el.querySelectorAll('.cn-port.in').forEach((port) => {
1302
+ port.addEventListener('mouseup', (e) => {
1307
1303
  var portIdx = parseInt(port.getAttribute('data-in-port'), 10);
1308
1304
  dropOnInputPort(e, n.id, portIdx);
1309
1305
  });
1310
- port.addEventListener('mouseenter', function() { port.classList.add('highlight'); });
1311
- port.addEventListener('mouseleave', function() { port.classList.remove('highlight'); });
1306
+ port.addEventListener('mouseenter', () => { port.classList.add('highlight'); });
1307
+ port.addEventListener('mouseleave', () => { port.classList.remove('highlight'); });
1312
1308
  });
1313
1309
 
1314
1310
  container.appendChild(el);
1315
1311
  } else {
1316
1312
  // Update position, selection, status
1317
- existing.style.left = n.x + 'px';
1318
- existing.style.top = n.y + 'px';
1319
- existing.className = 'cn' + (isSelected ? ' selected' : '') + (n.runStatus === 'running' ? ' running' : '');
1313
+ existing.style.left = `${n.x}px`;
1314
+ existing.style.top = `${n.y}px`;
1315
+ existing.className = `cn${isSelected ? ' selected' : ''}${n.runStatus === 'running' ? ' running' : ''}`;
1320
1316
  existing.style.borderColor = isSelected ? color : (n.runStatus === 'error' ? '#ef444444' : n.runStatus === 'ok' ? '#10b98133' : 'rgba(124,58,237,0.15)');
1321
1317
  // Update status badge
1322
1318
  var badge = existing.querySelector('.cn-status');
1323
1319
  if (n.runStatus) {
1324
- var statusText2 = n.runStatus === 'ok' ? '✓ ' + n.runItems + ' item' + (n.runItems !== 1 ? 's' : '') + (n.runDuration ? ' · ' + n.runDuration + 'ms' : '')
1320
+ var statusText2 = n.runStatus === 'ok' ? `✓ ${n.runItems} item${n.runItems !== 1 ? 's' : ''}${n.runDuration ? ` · ${n.runDuration}ms` : ''}`
1325
1321
  : n.runStatus === 'running' ? '⏳ running'
1326
1322
  : n.runStatus === 'error' ? '✕ error'
1327
1323
  : '— skipped';
1328
1324
  if (!badge) {
1329
1325
  var newBadge = document.createElement('div');
1330
- newBadge.className = 'cn-status ' + n.runStatus;
1326
+ newBadge.className = `cn-status ${n.runStatus}`;
1331
1327
  newBadge.textContent = statusText2;
1332
1328
  existing.insertBefore(newBadge, existing.firstChild);
1333
1329
  } else {
1334
- badge.className = 'cn-status ' + n.runStatus;
1330
+ badge.className = `cn-status ${n.runStatus}`;
1335
1331
  badge.textContent = statusText2;
1336
1332
  }
1337
1333
  } else if (badge) {
@@ -1347,16 +1343,16 @@ function renderNodes() {
1347
1343
  function renderEdges() {
1348
1344
  var layer = document.getElementById('edge-layer');
1349
1345
  layer.innerHTML = '';
1350
- canvas.edges.forEach(function(edge) {
1351
- var fromNode = canvas.nodes.find(function(n) { return n.id === edge.from; });
1352
- var toNode = canvas.nodes.find(function(n) { return n.id === edge.to; });
1346
+ canvas.edges.forEach((edge) => {
1347
+ var fromNode = canvas.nodes.find((n) => n.id === edge.from);
1348
+ var toNode = canvas.nodes.find((n) => n.id === edge.to);
1353
1349
  if (!fromNode || !toNode) return;
1354
1350
  var sx = (fromNode.x + 200) * canvas.zoom + canvas.panX;
1355
1351
  var sy = (fromNode.y + 40 + 6 + edge.fromPort * 26 + 13) * canvas.zoom + canvas.panY;
1356
1352
  var tx = toNode.x * canvas.zoom + canvas.panX;
1357
1353
  var ty = (toNode.y + 40 + 6 + edge.toPort * 26 + 13) * canvas.zoom + canvas.panY;
1358
1354
  var dx = Math.max(60, Math.abs(tx - sx) * 0.5) * canvas.zoom;
1359
- var d = 'M' + sx + ',' + sy + ' C' + (sx+dx) + ',' + sy + ' ' + (tx-dx) + ',' + ty + ' ' + tx + ',' + ty;
1355
+ var d = `M${sx},${sy} C${sx+dx},${sy} ${tx-dx},${ty} ${tx},${ty}`;
1360
1356
  var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1361
1357
  path.setAttribute('d', d);
1362
1358
  path.setAttribute('stroke', '#7c3aed88');
@@ -1367,7 +1363,7 @@ function renderEdges() {
1367
1363
  layer.appendChild(path);
1368
1364
 
1369
1365
  // Remove edge on click
1370
- (function(edgeId, midX, midY) {
1366
+ ((edgeId, _midX, _midY) => {
1371
1367
  path.style.cursor = 'pointer';
1372
1368
  path.style.strokeWidth = '4';
1373
1369
  path.style.stroke = 'transparent';
@@ -1377,8 +1373,8 @@ function renderEdges() {
1377
1373
  hit.setAttribute('stroke-width', '8');
1378
1374
  hit.setAttribute('fill', 'none');
1379
1375
  hit.style.cursor = 'pointer';
1380
- hit.addEventListener('click', function() {
1381
- canvas.edges = canvas.edges.filter(function(e) { return e.id !== edgeId; });
1376
+ hit.addEventListener('click', () => {
1377
+ canvas.edges = canvas.edges.filter((e) => e.id !== edgeId);
1382
1378
  renderEdges();
1383
1379
  });
1384
1380
  layer.appendChild(hit);
@@ -1391,7 +1387,7 @@ function renderEdges() {
1391
1387
  // ═══════════════════════════════════════════════════════════════════
1392
1388
  function renderPropsPanel() {
1393
1389
  var body = document.getElementById('props-body');
1394
- var node = canvas.nodes.find(function(n) { return n.id === canvas.selectedId; });
1390
+ var node = canvas.nodes.find((n) => n.id === canvas.selectedId);
1395
1391
  if (!node) {
1396
1392
  body.innerHTML = '<div class="empty" style="padding:20px;color:#333;font-size:11px;text-align:center">Select a node to edit its properties</div>';
1397
1393
  return;
@@ -1401,41 +1397,37 @@ function renderPropsPanel() {
1401
1397
  '<input class="prop-input" id="prop-node-name" value="' + esc(node.name || '') + '" /></div>';
1402
1398
  html += '<div class="prop-row"><div class="prop-label">On error</div>' +
1403
1399
  '<select class="prop-select" id="prop-on-error">' +
1404
- ['stop','skip'].map(function(v) {
1405
- return '<option value="' + v + '"' + (node.onError === v ? ' selected' : '') + '>' + v + '</option>';
1406
- }).join('') + '</select></div>';
1400
+ ['stop','skip'].map((v) => `<option value="${v}"${node.onError === v ? ' selected' : ''}>${v}</option>`).join('') + '</select></div>';
1407
1401
 
1408
- fields.forEach(function(f) {
1402
+ fields.forEach((f) => {
1409
1403
  var val = node.config[f.key] !== undefined ? String(node.config[f.key]) : '';
1410
- html += '<div class="prop-row"><div class="prop-label">' + esc(f.label) + '</div>';
1404
+ html += `<div class="prop-row"><div class="prop-label">${esc(f.label)}</div>`;
1411
1405
  if (f.type === 'select') {
1412
1406
  html += '<select class="prop-select" data-key="' + f.key + '">' +
1413
- (f.options || []).map(function(o) {
1414
- return '<option value="' + esc(o) + '"' + (val === o ? ' selected' : '') + '>' + esc(o) + '</option>';
1415
- }).join('') + '</select>';
1407
+ (f.options || []).map((o) => `<option value="${esc(o)}"${val === o ? ' selected' : ''}>${esc(o)}</option>`).join('') + '</select>';
1416
1408
  } else if (f.type === 'textarea') {
1417
- html += '<textarea class="prop-textarea" data-key="' + f.key + '">' + esc(val) + '</textarea>';
1409
+ html += `<textarea class="prop-textarea" data-key="${f.key}">${esc(val)}</textarea>`;
1418
1410
  } else {
1419
- html += '<input class="prop-input" data-key="' + f.key + '" value="' + esc(val) + '" />';
1411
+ html += `<input class="prop-input" data-key="${f.key}" value="${esc(val)}" />`;
1420
1412
  }
1421
1413
  html += '</div>';
1422
1414
  });
1423
1415
 
1424
1416
  body.innerHTML = html;
1425
1417
 
1426
- body.querySelector('#prop-node-name').addEventListener('input', function(e) {
1418
+ body.querySelector('#prop-node-name').addEventListener('input', (e) => {
1427
1419
  node.name = e.target.value;
1428
- var el = document.querySelector('[data-node-id="' + node.id + '"] .cn-label');
1420
+ var el = document.querySelector(`[data-node-id="${node.id}"] .cn-label`);
1429
1421
  if (el) el.textContent = node.name;
1430
1422
  });
1431
- body.querySelector('#prop-on-error').addEventListener('change', function(e) {
1423
+ body.querySelector('#prop-on-error').addEventListener('change', (e) => {
1432
1424
  node.onError = e.target.value;
1433
1425
  });
1434
- body.querySelectorAll('[data-key]').forEach(function(el) {
1435
- el.addEventListener('input', function() {
1426
+ body.querySelectorAll('[data-key]').forEach((el) => {
1427
+ el.addEventListener('input', () => {
1436
1428
  node.config[el.getAttribute('data-key')] = el.value;
1437
1429
  });
1438
- el.addEventListener('change', function() {
1430
+ el.addEventListener('change', () => {
1439
1431
  node.config[el.getAttribute('data-key')] = el.value;
1440
1432
  });
1441
1433
  });
@@ -1445,16 +1437,14 @@ function renderPropsPanel() {
1445
1437
  // PLAYBOOK SERIALIZATION
1446
1438
  // ═══════════════════════════════════════════════════════════════════
1447
1439
  function toPlaybookDef() {
1448
- var id = canvas.playbookId || ('pb_' + Date.now().toString(36));
1440
+ var id = canvas.playbookId || (`pb_${Date.now().toString(36)}`);
1449
1441
  canvas.playbookId = id;
1450
1442
  var name = document.getElementById('pb-name-input').value.trim() || 'Untitled Playbook';
1451
1443
  return {
1452
1444
  id: id,
1453
1445
  name: name,
1454
- nodes: canvas.nodes.map(function(n) {
1455
- return { id: n.id, type: n.type, name: n.name, config: n.config, onError: n.onError || 'stop' };
1456
- }),
1457
- connections: canvas.edges.map(function(e) {
1446
+ nodes: canvas.nodes.map((n) => ({ id: n.id, type: n.type, name: n.name, config: n.config, onError: n.onError || 'stop' })),
1447
+ connections: canvas.edges.map((e) => {
1458
1448
  var res = { from: e.from, to: e.to };
1459
1449
  if (e.handle && e.handle !== 'main' && e.handle !== 'out' && e.handle !== 'items') res.handle = e.handle;
1460
1450
  return res;
@@ -1473,7 +1463,7 @@ function loadPlaybookDef(pb) {
1473
1463
 
1474
1464
  // Lay out nodes in a simple column if no positions stored
1475
1465
  var x = 100, y = 60;
1476
- (pb.nodes || []).forEach(function(n, i) {
1466
+ (pb.nodes || []).forEach((n, i) => {
1477
1467
  var def = getNodeDef(n.type) || { inputs:[{label:'in'}], outputs:[{label:'out'}], color:'#7c3aed', label: n.type };
1478
1468
  var node = {
1479
1469
  id: n.id,
@@ -1492,13 +1482,13 @@ function loadPlaybookDef(pb) {
1492
1482
  });
1493
1483
 
1494
1484
  // Build edges from connections
1495
- (pb.connections || []).forEach(function(c) {
1496
- var fromNode = canvas.nodes.find(function(n) { return n.id === c.from; });
1497
- var toNode = canvas.nodes.find(function(n) { return n.id === c.to; });
1485
+ (pb.connections || []).forEach((c) => {
1486
+ var fromNode = canvas.nodes.find((n) => n.id === c.from);
1487
+ var toNode = canvas.nodes.find((n) => n.id === c.to);
1498
1488
  if (!fromNode || !toNode) return;
1499
1489
  var fromDef = fromNode._def || { outputs: [{label:'main'}] };
1500
1490
  var handle = c.handle || (fromDef.outputs[0] ? fromDef.outputs[0].label : 'main');
1501
- var fromPortIdx = fromDef.outputs.findIndex(function(o) { return o.label === handle; });
1491
+ var fromPortIdx = fromDef.outputs.findIndex((o) => o.label === handle);
1502
1492
  if (fromPortIdx < 0) fromPortIdx = 0;
1503
1493
  canvas.edges.push({
1504
1494
  id: uid(),
@@ -1519,7 +1509,7 @@ function loadPlaybookDef(pb) {
1519
1509
  // ═══════════════════════════════════════════════════════════════════
1520
1510
  // TOOLBAR ACTIONS
1521
1511
  // ═══════════════════════════════════════════════════════════════════
1522
- document.getElementById('btn-new').addEventListener('click', function() {
1512
+ document.getElementById('btn-new').addEventListener('click', () => {
1523
1513
  canvas.nodes = [];
1524
1514
  canvas.edges = [];
1525
1515
  canvas.playbookId = null;
@@ -1531,25 +1521,25 @@ document.getElementById('btn-new').addEventListener('click', function() {
1531
1521
  renderPropsPanel();
1532
1522
  });
1533
1523
 
1534
- document.getElementById('btn-save').addEventListener('click', function() {
1524
+ document.getElementById('btn-save').addEventListener('click', () => {
1535
1525
  var pb = toPlaybookDef();
1536
1526
  fetch('/api/playbooks', {
1537
1527
  method: 'POST',
1538
1528
  headers: { 'Content-Type': 'application/json' },
1539
1529
  body: JSON.stringify(pb),
1540
- }).then(function(r) { return r.json(); }).then(function(saved) {
1530
+ }).then((r) => r.json()).then((saved) => {
1541
1531
  canvas.playbookId = saved.id;
1542
- showToast('Playbook saved: ' + saved.name);
1543
- }).catch(function(e) {
1544
- showToast('Save failed: ' + e, true);
1532
+ showToast(`Playbook saved: ${saved.name}`);
1533
+ }).catch((e) => {
1534
+ showToast(`Save failed: ${e}`, true);
1545
1535
  });
1546
1536
  });
1547
1537
 
1548
- document.getElementById('btn-open').addEventListener('click', function() {
1538
+ document.getElementById('btn-open').addEventListener('click', () => {
1549
1539
  openPlaybookList();
1550
1540
  });
1551
1541
 
1552
- document.getElementById('btn-run').addEventListener('click', function() {
1542
+ document.getElementById('btn-run').addEventListener('click', () => {
1553
1543
  if (!canvas.playbookId) {
1554
1544
  // Auto-save first
1555
1545
  var pb = toPlaybookDef();
@@ -1557,9 +1547,9 @@ document.getElementById('btn-run').addEventListener('click', function() {
1557
1547
  method: 'POST',
1558
1548
  headers: { 'Content-Type': 'application/json' },
1559
1549
  body: JSON.stringify(pb),
1560
- }).then(function() {
1550
+ }).then(() => {
1561
1551
  runCurrentPlaybook(pb.id);
1562
- }).catch(function(e) { showToast('Error: ' + e, true); });
1552
+ }).catch((e) => { showToast(`Error: ${e}`, true); });
1563
1553
  } else {
1564
1554
  // Save then run
1565
1555
  var pb2 = toPlaybookDef();
@@ -1567,29 +1557,29 @@ document.getElementById('btn-run').addEventListener('click', function() {
1567
1557
  method: 'POST',
1568
1558
  headers: { 'Content-Type': 'application/json' },
1569
1559
  body: JSON.stringify(pb2),
1570
- }).then(function() {
1560
+ }).then(() => {
1571
1561
  runCurrentPlaybook(pb2.id);
1572
- }).catch(function(e) { showToast('Error: ' + e, true); });
1562
+ }).catch((e) => { showToast(`Error: ${e}`, true); });
1573
1563
  }
1574
1564
  });
1575
1565
 
1576
1566
  function runCurrentPlaybook(playbookId) {
1577
1567
  // Reset node statuses
1578
- canvas.nodes.forEach(function(n) { n.runStatus = null; n.runItems = 0; n.runDuration = null; });
1568
+ canvas.nodes.forEach((n) => { n.runStatus = null; n.runItems = 0; n.runDuration = null; });
1579
1569
  renderNodes();
1580
- fetch('/api/playbooks/' + playbookId + '/run', { method: 'POST' })
1581
- .then(function(r) { return r.json(); })
1582
- .then(function(res) {
1570
+ fetch(`/api/playbooks/${playbookId}/run`, { method: 'POST' })
1571
+ .then((r) => r.json())
1572
+ .then((res) => {
1583
1573
  if (res.ok) {
1584
1574
  showToast('Playbook started — watch the Runs tab');
1585
1575
  // Switch to runs panel
1586
- document.querySelectorAll('.nav-item').forEach(function(n) { n.classList.remove('active'); });
1576
+ document.querySelectorAll('.nav-item').forEach((n) => { n.classList.remove('active'); });
1587
1577
  document.querySelector('[data-panel="playbooks"]').classList.add('active');
1588
- document.querySelectorAll('.panel').forEach(function(p) { p.classList.remove('active'); });
1578
+ document.querySelectorAll('.panel').forEach((p) => { p.classList.remove('active'); });
1589
1579
  document.getElementById('pb-panel').classList.add('active');
1590
1580
  }
1591
1581
  })
1592
- .catch(function(e) { showToast('Run failed: ' + e, true); });
1582
+ .catch((e) => { showToast(`Run failed: ${e}`, true); });
1593
1583
  }
1594
1584
 
1595
1585
  // ═══════════════════════════════════════════════════════════════════
@@ -1599,36 +1589,34 @@ function openPlaybookList() {
1599
1589
  var overlay = document.getElementById('pb-list-overlay');
1600
1590
  overlay.classList.add('show');
1601
1591
  fetch('/api/playbooks')
1602
- .then(function(r) { return r.json(); })
1603
- .then(function(list) {
1592
+ .then((r) => r.json())
1593
+ .then((list) => {
1604
1594
  var body = document.getElementById('pblo-body');
1605
1595
  if (!list.length) {
1606
1596
  body.innerHTML = '<div class="pblo-empty">No saved playbooks yet. Build one and click Save!</div>';
1607
1597
  return;
1608
1598
  }
1609
- body.innerHTML = list.map(function(pb) {
1610
- return '<div class="pblo-item" data-pb-id="' + esc(pb.id) + '">' +
1599
+ body.innerHTML = list.map((pb) => '<div class="pblo-item" data-pb-id="' + esc(pb.id) + '">' +
1611
1600
  '<span class="pblo-item-name">' + esc(pb.name) + '</span>' +
1612
1601
  '<span class="pblo-item-meta">' + (pb.nodes ? pb.nodes.length : 0) + ' nodes</span>' +
1613
1602
  '<button class="pblo-del" data-del-id="' + esc(pb.id) + '" title="Delete">✕</button>' +
1614
- '</div>';
1615
- }).join('');
1616
- body.querySelectorAll('.pblo-item').forEach(function(el) {
1617
- el.addEventListener('click', function(e) {
1603
+ '</div>').join('');
1604
+ body.querySelectorAll('.pblo-item').forEach((el) => {
1605
+ el.addEventListener('click', (e) => {
1618
1606
  if (e.target.closest('.pblo-del')) return;
1619
1607
  var pbId = el.getAttribute('data-pb-id');
1620
- fetch('/api/playbooks/' + pbId).then(function(r) { return r.json(); }).then(function(pb) {
1608
+ fetch(`/api/playbooks/${pbId}`).then((r) => r.json()).then((pb) => {
1621
1609
  loadPlaybookDef(pb);
1622
1610
  overlay.classList.remove('show');
1623
1611
  });
1624
1612
  });
1625
1613
  });
1626
- body.querySelectorAll('.pblo-del').forEach(function(btn) {
1627
- btn.addEventListener('click', function(e) {
1614
+ body.querySelectorAll('.pblo-del').forEach((btn) => {
1615
+ btn.addEventListener('click', (e) => {
1628
1616
  e.stopPropagation();
1629
1617
  var delId = btn.getAttribute('data-del-id');
1630
1618
  if (!confirm('Delete this playbook?')) return;
1631
- fetch('/api/playbooks/' + delId, { method: 'DELETE' }).then(function() {
1619
+ fetch(`/api/playbooks/${delId}`, { method: 'DELETE' }).then(() => {
1632
1620
  if (canvas.playbookId === delId) {
1633
1621
  canvas.playbookId = null;
1634
1622
  canvas.nodes = [];
@@ -1645,12 +1633,12 @@ function openPlaybookList() {
1645
1633
  });
1646
1634
  });
1647
1635
  })
1648
- .catch(function() {
1636
+ .catch(() => {
1649
1637
  document.getElementById('pblo-body').innerHTML = '<div class="pblo-empty">Failed to load playbooks.</div>';
1650
1638
  });
1651
1639
  }
1652
1640
 
1653
- document.getElementById('pblo-close-btn').addEventListener('click', function() {
1641
+ document.getElementById('pblo-close-btn').addEventListener('click', () => {
1654
1642
  document.getElementById('pb-list-overlay').classList.remove('show');
1655
1643
  });
1656
1644
 
@@ -1663,7 +1651,7 @@ function showToast(msg, isError) {
1663
1651
  t.style.cssText = 'position:fixed;bottom:20px;right:20px;z-index:9999;padding:8px 14px;border-radius:6px;font-size:11px;font-family:monospace;max-width:320px;pointer-events:none;transition:opacity .3s;' +
1664
1652
  (isError ? 'background:#ef444420;border:1px solid #ef444466;color:#ef4444;' : 'background:#7c3aed20;border:1px solid #7c3aed66;color:#c4b5fd;');
1665
1653
  document.body.appendChild(t);
1666
- setTimeout(function() { t.style.opacity = '0'; setTimeout(function() { t.remove(); }, 300); }, 2500);
1654
+ setTimeout(() => { t.style.opacity = '0'; setTimeout(() => { t.remove(); }, 300); }, 2500);
1667
1655
  }
1668
1656
 
1669
1657
  // ═══════════════════════════════════════════════════════════════════
@@ -1671,7 +1659,7 @@ function showToast(msg, isError) {
1671
1659
  // ═══════════════════════════════════════════════════════════════════
1672
1660
  function handleBuilderEvent(evt) {
1673
1661
  if (!evt.nodeId) return;
1674
- var node = canvas.nodes.find(function(n) { return n.id === evt.nodeId; });
1662
+ var node = canvas.nodes.find((n) => n.id === evt.nodeId);
1675
1663
  if (!node) return;
1676
1664
  if (evt.eventType === 'step_started') {
1677
1665
  node.runStatus = 'running';
@@ -1711,17 +1699,17 @@ function handleEvent(evt) {
1711
1699
  r.status = 'running';
1712
1700
  r.startedAt = evt.timestamp || Date.now();
1713
1701
  } else if (evt.eventType === 'step_started') {
1714
- runLogs[id].push({ ts: t, type: 'info', text: (evt.nodeName || '?') + ' — started' });
1702
+ runLogs[id].push({ ts: t, type: 'info', text: `${evt.nodeName || '?'} — started` });
1715
1703
  } else if (evt.eventType === 'step_completed') {
1716
1704
  r.itemsProcessed = (r.itemsProcessed || 0) + (evt.itemTotal || 1);
1717
- runLogs[id].push({ ts: t, type: 'ok', text: (evt.nodeName || '?') + ' ' + (evt.durationMs ? evt.durationMs + 'ms' : '') });
1705
+ runLogs[id].push({ ts: t, type: 'ok', text: `${evt.nodeName || '?'}${evt.durationMs ? `${evt.durationMs}ms` : ''}` });
1718
1706
  } else if (evt.eventType === 'step_failed') {
1719
- runLogs[id].push({ ts: t, type: 'err', text: (evt.nodeName || '?') + ' ' + (evt.error || '') });
1707
+ runLogs[id].push({ ts: t, type: 'err', text: `${evt.nodeName || '?'}${evt.error || ''}` });
1720
1708
  } else if (evt.eventType === 'run_completed') {
1721
1709
  r.status = 'completed';
1722
1710
  r.endedAt = evt.timestamp || Date.now();
1723
1711
  // Clear running status on nodes
1724
- canvas.nodes.forEach(function(n) {
1712
+ canvas.nodes.forEach((n) => {
1725
1713
  if (n.runStatus === 'running') { n.runStatus = null; }
1726
1714
  });
1727
1715
  } else if (evt.eventType === 'run_failed') {
@@ -1763,9 +1751,9 @@ var _sseRetryDelay = 1000;
1763
1751
  function connectSSE() {
1764
1752
  setConnStatus('connecting');
1765
1753
  var es = new EventSource('/events');
1766
- es.onopen = function() { setConnStatus('live'); _sseRetryDelay = 1000; };
1767
- es.onmessage = function(e) { handleEvent(JSON.parse(e.data)); };
1768
- es.onerror = function() {
1754
+ es.onopen = () => { setConnStatus('live'); _sseRetryDelay = 1000; };
1755
+ es.onmessage = (e) => { handleEvent(JSON.parse(e.data)); };
1756
+ es.onerror = () => {
1769
1757
  setConnStatus('error');
1770
1758
  es.close();
1771
1759
  setTimeout(connectSSE, Math.min(_sseRetryDelay *= 2, 30000));
@@ -1774,12 +1762,12 @@ function connectSSE() {
1774
1762
 
1775
1763
  function connect() {
1776
1764
  setConnStatus('connecting');
1777
- var sock = new WebSocket('ws://' + location.host + '/ws');
1778
- sock.onopen = function() { setConnStatus('live'); };
1779
- sock.onmessage = function(e) {
1765
+ var sock = new WebSocket(`ws://${location.host}/ws`);
1766
+ sock.onopen = () => { setConnStatus('live'); };
1767
+ sock.onmessage = (e) => {
1780
1768
  var msg = JSON.parse(e.data);
1781
1769
  if (msg.type === 'history') {
1782
- msg.runs.forEach(function(r) {
1770
+ msg.runs.forEach((r) => {
1783
1771
  runs[r.id] = r;
1784
1772
  if (!runLogs[r.id]) runLogs[r.id] = [];
1785
1773
  });
@@ -1790,13 +1778,13 @@ function connect() {
1790
1778
  }
1791
1779
  };
1792
1780
  var wsFailedOnce = false;
1793
- sock.onclose = function() {
1781
+ sock.onclose = () => {
1794
1782
  setConnStatus('error');
1795
1783
  if (!wsFailedOnce) {
1796
1784
  wsFailedOnce = true;
1797
- fetch('/events', { method: 'HEAD' }).then(function(r) {
1785
+ fetch('/events', { method: 'HEAD' }).then((r) => {
1798
1786
  if (r.ok) { connectSSE(); } else { setTimeout(connect, 2500); }
1799
- }).catch(function() { setTimeout(connect, 2500); });
1787
+ }).catch(() => { setTimeout(connect, 2500); });
1800
1788
  } else {
1801
1789
  setTimeout(connect, 2500);
1802
1790
  }
@@ -1805,7 +1793,7 @@ function connect() {
1805
1793
 
1806
1794
  // ── init ───────────────────────────────────────────────────
1807
1795
  connect();
1808
- setInterval(function() { if (Object.values(runs).some(function(r){return r.status==='running';})) renderCards(); }, 5000);
1796
+ setInterval(() => { if (Object.values(runs).some((r)=> r.status==='running')) renderCards(); }, 5000);
1809
1797
  </script>
1810
1798
  </body>
1811
1799
  </html>