devharness 0.8.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 (627) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/build/atomic-write.d.ts +28 -0
  4. package/build/atomic-write.d.ts.map +1 -0
  5. package/build/atomic-write.js +126 -0
  6. package/build/atomic-write.js.map +1 -0
  7. package/build/cdp-manager.d.ts +524 -0
  8. package/build/cdp-manager.d.ts.map +1 -0
  9. package/build/cdp-manager.js +1828 -0
  10. package/build/cdp-manager.js.map +1 -0
  11. package/build/cdp-manager.test.d.ts +6 -0
  12. package/build/cdp-manager.test.d.ts.map +1 -0
  13. package/build/cdp-manager.test.js +546 -0
  14. package/build/cdp-manager.test.js.map +1 -0
  15. package/build/chrome-launcher.d.ts +400 -0
  16. package/build/chrome-launcher.d.ts.map +1 -0
  17. package/build/chrome-launcher.js +1071 -0
  18. package/build/chrome-launcher.js.map +1 -0
  19. package/build/chrome-launcher.test.d.ts +11 -0
  20. package/build/chrome-launcher.test.d.ts.map +1 -0
  21. package/build/chrome-launcher.test.js +204 -0
  22. package/build/chrome-launcher.test.js.map +1 -0
  23. package/build/clickable-cache.d.ts +73 -0
  24. package/build/clickable-cache.d.ts.map +1 -0
  25. package/build/clickable-cache.js +90 -0
  26. package/build/clickable-cache.js.map +1 -0
  27. package/build/command-recorder.d.ts +401 -0
  28. package/build/command-recorder.d.ts.map +1 -0
  29. package/build/command-recorder.js +701 -0
  30. package/build/command-recorder.js.map +1 -0
  31. package/build/config.d.ts +390 -0
  32. package/build/config.d.ts.map +1 -0
  33. package/build/config.js +826 -0
  34. package/build/config.js.map +1 -0
  35. package/build/config.test.d.ts +2 -0
  36. package/build/config.test.d.ts.map +1 -0
  37. package/build/config.test.js +112 -0
  38. package/build/config.test.js.map +1 -0
  39. package/build/connection-manager.d.ts +159 -0
  40. package/build/connection-manager.d.ts.map +1 -0
  41. package/build/connection-manager.js +432 -0
  42. package/build/connection-manager.js.map +1 -0
  43. package/build/connection-manager.test.d.ts +11 -0
  44. package/build/connection-manager.test.d.ts.map +1 -0
  45. package/build/connection-manager.test.js +114 -0
  46. package/build/connection-manager.test.js.map +1 -0
  47. package/build/console-monitor.d.ts +150 -0
  48. package/build/console-monitor.d.ts.map +1 -0
  49. package/build/console-monitor.js +454 -0
  50. package/build/console-monitor.js.map +1 -0
  51. package/build/dashboard/bundle.js +1 -0
  52. package/build/dashboard/dashboard-client.d.ts +42 -0
  53. package/build/dashboard/dashboard-client.d.ts.map +1 -0
  54. package/build/dashboard/dashboard-client.js +184 -0
  55. package/build/dashboard/dashboard-client.js.map +1 -0
  56. package/build/dashboard/dashboard-hub.d.ts +50 -0
  57. package/build/dashboard/dashboard-hub.d.ts.map +1 -0
  58. package/build/dashboard/dashboard-hub.js +654 -0
  59. package/build/dashboard/dashboard-hub.js.map +1 -0
  60. package/build/dashboard/hub-lock.d.ts +16 -0
  61. package/build/dashboard/hub-lock.d.ts.map +1 -0
  62. package/build/dashboard/hub-lock.js +77 -0
  63. package/build/dashboard/hub-lock.js.map +1 -0
  64. package/build/dashboard/index.d.ts +25 -0
  65. package/build/dashboard/index.d.ts.map +1 -0
  66. package/build/dashboard/index.js +77 -0
  67. package/build/dashboard/index.js.map +1 -0
  68. package/build/dashboard/types.d.ts +83 -0
  69. package/build/dashboard/types.d.ts.map +1 -0
  70. package/build/dashboard/types.js +6 -0
  71. package/build/dashboard/types.js.map +1 -0
  72. package/build/debug-logger.d.ts +85 -0
  73. package/build/debug-logger.d.ts.map +1 -0
  74. package/build/debug-logger.js +195 -0
  75. package/build/debug-logger.js.map +1 -0
  76. package/build/debugger-aware-wrapper.d.ts +37 -0
  77. package/build/debugger-aware-wrapper.d.ts.map +1 -0
  78. package/build/debugger-aware-wrapper.js +128 -0
  79. package/build/debugger-aware-wrapper.js.map +1 -0
  80. package/build/dom-change-monitor.d.ts +92 -0
  81. package/build/dom-change-monitor.d.ts.map +1 -0
  82. package/build/dom-change-monitor.js +437 -0
  83. package/build/dom-change-monitor.js.map +1 -0
  84. package/build/element-collector.d.ts +16 -0
  85. package/build/element-collector.d.ts.map +1 -0
  86. package/build/element-collector.js +207 -0
  87. package/build/element-collector.js.map +1 -0
  88. package/build/error-helpers.d.ts +43 -0
  89. package/build/error-helpers.d.ts.map +1 -0
  90. package/build/error-helpers.js +143 -0
  91. package/build/error-helpers.js.map +1 -0
  92. package/build/formatters/console-formatter.d.ts +160 -0
  93. package/build/formatters/console-formatter.d.ts.map +1 -0
  94. package/build/formatters/console-formatter.js +338 -0
  95. package/build/formatters/console-formatter.js.map +1 -0
  96. package/build/helpers/parser-plugins.d.ts +44 -0
  97. package/build/helpers/parser-plugins.d.ts.map +1 -0
  98. package/build/helpers/parser-plugins.js +102 -0
  99. package/build/helpers/parser-plugins.js.map +1 -0
  100. package/build/helpers/paths.d.ts +79 -0
  101. package/build/helpers/paths.d.ts.map +1 -0
  102. package/build/helpers/paths.js +168 -0
  103. package/build/helpers/paths.js.map +1 -0
  104. package/build/helpers/process-liveness.d.ts +24 -0
  105. package/build/helpers/process-liveness.d.ts.map +1 -0
  106. package/build/helpers/process-liveness.js +36 -0
  107. package/build/helpers/process-liveness.js.map +1 -0
  108. package/build/helpers/process-liveness.test.d.ts +2 -0
  109. package/build/helpers/process-liveness.test.d.ts.map +1 -0
  110. package/build/helpers/process-liveness.test.js +40 -0
  111. package/build/helpers/process-liveness.test.js.map +1 -0
  112. package/build/helpers/sequence-tree.d.ts +27 -0
  113. package/build/helpers/sequence-tree.d.ts.map +1 -0
  114. package/build/helpers/sequence-tree.js +80 -0
  115. package/build/helpers/sequence-tree.js.map +1 -0
  116. package/build/helpers/sequence-tree.test.d.ts +2 -0
  117. package/build/helpers/sequence-tree.test.d.ts.map +1 -0
  118. package/build/helpers/sequence-tree.test.js +122 -0
  119. package/build/helpers/sequence-tree.test.js.map +1 -0
  120. package/build/index.d.ts +3 -0
  121. package/build/index.d.ts.map +1 -0
  122. package/build/index.js +2007 -0
  123. package/build/index.js.map +1 -0
  124. package/build/interaction-recorder.d.ts +214 -0
  125. package/build/interaction-recorder.d.ts.map +1 -0
  126. package/build/interaction-recorder.js +2007 -0
  127. package/build/interaction-recorder.js.map +1 -0
  128. package/build/issue-tracker.d.ts +107 -0
  129. package/build/issue-tracker.d.ts.map +1 -0
  130. package/build/issue-tracker.js +582 -0
  131. package/build/issue-tracker.js.map +1 -0
  132. package/build/issue-tracker.test.d.ts +2 -0
  133. package/build/issue-tracker.test.d.ts.map +1 -0
  134. package/build/issue-tracker.test.js +88 -0
  135. package/build/issue-tracker.test.js.map +1 -0
  136. package/build/launch-chrome-port.test.d.ts +14 -0
  137. package/build/launch-chrome-port.test.d.ts.map +1 -0
  138. package/build/launch-chrome-port.test.js +97 -0
  139. package/build/launch-chrome-port.test.js.map +1 -0
  140. package/build/log-processor/orchestrator.d.ts +32 -0
  141. package/build/log-processor/orchestrator.d.ts.map +1 -0
  142. package/build/log-processor/orchestrator.js +27 -0
  143. package/build/log-processor/orchestrator.js.map +1 -0
  144. package/build/logpoint-execution-tracker.d.ts +57 -0
  145. package/build/logpoint-execution-tracker.d.ts.map +1 -0
  146. package/build/logpoint-execution-tracker.js +112 -0
  147. package/build/logpoint-execution-tracker.js.map +1 -0
  148. package/build/mcp-supervisor.d.ts +3 -0
  149. package/build/mcp-supervisor.d.ts.map +1 -0
  150. package/build/mcp-supervisor.js +211 -0
  151. package/build/mcp-supervisor.js.map +1 -0
  152. package/build/messages.d.ts +165 -0
  153. package/build/messages.d.ts.map +1 -0
  154. package/build/messages.js +574 -0
  155. package/build/messages.js.map +1 -0
  156. package/build/network-monitor.d.ts +172 -0
  157. package/build/network-monitor.d.ts.map +1 -0
  158. package/build/network-monitor.js +350 -0
  159. package/build/network-monitor.js.map +1 -0
  160. package/build/overlays.d.ts +49 -0
  161. package/build/overlays.d.ts.map +1 -0
  162. package/build/overlays.js +409 -0
  163. package/build/overlays.js.map +1 -0
  164. package/build/persistent-profiles.test.d.ts +15 -0
  165. package/build/persistent-profiles.test.d.ts.map +1 -0
  166. package/build/persistent-profiles.test.js +470 -0
  167. package/build/persistent-profiles.test.js.map +1 -0
  168. package/build/port-reserver.d.ts +32 -0
  169. package/build/port-reserver.d.ts.map +1 -0
  170. package/build/port-reserver.js +118 -0
  171. package/build/port-reserver.js.map +1 -0
  172. package/build/puppeteer-manager.d.ts +47 -0
  173. package/build/puppeteer-manager.d.ts.map +1 -0
  174. package/build/puppeteer-manager.js +116 -0
  175. package/build/puppeteer-manager.js.map +1 -0
  176. package/build/recording-coverage.test.d.ts +12 -0
  177. package/build/recording-coverage.test.d.ts.map +1 -0
  178. package/build/recording-coverage.test.js +72 -0
  179. package/build/recording-coverage.test.js.map +1 -0
  180. package/build/reference-validator.d.ts +47 -0
  181. package/build/reference-validator.d.ts.map +1 -0
  182. package/build/reference-validator.js +86 -0
  183. package/build/reference-validator.js.map +1 -0
  184. package/build/reference-validator.test.d.ts +5 -0
  185. package/build/reference-validator.test.d.ts.map +1 -0
  186. package/build/reference-validator.test.js +243 -0
  187. package/build/reference-validator.test.js.map +1 -0
  188. package/build/replay-cursor.d.ts +27 -0
  189. package/build/replay-cursor.d.ts.map +1 -0
  190. package/build/replay-cursor.js +240 -0
  191. package/build/replay-cursor.js.map +1 -0
  192. package/build/runners/docker-compose-runner.d.ts +69 -0
  193. package/build/runners/docker-compose-runner.d.ts.map +1 -0
  194. package/build/runners/docker-compose-runner.js +438 -0
  195. package/build/runners/docker-compose-runner.js.map +1 -0
  196. package/build/runners/docker-runner.d.ts +65 -0
  197. package/build/runners/docker-runner.d.ts.map +1 -0
  198. package/build/runners/docker-runner.js +414 -0
  199. package/build/runners/docker-runner.js.map +1 -0
  200. package/build/runners/index.d.ts +19 -0
  201. package/build/runners/index.d.ts.map +1 -0
  202. package/build/runners/index.js +35 -0
  203. package/build/runners/index.js.map +1 -0
  204. package/build/runners/native-runner.d.ts +95 -0
  205. package/build/runners/native-runner.d.ts.map +1 -0
  206. package/build/runners/native-runner.js +370 -0
  207. package/build/runners/native-runner.js.map +1 -0
  208. package/build/runners/types.d.ts +147 -0
  209. package/build/runners/types.d.ts.map +1 -0
  210. package/build/runners/types.js +25 -0
  211. package/build/runners/types.js.map +1 -0
  212. package/build/self-restart.d.ts +12 -0
  213. package/build/self-restart.d.ts.map +1 -0
  214. package/build/self-restart.js +41 -0
  215. package/build/self-restart.js.map +1 -0
  216. package/build/self-restart.test.d.ts +2 -0
  217. package/build/self-restart.test.d.ts.map +1 -0
  218. package/build/self-restart.test.js +34 -0
  219. package/build/self-restart.test.js.map +1 -0
  220. package/build/server-claims.d.ts +161 -0
  221. package/build/server-claims.d.ts.map +1 -0
  222. package/build/server-claims.js +382 -0
  223. package/build/server-claims.js.map +1 -0
  224. package/build/server-claims.test.d.ts +2 -0
  225. package/build/server-claims.test.d.ts.map +1 -0
  226. package/build/server-claims.test.js +197 -0
  227. package/build/server-claims.test.js.map +1 -0
  228. package/build/server-manager.d.ts +438 -0
  229. package/build/server-manager.d.ts.map +1 -0
  230. package/build/server-manager.js +1674 -0
  231. package/build/server-manager.js.map +1 -0
  232. package/build/server-manager.test.d.ts +17 -0
  233. package/build/server-manager.test.d.ts.map +1 -0
  234. package/build/server-manager.test.js +122 -0
  235. package/build/server-manager.test.js.map +1 -0
  236. package/build/server-ownership.test.d.ts +2 -0
  237. package/build/server-ownership.test.d.ts.map +1 -0
  238. package/build/server-ownership.test.js +238 -0
  239. package/build/server-ownership.test.js.map +1 -0
  240. package/build/server-watcher.d.ts +21 -0
  241. package/build/server-watcher.d.ts.map +1 -0
  242. package/build/server-watcher.js +105 -0
  243. package/build/server-watcher.js.map +1 -0
  244. package/build/session-detector.d.ts +47 -0
  245. package/build/session-detector.d.ts.map +1 -0
  246. package/build/session-detector.js +229 -0
  247. package/build/session-detector.js.map +1 -0
  248. package/build/session-detector.test.d.ts +9 -0
  249. package/build/session-detector.test.d.ts.map +1 -0
  250. package/build/session-detector.test.js +45 -0
  251. package/build/session-detector.test.js.map +1 -0
  252. package/build/sourcemap-handler.d.ts +114 -0
  253. package/build/sourcemap-handler.d.ts.map +1 -0
  254. package/build/sourcemap-handler.js +479 -0
  255. package/build/sourcemap-handler.js.map +1 -0
  256. package/build/supervisor/child-manager.d.ts +43 -0
  257. package/build/supervisor/child-manager.d.ts.map +1 -0
  258. package/build/supervisor/child-manager.js +148 -0
  259. package/build/supervisor/child-manager.js.map +1 -0
  260. package/build/supervisor/child-manager.test.d.ts +2 -0
  261. package/build/supervisor/child-manager.test.d.ts.map +1 -0
  262. package/build/supervisor/child-manager.test.js +107 -0
  263. package/build/supervisor/child-manager.test.js.map +1 -0
  264. package/build/supervisor/client-watcher.d.ts +48 -0
  265. package/build/supervisor/client-watcher.d.ts.map +1 -0
  266. package/build/supervisor/client-watcher.js +186 -0
  267. package/build/supervisor/client-watcher.js.map +1 -0
  268. package/build/supervisor/client-watcher.test.d.ts +2 -0
  269. package/build/supervisor/client-watcher.test.d.ts.map +1 -0
  270. package/build/supervisor/client-watcher.test.js +121 -0
  271. package/build/supervisor/client-watcher.test.js.map +1 -0
  272. package/build/supervisor/idle-config.d.ts +30 -0
  273. package/build/supervisor/idle-config.d.ts.map +1 -0
  274. package/build/supervisor/idle-config.js +76 -0
  275. package/build/supervisor/idle-config.js.map +1 -0
  276. package/build/supervisor/idle-config.test.d.ts +2 -0
  277. package/build/supervisor/idle-config.test.d.ts.map +1 -0
  278. package/build/supervisor/idle-config.test.js +119 -0
  279. package/build/supervisor/idle-config.test.js.map +1 -0
  280. package/build/supervisor/ndjson-reader.d.ts +47 -0
  281. package/build/supervisor/ndjson-reader.d.ts.map +1 -0
  282. package/build/supervisor/ndjson-reader.js +75 -0
  283. package/build/supervisor/ndjson-reader.js.map +1 -0
  284. package/build/supervisor/ndjson-reader.test.d.ts +2 -0
  285. package/build/supervisor/ndjson-reader.test.d.ts.map +1 -0
  286. package/build/supervisor/ndjson-reader.test.js +92 -0
  287. package/build/supervisor/ndjson-reader.test.js.map +1 -0
  288. package/build/supervisor/pidfile.d.ts +11 -0
  289. package/build/supervisor/pidfile.d.ts.map +1 -0
  290. package/build/supervisor/pidfile.js +29 -0
  291. package/build/supervisor/pidfile.js.map +1 -0
  292. package/build/supervisor/pidfile.test.d.ts +8 -0
  293. package/build/supervisor/pidfile.test.d.ts.map +1 -0
  294. package/build/supervisor/pidfile.test.js +46 -0
  295. package/build/supervisor/pidfile.test.js.map +1 -0
  296. package/build/supervisor/restart-coordinator.d.ts +73 -0
  297. package/build/supervisor/restart-coordinator.d.ts.map +1 -0
  298. package/build/supervisor/restart-coordinator.js +300 -0
  299. package/build/supervisor/restart-coordinator.js.map +1 -0
  300. package/build/supervisor/restart-coordinator.test.d.ts +2 -0
  301. package/build/supervisor/restart-coordinator.test.d.ts.map +1 -0
  302. package/build/supervisor/restart-coordinator.test.js +434 -0
  303. package/build/supervisor/restart-coordinator.test.js.map +1 -0
  304. package/build/test-support/fake-execute-tool-call.d.ts +11 -0
  305. package/build/test-support/fake-execute-tool-call.d.ts.map +1 -0
  306. package/build/test-support/fake-execute-tool-call.js +19 -0
  307. package/build/test-support/fake-execute-tool-call.js.map +1 -0
  308. package/build/tool-error.d.ts +14 -0
  309. package/build/tool-error.d.ts.map +1 -0
  310. package/build/tool-error.js +18 -0
  311. package/build/tool-error.js.map +1 -0
  312. package/build/tool-response.d.ts +293 -0
  313. package/build/tool-response.d.ts.map +1 -0
  314. package/build/tool-response.js +365 -0
  315. package/build/tool-response.js.map +1 -0
  316. package/build/tools/assert-tools.d.ts +62 -0
  317. package/build/tools/assert-tools.d.ts.map +1 -0
  318. package/build/tools/assert-tools.js +330 -0
  319. package/build/tools/assert-tools.js.map +1 -0
  320. package/build/tools/breakpoint-await-abort.test.d.ts +2 -0
  321. package/build/tools/breakpoint-await-abort.test.d.ts.map +1 -0
  322. package/build/tools/breakpoint-await-abort.test.js +124 -0
  323. package/build/tools/breakpoint-await-abort.test.js.map +1 -0
  324. package/build/tools/breakpoint-tools.d.ts +99 -0
  325. package/build/tools/breakpoint-tools.d.ts.map +1 -0
  326. package/build/tools/breakpoint-tools.js +1197 -0
  327. package/build/tools/breakpoint-tools.js.map +1 -0
  328. package/build/tools/config-tools.d.ts +58 -0
  329. package/build/tools/config-tools.d.ts.map +1 -0
  330. package/build/tools/config-tools.js +180 -0
  331. package/build/tools/config-tools.js.map +1 -0
  332. package/build/tools/connection-routing.test.d.ts +12 -0
  333. package/build/tools/connection-routing.test.d.ts.map +1 -0
  334. package/build/tools/connection-routing.test.js +206 -0
  335. package/build/tools/connection-routing.test.js.map +1 -0
  336. package/build/tools/console-tools.d.ts +84 -0
  337. package/build/tools/console-tools.d.ts.map +1 -0
  338. package/build/tools/console-tools.js +241 -0
  339. package/build/tools/console-tools.js.map +1 -0
  340. package/build/tools/content-tools.d.ts +74 -0
  341. package/build/tools/content-tools.d.ts.map +1 -0
  342. package/build/tools/content-tools.js +582 -0
  343. package/build/tools/content-tools.js.map +1 -0
  344. package/build/tools/dashboard-tools.d.ts +38 -0
  345. package/build/tools/dashboard-tools.d.ts.map +1 -0
  346. package/build/tools/dashboard-tools.js +123 -0
  347. package/build/tools/dashboard-tools.js.map +1 -0
  348. package/build/tools/dom-tools.d.ts +41 -0
  349. package/build/tools/dom-tools.d.ts.map +1 -0
  350. package/build/tools/dom-tools.js +277 -0
  351. package/build/tools/dom-tools.js.map +1 -0
  352. package/build/tools/download-tools.d.ts +55 -0
  353. package/build/tools/download-tools.d.ts.map +1 -0
  354. package/build/tools/download-tools.js +280 -0
  355. package/build/tools/download-tools.js.map +1 -0
  356. package/build/tools/execution-tools.d.ts +40 -0
  357. package/build/tools/execution-tools.d.ts.map +1 -0
  358. package/build/tools/execution-tools.js +121 -0
  359. package/build/tools/execution-tools.js.map +1 -0
  360. package/build/tools/input-abort.test.d.ts +2 -0
  361. package/build/tools/input-abort.test.d.ts.map +1 -0
  362. package/build/tools/input-abort.test.js +227 -0
  363. package/build/tools/input-abort.test.js.map +1 -0
  364. package/build/tools/input-ambiguous-selector.test.d.ts +2 -0
  365. package/build/tools/input-ambiguous-selector.test.d.ts.map +1 -0
  366. package/build/tools/input-ambiguous-selector.test.js +34 -0
  367. package/build/tools/input-ambiguous-selector.test.js.map +1 -0
  368. package/build/tools/input-tools.d.ts +168 -0
  369. package/build/tools/input-tools.d.ts.map +1 -0
  370. package/build/tools/input-tools.js +1397 -0
  371. package/build/tools/input-tools.js.map +1 -0
  372. package/build/tools/inspection-tools.d.ts +112 -0
  373. package/build/tools/inspection-tools.d.ts.map +1 -0
  374. package/build/tools/inspection-tools.js +637 -0
  375. package/build/tools/inspection-tools.js.map +1 -0
  376. package/build/tools/interpolation.d.ts +30 -0
  377. package/build/tools/interpolation.d.ts.map +1 -0
  378. package/build/tools/interpolation.js +143 -0
  379. package/build/tools/interpolation.js.map +1 -0
  380. package/build/tools/issues-abort-hygiene.test.d.ts +2 -0
  381. package/build/tools/issues-abort-hygiene.test.d.ts.map +1 -0
  382. package/build/tools/issues-abort-hygiene.test.js +79 -0
  383. package/build/tools/issues-abort-hygiene.test.js.map +1 -0
  384. package/build/tools/issues-tools.d.ts +98 -0
  385. package/build/tools/issues-tools.d.ts.map +1 -0
  386. package/build/tools/issues-tools.js +821 -0
  387. package/build/tools/issues-tools.js.map +1 -0
  388. package/build/tools/issues-tools.test.d.ts +8 -0
  389. package/build/tools/issues-tools.test.d.ts.map +1 -0
  390. package/build/tools/issues-tools.test.js +184 -0
  391. package/build/tools/issues-tools.test.js.map +1 -0
  392. package/build/tools/modal-tools.d.ts +73 -0
  393. package/build/tools/modal-tools.d.ts.map +1 -0
  394. package/build/tools/modal-tools.js +161 -0
  395. package/build/tools/modal-tools.js.map +1 -0
  396. package/build/tools/network-tools.d.ts +72 -0
  397. package/build/tools/network-tools.d.ts.map +1 -0
  398. package/build/tools/network-tools.js +432 -0
  399. package/build/tools/network-tools.js.map +1 -0
  400. package/build/tools/page-tools.d.ts +78 -0
  401. package/build/tools/page-tools.d.ts.map +1 -0
  402. package/build/tools/page-tools.js +255 -0
  403. package/build/tools/page-tools.js.map +1 -0
  404. package/build/tools/plugin-tools.d.ts +16 -0
  405. package/build/tools/plugin-tools.d.ts.map +1 -0
  406. package/build/tools/plugin-tools.js +17 -0
  407. package/build/tools/plugin-tools.js.map +1 -0
  408. package/build/tools/replay-abort.test.d.ts +2 -0
  409. package/build/tools/replay-abort.test.d.ts.map +1 -0
  410. package/build/tools/replay-abort.test.js +259 -0
  411. package/build/tools/replay-abort.test.js.map +1 -0
  412. package/build/tools/replay-add-conditional.test.d.ts +2 -0
  413. package/build/tools/replay-add-conditional.test.d.ts.map +1 -0
  414. package/build/tools/replay-add-conditional.test.js +205 -0
  415. package/build/tools/replay-add-conditional.test.js.map +1 -0
  416. package/build/tools/replay-background-run.test.d.ts +2 -0
  417. package/build/tools/replay-background-run.test.d.ts.map +1 -0
  418. package/build/tools/replay-background-run.test.js +176 -0
  419. package/build/tools/replay-background-run.test.js.map +1 -0
  420. package/build/tools/replay-capture-variables.test.d.ts +2 -0
  421. package/build/tools/replay-capture-variables.test.d.ts.map +1 -0
  422. package/build/tools/replay-capture-variables.test.js +331 -0
  423. package/build/tools/replay-capture-variables.test.js.map +1 -0
  424. package/build/tools/replay-conditional-idb-and-launch.test.d.ts +11 -0
  425. package/build/tools/replay-conditional-idb-and-launch.test.d.ts.map +1 -0
  426. package/build/tools/replay-conditional-idb-and-launch.test.js +429 -0
  427. package/build/tools/replay-conditional-idb-and-launch.test.js.map +1 -0
  428. package/build/tools/replay-conditional-timeout.test.d.ts +14 -0
  429. package/build/tools/replay-conditional-timeout.test.d.ts.map +1 -0
  430. package/build/tools/replay-conditional-timeout.test.js +126 -0
  431. package/build/tools/replay-conditional-timeout.test.js.map +1 -0
  432. package/build/tools/replay-declare.test.d.ts +2 -0
  433. package/build/tools/replay-declare.test.d.ts.map +1 -0
  434. package/build/tools/replay-declare.test.js +106 -0
  435. package/build/tools/replay-declare.test.js.map +1 -0
  436. package/build/tools/replay-declared-browser-cleanup.test.d.ts +2 -0
  437. package/build/tools/replay-declared-browser-cleanup.test.d.ts.map +1 -0
  438. package/build/tools/replay-declared-browser-cleanup.test.js +103 -0
  439. package/build/tools/replay-declared-browser-cleanup.test.js.map +1 -0
  440. package/build/tools/replay-declared-profile.test.d.ts +2 -0
  441. package/build/tools/replay-declared-profile.test.d.ts.map +1 -0
  442. package/build/tools/replay-declared-profile.test.js +116 -0
  443. package/build/tools/replay-declared-profile.test.js.map +1 -0
  444. package/build/tools/replay-executor.d.ts +556 -0
  445. package/build/tools/replay-executor.d.ts.map +1 -0
  446. package/build/tools/replay-executor.js +2347 -0
  447. package/build/tools/replay-executor.js.map +1 -0
  448. package/build/tools/replay-folder-save.test.d.ts +2 -0
  449. package/build/tools/replay-folder-save.test.d.ts.map +1 -0
  450. package/build/tools/replay-folder-save.test.js +63 -0
  451. package/build/tools/replay-folder-save.test.js.map +1 -0
  452. package/build/tools/replay-formatters.d.ts +148 -0
  453. package/build/tools/replay-formatters.d.ts.map +1 -0
  454. package/build/tools/replay-formatters.js +856 -0
  455. package/build/tools/replay-formatters.js.map +1 -0
  456. package/build/tools/replay-kill-chrome-on-finish.test.d.ts +2 -0
  457. package/build/tools/replay-kill-chrome-on-finish.test.d.ts.map +1 -0
  458. package/build/tools/replay-kill-chrome-on-finish.test.js +175 -0
  459. package/build/tools/replay-kill-chrome-on-finish.test.js.map +1 -0
  460. package/build/tools/replay-multi-connection.test.d.ts +2 -0
  461. package/build/tools/replay-multi-connection.test.d.ts.map +1 -0
  462. package/build/tools/replay-multi-connection.test.js +547 -0
  463. package/build/tools/replay-multi-connection.test.js.map +1 -0
  464. package/build/tools/replay-output-and-record-options.test.d.ts +2 -0
  465. package/build/tools/replay-output-and-record-options.test.d.ts.map +1 -0
  466. package/build/tools/replay-output-and-record-options.test.js +240 -0
  467. package/build/tools/replay-output-and-record-options.test.js.map +1 -0
  468. package/build/tools/replay-production-error-shape.test.d.ts +7 -0
  469. package/build/tools/replay-production-error-shape.test.d.ts.map +1 -0
  470. package/build/tools/replay-production-error-shape.test.js +93 -0
  471. package/build/tools/replay-production-error-shape.test.js.map +1 -0
  472. package/build/tools/replay-rebase.test.d.ts +2 -0
  473. package/build/tools/replay-rebase.test.d.ts.map +1 -0
  474. package/build/tools/replay-rebase.test.js +58 -0
  475. package/build/tools/replay-rebase.test.js.map +1 -0
  476. package/build/tools/replay-retry-classification.test.d.ts +9 -0
  477. package/build/tools/replay-retry-classification.test.d.ts.map +1 -0
  478. package/build/tools/replay-retry-classification.test.js +57 -0
  479. package/build/tools/replay-retry-classification.test.js.map +1 -0
  480. package/build/tools/replay-run-registry.d.ts +55 -0
  481. package/build/tools/replay-run-registry.d.ts.map +1 -0
  482. package/build/tools/replay-run-registry.js +65 -0
  483. package/build/tools/replay-run-registry.js.map +1 -0
  484. package/build/tools/replay-sequence-reload.test.d.ts +2 -0
  485. package/build/tools/replay-sequence-reload.test.d.ts.map +1 -0
  486. package/build/tools/replay-sequence-reload.test.js +82 -0
  487. package/build/tools/replay-sequence-reload.test.js.map +1 -0
  488. package/build/tools/replay-socket-scope.test.d.ts +2 -0
  489. package/build/tools/replay-socket-scope.test.d.ts.map +1 -0
  490. package/build/tools/replay-socket-scope.test.js +75 -0
  491. package/build/tools/replay-socket-scope.test.js.map +1 -0
  492. package/build/tools/replay-step-connection.test.d.ts +2 -0
  493. package/build/tools/replay-step-connection.test.d.ts.map +1 -0
  494. package/build/tools/replay-step-connection.test.js +292 -0
  495. package/build/tools/replay-step-connection.test.js.map +1 -0
  496. package/build/tools/replay-step-timeout.test.d.ts +2 -0
  497. package/build/tools/replay-step-timeout.test.d.ts.map +1 -0
  498. package/build/tools/replay-step-timeout.test.js +204 -0
  499. package/build/tools/replay-step-timeout.test.js.map +1 -0
  500. package/build/tools/replay-tags.test.d.ts +2 -0
  501. package/build/tools/replay-tags.test.d.ts.map +1 -0
  502. package/build/tools/replay-tags.test.js +99 -0
  503. package/build/tools/replay-tags.test.js.map +1 -0
  504. package/build/tools/replay-teardown-and-foreach.test.d.ts +13 -0
  505. package/build/tools/replay-teardown-and-foreach.test.d.ts.map +1 -0
  506. package/build/tools/replay-teardown-and-foreach.test.js +318 -0
  507. package/build/tools/replay-teardown-and-foreach.test.js.map +1 -0
  508. package/build/tools/replay-tool-name-validation.test.d.ts +2 -0
  509. package/build/tools/replay-tool-name-validation.test.d.ts.map +1 -0
  510. package/build/tools/replay-tool-name-validation.test.js +280 -0
  511. package/build/tools/replay-tool-name-validation.test.js.map +1 -0
  512. package/build/tools/replay-tools.d.ts +288 -0
  513. package/build/tools/replay-tools.d.ts.map +1 -0
  514. package/build/tools/replay-tools.js +2994 -0
  515. package/build/tools/replay-tools.js.map +1 -0
  516. package/build/tools/request-abort.test.d.ts +2 -0
  517. package/build/tools/request-abort.test.d.ts.map +1 -0
  518. package/build/tools/request-abort.test.js +130 -0
  519. package/build/tools/request-abort.test.js.map +1 -0
  520. package/build/tools/request-tools.d.ts +56 -0
  521. package/build/tools/request-tools.d.ts.map +1 -0
  522. package/build/tools/request-tools.js +174 -0
  523. package/build/tools/request-tools.js.map +1 -0
  524. package/build/tools/screenshot-tools.d.ts +135 -0
  525. package/build/tools/screenshot-tools.d.ts.map +1 -0
  526. package/build/tools/screenshot-tools.js +636 -0
  527. package/build/tools/screenshot-tools.js.map +1 -0
  528. package/build/tools/server-tools.d.ts +88 -0
  529. package/build/tools/server-tools.d.ts.map +1 -0
  530. package/build/tools/server-tools.js +485 -0
  531. package/build/tools/server-tools.js.map +1 -0
  532. package/build/tools/source-tools.d.ts +46 -0
  533. package/build/tools/source-tools.d.ts.map +1 -0
  534. package/build/tools/source-tools.js +47 -0
  535. package/build/tools/source-tools.js.map +1 -0
  536. package/build/tools/storage-tools.d.ts +141 -0
  537. package/build/tools/storage-tools.d.ts.map +1 -0
  538. package/build/tools/storage-tools.js +894 -0
  539. package/build/tools/storage-tools.js.map +1 -0
  540. package/build/tools/storage-tools.test.d.ts +13 -0
  541. package/build/tools/storage-tools.test.d.ts.map +1 -0
  542. package/build/tools/storage-tools.test.js +707 -0
  543. package/build/tools/storage-tools.test.js.map +1 -0
  544. package/build/tools/tab-tools.d.ts +42 -0
  545. package/build/tools/tab-tools.d.ts.map +1 -0
  546. package/build/tools/tab-tools.js +296 -0
  547. package/build/tools/tab-tools.js.map +1 -0
  548. package/build/tools/wait-tools.d.ts +85 -0
  549. package/build/tools/wait-tools.d.ts.map +1 -0
  550. package/build/tools/wait-tools.js +236 -0
  551. package/build/tools/wait-tools.js.map +1 -0
  552. package/build/tools/wait-tools.test.d.ts +9 -0
  553. package/build/tools/wait-tools.test.d.ts.map +1 -0
  554. package/build/tools/wait-tools.test.js +193 -0
  555. package/build/tools/wait-tools.test.js.map +1 -0
  556. package/build/types.d.ts +133 -0
  557. package/build/types.d.ts.map +1 -0
  558. package/build/types.js +5 -0
  559. package/build/types.js.map +1 -0
  560. package/build/ui-verifier.d.ts +88 -0
  561. package/build/ui-verifier.d.ts.map +1 -0
  562. package/build/ui-verifier.js +540 -0
  563. package/build/ui-verifier.js.map +1 -0
  564. package/build/utils/abort.d.ts +68 -0
  565. package/build/utils/abort.d.ts.map +1 -0
  566. package/build/utils/abort.js +159 -0
  567. package/build/utils/abort.js.map +1 -0
  568. package/build/utils/abort.test.d.ts +2 -0
  569. package/build/utils/abort.test.d.ts.map +1 -0
  570. package/build/utils/abort.test.js +174 -0
  571. package/build/utils/abort.test.js.map +1 -0
  572. package/build/utils/modal-detection-core.d.ts +150 -0
  573. package/build/utils/modal-detection-core.d.ts.map +1 -0
  574. package/build/utils/modal-detection-core.js +332 -0
  575. package/build/utils/modal-detection-core.js.map +1 -0
  576. package/build/utils/modal-detection-core.test.d.ts +5 -0
  577. package/build/utils/modal-detection-core.test.d.ts.map +1 -0
  578. package/build/utils/modal-detection-core.test.js +492 -0
  579. package/build/utils/modal-detection-core.test.js.map +1 -0
  580. package/build/utils/modal-detector.d.ts +29 -0
  581. package/build/utils/modal-detector.d.ts.map +1 -0
  582. package/build/utils/modal-detector.js +281 -0
  583. package/build/utils/modal-detector.js.map +1 -0
  584. package/build/utils/modal-dismissal.d.ts +32 -0
  585. package/build/utils/modal-dismissal.d.ts.map +1 -0
  586. package/build/utils/modal-dismissal.js +190 -0
  587. package/build/utils/modal-dismissal.js.map +1 -0
  588. package/build/utils/port-check.d.ts +31 -0
  589. package/build/utils/port-check.d.ts.map +1 -0
  590. package/build/utils/port-check.js +87 -0
  591. package/build/utils/port-check.js.map +1 -0
  592. package/build/utils/port-check.test.d.ts +2 -0
  593. package/build/utils/port-check.test.d.ts.map +1 -0
  594. package/build/utils/port-check.test.js +66 -0
  595. package/build/utils/port-check.test.js.map +1 -0
  596. package/build/utils/selector-resolver.d.ts +66 -0
  597. package/build/utils/selector-resolver.d.ts.map +1 -0
  598. package/build/utils/selector-resolver.js +200 -0
  599. package/build/utils/selector-resolver.js.map +1 -0
  600. package/build/validation-helpers.d.ts +41 -0
  601. package/build/validation-helpers.d.ts.map +1 -0
  602. package/build/validation-helpers.js +236 -0
  603. package/build/validation-helpers.js.map +1 -0
  604. package/build/window-sizing.d.ts +26 -0
  605. package/build/window-sizing.d.ts.map +1 -0
  606. package/build/window-sizing.js +87 -0
  607. package/build/window-sizing.js.map +1 -0
  608. package/build/window-sizing.test.d.ts +8 -0
  609. package/build/window-sizing.test.d.ts.map +1 -0
  610. package/build/window-sizing.test.js +113 -0
  611. package/build/window-sizing.test.js.map +1 -0
  612. package/docs/README.md +74 -0
  613. package/docs/automation.md +562 -0
  614. package/docs/debugging.md +229 -0
  615. package/docs/installation.md +133 -0
  616. package/docs/instructions.md +227 -0
  617. package/docs/mcp-instructions.md +15 -0
  618. package/docs/message-system.md +327 -0
  619. package/docs/messages.md +3480 -0
  620. package/docs/parser-plugins.md +132 -0
  621. package/docs/replay.md +1411 -0
  622. package/docs/troubleshooting.md +272 -0
  623. package/docs/working_with_llm_notes.md +5 -0
  624. package/package.json +87 -0
  625. package/skills/devharness/SKILL.md +195 -0
  626. package/skills/devharness/references/sequences.md +613 -0
  627. package/skills/devharness/references/tool-categories.md +99 -0
@@ -0,0 +1,613 @@
1
+ # Replay Sequences
2
+
3
+ A sequence is an ordered list of tool calls you can re-run. It's how cdp-tools
4
+ turns "I clicked around and hit the bug" into something repeatable - a
5
+ regression test, a repro attached to an issue, or a multi-step automation.
6
+
7
+ Everything below is the `replay` tool: `replay({ action: '...' })`.
8
+
9
+ ## Folders
10
+
11
+ Sequences may live in subfolders of the sequences dir:
12
+
13
+ ```
14
+ .cdp-tools/sequences/
15
+ _helpers/ preamble guards, forEach bodies - loaded, never run on their own
16
+ spine/
17
+ story/
18
+ ```
19
+
20
+ Filenames are relative to that root (`spine/spine-01.json`), and `load` still
21
+ accepts the bare basename, so moving a file into a folder does not break calls
22
+ that name it.
23
+
24
+ `replay({ action: 'runAll', folder: 'spine' })` loads the WHOLE tree, then runs
25
+ only that folder. Loading everything matters: `conditional`'s `then` and
26
+ `forEach`'s `do` resolve by sequence NAME, not by path, so a spine sequence can
27
+ call a helper in `_helpers/` only if that helper was loaded too.
28
+
29
+ **Tags are the other axis.** `replay({ action: 'declare', name: '...', tags:
30
+ ['ui'] })` labels a sequence; `replay({ action: 'runAll', tags: ['ui'] })` runs
31
+ only those, and composes with `folder`. Several tags mean *any of*. Tags are
32
+ lowercased and de-duplicated (a tag is matched, not displayed) and may not
33
+ contain spaces.
34
+
35
+ Every `runAll` reports the split whether or not you filtered - `3 passed (1
36
+ contract, 1 ui, 1 untagged)`. That is the point: a suite reporting "36 passed"
37
+ reads as interface coverage even when a third of it never issues an `input`
38
+ step, and folders cannot carry the distinction because they already carry
39
+ scenario shape.
40
+
41
+ A folder whose name starts with `_` is skipped by a bare `runAll` - those
42
+ sequences fail in isolation by design (unbound `{{var:}}`, an unmet
43
+ precondition). Naming one explicitly runs it anyway.
44
+
45
+ Failures are recorded and the suite continues unless `continueOnFailure: false`.
46
+ A sequence that only PROMPTS (recorded variables, none supplied) or that PAUSES
47
+ is reported as a failure, not a pass - it did not run.
48
+
49
+ ## Rules for building one
50
+
51
+ These hold however you build a sequence - by hand, as a subagent, or from a
52
+ slash command. They are here, once, rather than restated by each of those.
53
+
54
+ - **Never hand-write sequence JSON.** Sequences come from recorded tool calls.
55
+ Hand-edited JSON skips the validation the tools apply and does not port.
56
+ The things that cannot be recorded have their own actions rather than being
57
+ an exception to this: `addConditional` for a guarded branch, `declare` for
58
+ the browsers and sockets a sequence needs.
59
+ - **Do the work with the tools; don't describe it.** Every call you make is
60
+ recorded, and the sequence is assembled from that history afterwards.
61
+ - **Pass `connectionReason` on every browser call** - including the connection
62
+ that is already active, and including tools where it is optional (`inspect`,
63
+ `execution`, `storage`, `network`, `breakpoint`, `request`). A call without it
64
+ records nothing about which browser it ran in, so on replay it lands wherever
65
+ the run-level connection points - silently, and the run still passes. This is
66
+ the most common way to produce a sequence that tests nothing.
67
+ - **Check `listSaved` first.** Auth and setup flows often already exist; a
68
+ `conditional` step can reuse one instead of re-recording it.
69
+ - **Keep the path minimal.** Skip exploratory calls (source searches, unrelated
70
+ navigation); include only what is needed to reproduce.
71
+ - **Write a specific `expectedOutcome`** - file:line, variable names, expected
72
+ vs actual values. "It works" is not an expected outcome.
73
+
74
+ ## Getting a sequence
75
+
76
+ **Record what a human does** - `recordInteraction`
77
+
78
+ ```
79
+ replay({ action: 'recordInteraction', connectionReason: 'signup-flow' })
80
+ ```
81
+
82
+ Opens the page with a recording overlay and captures real mouse, keyboard and
83
+ navigation events. **This call blocks until the person finishes in the
84
+ browser** - there is no separate stop action. It returns the created sequence.
85
+ Pass `issueId` to name and link the recording to an issue (`bug-7-repro`).
86
+
87
+ Because it waits on a human, don't call it unattended - the same rule as
88
+ `issues({ action: 'resolve' })`.
89
+
90
+ Tune how events become commands with `simplifyEvents` (default true),
91
+ `includeHovers` (false), `preferCoordinates` (false - `x,y` clicks for
92
+ canvas/3D) and `preferSelectors` (false - selector clicks even for canvas;
93
+ wins if both preference flags are set). Add `outputFormat: 'events'` or
94
+ `'commands'` to get the raw captured events / converted commands as JSON
95
+ alongside the summary, or `'review'` for a readable walkthrough of the captured
96
+ events (coordinates, element and selector per interaction, plus navigations,
97
+ pastes and comments). All three are only available here - raw events are not
98
+ stored with the sequence.
99
+
100
+ **Build one from calls you already made** - `create`
101
+
102
+ ```
103
+ replay({ action: 'create', name: 'login-check', indices: [3, 4, 5] })
104
+ ```
105
+
106
+ Every tool response footer shows its history index (`**Repeat:**` hint).
107
+ `replay({ action: 'history' })` lists them. This is usually faster than
108
+ recording when you've just done the steps yourself.
109
+
110
+ **Re-run calls you already made, without building a sequence** - `repeat`
111
+
112
+ ```
113
+ replay({ action: 'repeat', indices: [12] }) // one call
114
+ replay({ action: 'repeat', indices: [58, 59, 60, 61] }) // a whole stretch, in order
115
+ ```
116
+
117
+ `indices` takes a list, so this replays a run of work in one call - and that is
118
+ usually the point. Whenever you are about to redo something you already did
119
+ (relaunch the browser, log in again, retype a form, get back to the screen
120
+ where the bug shows), repeat those indices instead of re-issuing the calls by
121
+ hand: it is faster, and retyped arguments drift from what actually ran.
122
+
123
+ Every tool response carries its own index in the footer, so the numbers are
124
+ already in front of you. `replay({ action: 'history' })` lists them when they
125
+ have scrolled away. If the stretch turns out to be worth keeping, hand the same
126
+ indices to `create`.
127
+
128
+ ## Managing them
129
+
130
+ - `list` / `get` / `delete` - sequences in memory. `get` takes
131
+ `outputFormat: 'commands' | 'playwright' | 'puppeteer'` to return the raw
132
+ command JSON or generated test code instead of the detail view (`'events'`
133
+ and `'review'` are recordInteraction-only - a stored sequence has no raw
134
+ events, and `get` says so rather than ignoring them)
135
+ - `load` / `listSaved` / `deleteSaved` - sequences on disk
136
+ - `export` - write to a file as `sequence`, `playwright`, or `puppeteer`
137
+ - `global: true` on `export` saves to `~/.cdp-tools/sequences/` instead of the
138
+ working directory
139
+
140
+ `load` and `create` reject a sequence naming a tool that doesn't exist, listing
141
+ the offending step, rather than failing halfway through a run after earlier
142
+ steps already changed state.
143
+
144
+ **Editing a sequence file mid-session just works.** The sequences directories
145
+ are watched like a managed dev server's sources, and a run re-checks the file's
146
+ timestamp anyway - so the version you just saved is the version that runs. No
147
+ `load` needed to pick up an edit. A file caught mid-write leaves the loaded copy
148
+ in place rather than replacing a good sequence with a half-saved one, and a
149
+ sequence built from history has no file to reload from.
150
+
151
+ ## Running
152
+
153
+ ```
154
+ replay({ action: 'run', sequenceId: 'seq-login', connectionReason: 'my-app' })
155
+ ```
156
+
157
+ **`run` does not block** (changed in 0.7): it returns a run id immediately and
158
+ executes in the background.
159
+
160
+ ```
161
+ replay({ action: 'status', runId: 'run-3-...' }) // progress; full result once settled
162
+ replay({ action: 'cancel', runId: 'run-3-...' }) // stop it
163
+ ```
164
+
165
+ `cancel` reaches the step that is in flight (including inside nested
166
+ `conditional` sequences), but what it can do there differs by tool - three
167
+ levels, and the difference matters:
168
+
169
+ - **Genuinely cancelled:** `wait` (all forms, mid-poll) and `request` with
170
+ `destination: 'node'` (the socket is closed - the server sees it aborted).
171
+ - **Stops waiting, work continues:** `navigate` (deliberately no
172
+ `Page.stopLoading` - a half-loaded page is worse than a loaded one),
173
+ `inspect({ action: 'evaluateExpression' })`, `content({ action: 'parse' })`.
174
+ - **Checkpoint only:** `input` - an input event on the wire cannot be
175
+ recalled, so cancelling stops events that had not gone out yet and undoes
176
+ nothing already dispatched (a cancelled drag does still release the button).
177
+ Same for `request` with `destination: 'browser'`, `screenshot`, and the
178
+ non-waiting `content`/`inspect` actions.
179
+
180
+ `breakpoint({ action: 'await' })` is cancellable and now **fails** the step
181
+ (it used to report success). `dom`, `network` and everything else have no real
182
+ wait to interrupt, so they stop at the next step boundary. In every case, work
183
+ already dispatched to the browser may still take effect. Full table:
184
+ `docs/replay.md`.
185
+
186
+ Several runs can execute concurrently - even of the same sequence - and the
187
+ run id is what tells them apart. Settled runs and their results are kept in
188
+ memory for 30 minutes (max 50); after that, or after a server restart (which
189
+ kills in-flight runs), the id returns `REPLAY_RUN_NOT_FOUND`. Nested sequences
190
+ (`conditional` flows, `replay run` steps) are part of their parent run, never
191
+ separate runs. Pass `wait: true` to block until completion and get the full
192
+ result in one call (the pre-0.7 behaviour).
193
+
194
+ Useful `run` parameters:
195
+
196
+ - `startUrl` - override the stored start URL for this run only (e.g. a
197
+ freshly minted magic link)
198
+ - `baseUrl` - retarget every absolute URL at another origin, keeping paths and
199
+ queries. Point a staging-recorded sequence at local
200
+ - `startFrom` - begin at step N (1-indexed)
201
+ - `stepTimeout` / `totalTimeout` - each step is bounded by
202
+ `min(stepTimeout, remaining totalTimeout)` (defaults 30s / 5min); a step that
203
+ exceeds it fails the run at that step. `wait` steps are exempt from
204
+ `stepTimeout` (they have their own `timeoutMs`) but still capped by
205
+ `totalTimeout`
206
+ - `variables` - substitute recorded typed text (see below)
207
+ - `killChromeOnFinish` - tears down the browsers this run OWNS: its own
208
+ run-level connection, plus any browser a `launchChrome` step actually
209
+ created. A step that reached an already-bound reference only borrowed that
210
+ browser, so it is left running and a sequence can read from a long-lived
211
+ instance you launched yourself without it being killed underneath you.
212
+ Skipped for any browser whose port another live connection shares (a
213
+ `launchChrome` step usually opens a tab in the same instance) - the run says
214
+ which connection kept it alive
215
+
216
+ Step through interactively with `step`, `finish`, `insert`, `status`, `cancel`
217
+ (`run` with `stepTo: N` pauses after step N; the run's status becomes `paused`
218
+ and you drive it from there). A bare `cancel` prefers the paused session;
219
+ use `runId` to address a specific background run.
220
+
221
+ ## Two different "variables" - don't confuse them
222
+
223
+ **1. `variables` on `run` replaces recorded typed text.** Keyed by the recorded
224
+ input, for replaying a signup with a fresh email:
225
+
226
+ ```
227
+ replay({ action: 'run', sequenceId: 'seq-signup',
228
+ variables: { 'var_2_#email': 'new@example.com' } })
229
+ ```
230
+
231
+ **2. `saveAs` captures a value mid-run for later steps.** Supported on
232
+ `request` and on `inspect({ action: 'evaluateExpression' })`. Later steps read
233
+ it with `{{var:name}}` or `{{var:name.path}}`:
234
+
235
+ ```
236
+ request({ url: '...', saveAs: 'login' }) // stores the whole response
237
+ inspect({ action: 'evaluateExpression',
238
+ expression: 'document.querySelector("#pair").href',
239
+ saveAs: 'pairingUrl' }) // stores the value itself
240
+ navigate({ action: 'goto', url: '{{var:pairingUrl}}' })
241
+ assert({ left: '{{var:login.body.token}}', operator: 'exists' })
242
+ ```
243
+
244
+ Note the asymmetry: `request` stores the response object (so you index into
245
+ `.body`), `inspect` stores the evaluated value directly. A `saveAs` that can't
246
+ be honoured fails the step rather than silently capturing nothing.
247
+
248
+ Values that only render as a description (`[HTMLDivElement]`, `Array(3)`) come
249
+ back as strings - capture a specific field rather than a whole DOM object.
250
+
251
+ ## Waiting for async work
252
+
253
+ Recording by hand hides races: driving tools interactively puts seconds
254
+ between calls, so async work always looks settled. Replayed back-to-back, a
255
+ step after a navigation or an async kick-off reads state that isn't there
256
+ yet. `wait` is the sequence step for that:
257
+
258
+ ```
259
+ { tool: 'wait', params: { selector: 'button:has-text("Join")' } } // appears
260
+ { tool: 'wait', params: { selectorGone: '.spinner' } } // disappears
261
+ { tool: 'wait', params: { expression: 'window.__probe !== "PENDING"' } }
262
+ { tool: 'wait', params: { ms: 500 } } // last resort
263
+ ```
264
+
265
+ Exactly one form per step. Condition forms poll a **synchronous** check from
266
+ the MCP side (default: every 100ms, up to `timeoutMs` 15000), so they survive
267
+ a navigation mid-wait and don't depend on in-page timers or promises. On
268
+ timeout the step fails and stops the run - a `wait` never hangs. For async
269
+ in-page work, kick it off in one step, store the result in a global, then
270
+ `wait({ expression: 'window.__result !== undefined' })` and read it with
271
+ `inspect` + `saveAs`.
272
+
273
+ Historical note: sequences in the wild use a marker-div + hover-on-
274
+ `:has-text()` idiom (an `input({ action: 'hover' })` on an element that only
275
+ exists once async work settles). That was never stylistic - hover's short
276
+ implicit element-wait was the *only* step that waited at all before `wait`
277
+ existed. Don't copy the pattern into new sequences; use `wait` and `assert`.
278
+
279
+ ## Multi-device / multi-browser sequences
280
+
281
+ Any step may carry its own `connectionReason`, and it is honoured for
282
+ validation and pause handling, not just dispatch. That's what makes
283
+ "device A scans, device B confirms" sequences work in one run:
284
+
285
+ ```
286
+ { tool: 'input', params: { action: 'click', selector: '#pair',
287
+ connectionReason: 'device-a' } }
288
+ { tool: 'inspect', params: { action: 'evaluateExpression',
289
+ expression: '...', saveAs: 'code',
290
+ connectionReason: 'device-a' } }
291
+ { tool: 'navigate', params: { action: 'goto', url: '{{var:code}}',
292
+ connectionReason: 'device-b' } }
293
+ ```
294
+
295
+ Steps without an explicit `connectionReason` use the run-level one.
296
+
297
+ **Recording one.** Pass `connectionReason` explicitly on **every** call while you
298
+ drive the browsers - including the one that happens to be active. Recording
299
+ preserves it, and `create` decides what to do with it:
300
+
301
+ - all steps on one connection - hoisted off the steps, so the sequence stays
302
+ portable and `run({ connectionReason })` still retargets it
303
+ - genuinely spanning connections - kept per step
304
+ - **mixed** (some steps named, some driven implicitly through the active
305
+ connection) - kept as-is with a warning, because nothing can tell which
306
+ browser the bare steps belonged to. `create` says so; re-record naming every
307
+ step rather than shipping it
308
+
309
+ "Bare" covers the tools whose `connectionReason` is *optional* (`inspect`,
310
+ `execution`, `storage`, `network`, `breakpoint`, `request`), not just the
311
+ browser-only ones - those are the ones actually left off. A sequence can be both
312
+ multi-connection and mixed, and that is the worst case: the bare steps land in a
313
+ different browser depending on the run-level `connectionReason`, green either
314
+ way. `create` warns about both.
315
+
316
+ **Inserting into one.** `insert` re-stamps the connection `create` hoisted off
317
+ (kept on the sequence as `recordedConnection`) before merging, so a same-browser
318
+ insert re-hoists and stays portable, while a cross-browser insert makes every
319
+ step explicit and becomes a real multi-connection sequence.
320
+
321
+ **Declaring the browsers it needs.** A sequence can bring up its own browsers
322
+ instead of expecting the caller to have launched them. Set it with `declare`:
323
+
324
+ ```js
325
+ replay({ action: 'declare', name: 'duo-stock-propagation',
326
+ requiredConnections: [
327
+ { reference: 'duo-member-two', role: 'the member who draws stock',
328
+ url: 'http://localhost:5173/login' }
329
+ ] })
330
+ ```
331
+
332
+ Each list replaces its field and `[]` clears it; passing one leaves the other
333
+ untouched. The sequence is written back to its file (a memory-only one waits
334
+ for `export`), and a declaration that cannot mean what it says is refused here
335
+ rather than on the next run. It lands on the sequence next to `commands`:
336
+
337
+ ```json
338
+ "requiredConnections": [
339
+ { "reference": "duo-member-two", "role": "the member who draws stock",
340
+ "url": "http://localhost:5173/login" }
341
+ ]
342
+ ```
343
+
344
+ `url` defaults to the sequence's `startUrl`; `forceNewInstance` defaults to
345
+ **true** (a separate process, not a tab - two identities in one browser share
346
+ its storage); `role` shows up in the run summary. A reference already bound to
347
+ a live browser is reused, and a `connections` mapping wins over the
348
+ declaration. A browser that will not launch fails the run before step 1.
349
+
350
+ **`profile` makes the device durable.** Add the persistent profile the browser
351
+ should come up on - the same ones `launchChrome({ profile })` creates:
352
+
353
+ ```json
354
+ { "reference": "device-a", "profile": "device-a", "role": "the enrolled device" }
355
+ ```
356
+
357
+ Storage (cookies, localStorage, IndexedDB, non-extractable CryptoKeys) survives
358
+ between runs, so a device enrolled once stays enrolled; the reference is just
359
+ this session's name for it. Steps still address browsers by `connectionReason` -
360
+ there is no per-step `profile`.
361
+
362
+ Two rules follow. `forceNewInstance` defaults to **false** when a profile is
363
+ named, because only one live Chrome may hold a profile and the one already
364
+ running it is the browser you asked for. And a profile-bearing reference may
365
+ **not** be rebound through `connections`, nor may two declarations share one
366
+ profile: a profile is an identity claim, not a default, and pointing it
367
+ elsewhere would run device-a's steps in a browser that is not device-a and pass.
368
+ Teardown kills the browser but never the profile directory.
369
+
370
+ The run closes what it launched on every terminal outcome - completed, failed,
371
+ cancelled - and reports *"Browsers closed (declared and launched): ..."*. A
372
+ pause keeps them (that is the state you stopped to inspect); whatever ends the
373
+ pause (`cancel`, `finish`, stepping off the end) closes them then. Browsers
374
+ that were already up, or that share a port with another live connection, are
375
+ left alone.
376
+
377
+ **Declaring the sockets it depends on.** `requiredSockets` is the same idea for
378
+ transports: URL substrings of the WebSockets the assertions ride on, set by the
379
+ same action (`replay({ action: 'declare', name: '...', requiredSockets:
380
+ ['/api/sync/socket'] })`). A sequence that declares them is
381
+ checked without the caller asking - `requireSockets: true` is only for a
382
+ sequence that declares none. Per entry the run fails when a matching socket
383
+ closed or hit frame errors mid-run, or when none is open at the end (including
384
+ one that never opened - invisible to any final "is it up" assertion). Closes
385
+ the run did not cause are not blamed on it: a socket torn down with its target
386
+ by a navigation, or hung up by the page, is normal. Match the app's own path,
387
+ not the origin, so the declaration survives `baseUrl`; dev-server sockets (Vite
388
+ HMR) go undeclared and are ignored.
389
+
390
+ **Replaying one in a different session.** Recorded references are per-session,
391
+ so rebind them:
392
+
393
+ ```
394
+ replay({ action: 'run', sequenceId: 'duo',
395
+ connections: { 'duo-member-two': 'my-second-browser' } })
396
+ ```
397
+
398
+ Recorded name on the left, a reference from this session on the right. A key
399
+ that matches nothing in the sequence is rejected up front, listing the real
400
+ ones, rather than being ignored - "the sequence" includes the sequences its
401
+ `conditional` steps pull in, so a setup sequence behind a conditional is
402
+ rebindable too. Mapping two recorded references onto one browser is rejected as
403
+ well - that would collapse the sequence into a single browser and pass.
404
+ `issues({ action: 'workOn' | 'resolve' })` takes `connections` too.
405
+
406
+ Any step naming a connection other than the run's is checked against the live
407
+ session first, so a missing browser fails as *"step 3 needs connection
408
+ duo-member-two, which does not exist in this session"* rather than as a generic
409
+ "not connected to browser" from somewhere inside the tool.
410
+
411
+ **repeat / runFromLog.** Each command replays against the connection it was
412
+ recorded with. An explicit `connectionReason` retargets a single-connection
413
+ batch and is refused for a multi-connection one.
414
+
415
+ **Exported code.** `outputFormat: 'playwright' | 'puppeteer'` gives each recorded
416
+ connection its own page rather than merging them into one. Only `navigate` and
417
+ `input` steps have equivalents; everything else (`conditional`, `launchChrome`,
418
+ `inspect`, `storage`, `wait`) becomes a `// [not generated]` comment, and a
419
+ sequence where nothing could be generated exports a test that **throws** instead
420
+ of an empty one that passes. Setup sequences are for `run`, not for export.
421
+
422
+ Two things that deliberately do not happen: a run-level `connectionReason` does
423
+ **not** override a step's own, and a per-step reference that doesn't exist in
424
+ this session **fails the step** - it never falls back to the run-level
425
+ connection. Falling back is what made a two-browser sequence silently replay in
426
+ one browser and report success.
427
+
428
+ ## Conditional steps
429
+
430
+ `conditional` is a virtual step tool - it runs another sequence inline when a
431
+ condition holds. It's handled inside the executor and never appears in the tool
432
+ list, which is why it's exempt from tool-name validation.
433
+
434
+ Not being a tool, it is never recorded, so `create`/`insert` cannot produce
435
+ one. `addConditional` is its authoring route:
436
+
437
+ ```javascript
438
+ replay({ action: 'addConditional',
439
+ name: 'checkout-flow', // or sequenceId
440
+ condition: '{{selector:.login-button}}',
441
+ thenSequence: 'perform-login', // name of another sequence
442
+ insertAfterStep: 0 }) // omit to append
443
+ ```
444
+
445
+ which stores `{ tool: 'conditional', params: { if, then } }`. Use it for state
446
+ that varies between runs - "log in first, but only if logged out".
447
+
448
+ Condition syntax and the branch target are checked before the sequence is
449
+ touched. A sequence already saved on disk is rewritten in place; otherwise it
450
+ waits for `export`. The response says which.
451
+
452
+ | Condition | True when |
453
+ |---|---|
454
+ | `{{selector:CSS}}` / `{{!selector:CSS}}` | element exists / doesn't |
455
+ | `{{url:contains:STRING}}` | current URL contains the string |
456
+ | `{{url:matches:REGEX}}` | current URL matches the regex |
457
+ | `{{url:EXACT}}` | current URL equals the value |
458
+ | `{{cookie:NAME}}` / `{{!cookie:NAME}}` | cookie exists / doesn't |
459
+ | `{{localStorage:KEY}}` / `{{!localStorage:KEY}}` | key exists / doesn't |
460
+ | `{{indexedDB:DB/STORE/KEY}}` / `{{!indexedDB:...}}` | that record exists / doesn't |
461
+ | `{{indexedDB:DB/STORE}}` | the object store holds at least one record |
462
+
463
+ A database or store that doesn't exist yet counts as **absent**, not as an
464
+ evaluation error - that's the state a wiped profile is in, and the state a
465
+ healing setup sequence exists to fix.
466
+ | `{{indexedDB:DB/STORE/KEY}}` / `{{!indexedDB:...}}` | that record exists / doesn't |
467
+ | `{{indexedDB:DB/STORE}}` | the object store holds at least one record |
468
+
469
+ A database or store that doesn't exist yet is **absent**, not an error - that's
470
+ the state a wiped profile is in. A value JSON can't represent (a
471
+ non-extractable `CryptoKey`, a `Blob`) still counts as present, so a device
472
+ identity is probeable directly instead of through some UI proxy. An all-digits
473
+ key is tried as a string and then as a number, since IndexedDB keys `42` and
474
+ `"42"` differ.
475
+
476
+ Conditions are interpolated like any other parameter, so a captured variable can
477
+ drive one: `{{indexedDB:identity/keys/{{var:deviceId}}}}`.
478
+
479
+ **Not met and cannot-evaluate are different outcomes.** A condition that is
480
+ legitimately false skips the nested sequence and the step counts as a
481
+ **success**. A condition that can't be evaluated at all - bad format, unknown
482
+ type, invalid or over-long regex, tool error - **fails the run**. Don't write a
483
+ conditional expecting a malformed condition to fall through quietly.
484
+
485
+ The nested sequence shares the parent run's captured variables (`saveAs` values
486
+ flow both ways) and inherits its remaining timeout budget. A `launchChrome` step
487
+ inside it is skipped when that reference is already connected and run when it
488
+ isn't, so a setup sequence spanning two browsers can create the second one
489
+ itself.
490
+
491
+ **Which browser its bare steps run in** follows from that: if the nested launch
492
+ actually ran, they run in the browser it created (a setup sequence is a launch
493
+ plus bare steps, since `create` hoists the connection off them - leaving them on
494
+ the caller would open a browser and then do the work in the wrong one); if the
495
+ launch was skipped or absent, they run in the calling run's connection, so a
496
+ nested login sequence still works wherever it's called from. Steps naming their
497
+ own `connectionReason` are unaffected.
498
+
499
+ **Two connections are not two devices.** A plain `launchChrome` opens a tab in
500
+ the running instance, so both references share one profile - one cookie jar, one
501
+ localStorage, one IndexedDB. A duo test built that way has ONE device identity
502
+ under two names, and a cross-user propagation check passes without a second
503
+ device existing. When the two sides must be genuinely separate, launch the
504
+ second with its own profile:
505
+ `launchChrome({ reference: 'duo-member-two', profile: 'member', forceNewInstance: true })`.
506
+ Same `port` in `listConnections` means same instance, so shared storage.
507
+
508
+ Nesting depth is capped by `replay.maxConditionalDepth` (default 10) and regexes
509
+ by `replay.maxRegexLength` (default 500), both in `.cdp-tools/config.json`.
510
+ Oscillating chains (A->B->A) are allowed up to the depth cap. Full detail:
511
+ `docs/replay.md`.
512
+
513
+ ## `forEach` steps
514
+
515
+ A condition asks whether ONE named thing exists, so `conditional` can express
516
+ "add it if it's missing" but never "remove everything that shouldn't be here".
517
+ `forEach` is the other half: enumerate a source, run a sequence per item.
518
+
519
+ ```javascript
520
+ { tool: 'forEach', params: {
521
+ in: '{{var:shares}}', // an array a previous saveAs captured
522
+ as: 'share', // bound per iteration
523
+ do: 'revoke-one-share', // sequence name, run once per item
524
+ where: 'item.name !== "Employees"', // optional filter
525
+ maxItems: 50 } } // optional cap (default 100)
526
+ ```
527
+
528
+ **`in` takes two forms.** `{{var:name}}` reads an array a previous `saveAs`
529
+ captured - which is how anything non-DOM is enumerated, since
530
+ `inspect({ action: 'evaluateExpression', saveAs: 'shares' })` can return exactly
531
+ the list you want and is a recordable step. `{{selectorAll:CSS}}` enumerates the
532
+ DOM, yielding `{ index, text, id, className, href, value }` per element -
533
+ elements themselves cannot cross the CDP boundary, so `index` is what the body
534
+ uses to address one again.
535
+
536
+ **`as` binds the item**, readable in the body as `{{var:share.id}}` like any
537
+ captured variable, with its position in `{{var:shareIndex}}`. The binding is
538
+ replaced per iteration, not scoped - the variable store is shared by reference
539
+ across nested runs, so a body's own `saveAs` captures also survive into the next
540
+ iteration.
541
+
542
+ **`where` is JavaScript, not the `{{...}}` condition grammar**, evaluated in the
543
+ page with `item` and `index` in scope. Conditions probe the browser for one named
544
+ thing; a filter has to read fields off an arbitrary object, which that grammar
545
+ cannot express. A `where` that cannot be evaluated **fails the run** - the same
546
+ rule a malformed condition follows, because silently excluding every item makes a
547
+ typo look like an empty result set.
548
+
549
+ An empty source is a **success**, and the run output says how many items were
550
+ found - a converge loop with nothing left to clean up would otherwise be
551
+ indistinguishable from a broken selector. A body failure stops the run and names
552
+ which item it was on. Depth shares `maxConditionalDepth` with `conditional`.
553
+
554
+ ## `teardown` - steps that always run
555
+
556
+ A sequence can carry a `teardown` array beside its `commands`:
557
+
558
+ ```json
559
+ { "name": "mint-and-check",
560
+ "commands": [ ... ],
561
+ "teardown": [
562
+ { "tool": "request",
563
+ "params": { "url": "/api/share/revoke/{{var:mint.body.id}}", "method": "POST" } }
564
+ ] }
565
+ ```
566
+
567
+ They run once the main steps reach a terminal state - success, a failed step, an
568
+ abort, or the total timeout - which is what makes cleanup survive the cases that
569
+ need it. Three properties, each deliberate:
570
+
571
+ - **Their own timeout budget** (`teardownTimeout`, default 60s), not drawn from
572
+ the run's `totalTimeout`. The commonest reason a run needs cleaning up after is
573
+ that it timed out; sharing the budget would skip teardown exactly then.
574
+ - **The run's abort signal is NOT passed down**, so `replay cancel` stops the
575
+ work and not the cleanup. A cancelled run is precisely one that left something
576
+ behind.
577
+ - **The variable store is shared**, so teardown can revoke what setup minted even
578
+ though the capturing step ran long before the failure.
579
+
580
+ They do **not** run when a run *pauses* - `stepTo`, a breakpoint, a click
581
+ validation failure. A paused run is not over, and its state is what you stopped
582
+ to look at.
583
+
584
+ A failing teardown step never changes the run's verdict; it is reported in its
585
+ own section. Otherwise a broken cleanup would mask the failure it was cleaning up
586
+ after.
587
+
588
+ **Teardown is always best-effort.** A killed cdp-tools process takes any pending
589
+ teardown with it, so it reduces accumulation and cannot guarantee a clean world.
590
+ An assertion that depends on nothing being left over ("No assets yet") stays
591
+ order-dependent whether or not teardown exists - mint your own fixture and assert
592
+ on that instead, and teardown becomes hygiene rather than correctness.
593
+
594
+ ## When a sequence is flaky
595
+
596
+ Name the symptom rather than adding sleeps - each of these has a real mechanism
597
+ behind it, documented in `docs/replay.md`:
598
+
599
+ | Symptom | What to reach for |
600
+ |---|---|
601
+ | Clicks land before the element exists | Click/type/hover already retry; add an explicit `wait({ selector })` step for work the previous step kicked off |
602
+ | Consent banners or dialogs block interaction | `handleModals: true` on the input action, with a `dismissStrategy` |
603
+ | Stale content while requests are in flight | `wait({ expression })` on a flag the app sets, not a fixed sleep |
604
+ | localhost URL fails because nothing is running | The port check fails fast - start the server (`server({ action: 'start' })`) |
605
+ | A run hangs or takes far too long | `stepTimeout` / `totalTimeout`; a step exceeding its budget fails the run at that step |
606
+ | A step ran against the wrong browser | See the multi-device section - almost always a bare `connectionReason` |
607
+
608
+ ## Verifying a fix
609
+
610
+ `issues({ action: 'workOn', id: N })` replays an issue's linked sequence so you
611
+ can see the bug reproduce, fix it, then replay again. Closing the issue is
612
+ `resolve`, which is human-gated - an agent should record findings with
613
+ `comment` and leave the closing to a person.