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,1197 @@
1
+ /**
2
+ * Breakpoint Management Tools
3
+ */
4
+ import { z } from 'zod';
5
+ import { createTool } from '../validation-helpers.js';
6
+ import { createSuccessResponse, createErrorResponse, getErrorMessage } from '../messages.js';
7
+ import { abortErrorFor, isAbortError, throwIfAborted } from '../utils/abort.js';
8
+ /**
9
+ * Helper to resolve TypeScript source maps for breakpoint locations.
10
+ * Handles Vite-style serving (skip translation) vs traditional builds (translate).
11
+ */
12
+ async function resolveBreakpointLocation(url, lineNumber, columnNumber, cdpManager, sourceMapHandler) {
13
+ let targetUrl = url;
14
+ let targetLine = lineNumber;
15
+ let targetColumn = columnNumber;
16
+ if (url.endsWith('.ts') || url.endsWith('.tsx')) {
17
+ // Check if this .ts/.tsx URL is already loaded as a script (Vite dev server)
18
+ const tsScriptLoaded = cdpManager.isScriptLoaded(url);
19
+ if (!tsScriptLoaded) {
20
+ // Traditional build: .ts files compiled to .js, need source map translation
21
+ const mapped = await sourceMapHandler.mapToGenerated(url, lineNumber, columnNumber || 0);
22
+ if (mapped) {
23
+ targetUrl = mapped.generatedFile;
24
+ targetLine = mapped.line;
25
+ targetColumn = mapped.column;
26
+ }
27
+ }
28
+ // If tsScriptLoaded is true, use url and lineNumber directly
29
+ // CDP will handle source map translation via inline source maps
30
+ }
31
+ return { url: targetUrl, line: targetLine, column: targetColumn };
32
+ }
33
+ // Schema definitions
34
+ const breakpointSchema = z.object({
35
+ action: z.enum([
36
+ 'set', 'remove', 'list', 'setLogpoint', 'validate', 'resetCounter', 'waitForScript',
37
+ 'setDOMBreakpoint', 'setEventBreakpoint', 'setXHRBreakpoint', 'await'
38
+ ]),
39
+ connectionReason: z.string().optional(),
40
+ // Location
41
+ url: z.string().optional(),
42
+ lineNumber: z.number().optional(),
43
+ columnNumber: z.number().optional(),
44
+ condition: z.string().optional(),
45
+ // Logpoint
46
+ logMessage: z.string().optional().describe('Message with {expr} interpolation'),
47
+ includeCallStack: z.boolean().optional(),
48
+ includeVariables: z.boolean().optional(),
49
+ maxExecutions: z.number().int().min(1).optional(),
50
+ // Timing
51
+ timeout: z.number().optional().describe('Timeout ms'),
52
+ // Management
53
+ breakpointId: z.string().optional(),
54
+ // DOM breakpoint
55
+ selector: z.string().optional(),
56
+ domBreakpointType: z.enum(['subtree-modified', 'attribute-modified', 'node-removed']).optional(),
57
+ // Event breakpoint
58
+ eventName: z.string().optional().describe('Event: click, submit, input, keydown...'),
59
+ targetName: z.string().optional().describe('Filter by element type'),
60
+ // XHR breakpoint
61
+ urlPattern: z.string().optional().describe('URL substring to match'),
62
+ }).strict();
63
+ export function createBreakpointTools(cdpManager, sourceMapHandler, logpointTracker, resolveConnectionFromReason) {
64
+ return {
65
+ breakpoint: createTool('Manage breakpoints and logpoints. Actions: set (line breakpoint), remove (remove by ID), list (list all), setLogpoint (log without pausing), validate (test expressions), resetCounter (reset logpoint counter), waitForScript (wait for script load), setDOMBreakpoint (pause when element changes), setEventBreakpoint (pause when event fires), setXHRBreakpoint (pause on network requests), await (set breakpoint and wait for hit - user can abort)', breakpointSchema, async (args, abortSignal) => {
66
+ const { action } = args;
67
+ // Resolve connection if connectionReason is provided
68
+ let targetCdpManager = cdpManager;
69
+ if (args.connectionReason && resolveConnectionFromReason) {
70
+ const resolved = await resolveConnectionFromReason(args.connectionReason);
71
+ if (!resolved) {
72
+ return createErrorResponse('CONNECTION_NOT_FOUND');
73
+ }
74
+ targetCdpManager = resolved.cdpManager;
75
+ }
76
+ switch (action) {
77
+ case 'set': {
78
+ if (!args.url || args.lineNumber === undefined) {
79
+ return createErrorResponse('INVALID_PARAMS', { message: 'url and lineNumber are required for set action' });
80
+ }
81
+ // Check connection and runtime type
82
+ const runtimeType = targetCdpManager.getRuntimeType();
83
+ const isConnected = targetCdpManager.isConnected();
84
+ if (!isConnected) {
85
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
86
+ }
87
+ // Resolve source maps for TypeScript files
88
+ const resolved = await resolveBreakpointLocation(args.url, args.lineNumber, args.columnNumber, targetCdpManager, sourceMapHandler);
89
+ const targetUrl = resolved.url;
90
+ const targetLine = resolved.line;
91
+ const targetColumn = resolved.column;
92
+ try {
93
+ const breakpoint = await targetCdpManager.setBreakpoint(targetUrl, targetLine, targetColumn, args.condition);
94
+ // Check if breakpoint is pending (script not loaded yet)
95
+ if (breakpoint.status === 'pending') {
96
+ // Don't inject console link for pending breakpoints (script not loaded)
97
+ let markdown = `## Breakpoint Set (Pending)\n\n`;
98
+ markdown += `**Breakpoint ID:** \`${breakpoint.breakpointId}\`\n`;
99
+ markdown += `**URL:** \`${targetUrl}\`\n`;
100
+ markdown += `**Line:** ${targetLine}\n`;
101
+ if (args.condition) {
102
+ markdown += `**Condition:** \`${args.condition}\`\n`;
103
+ }
104
+ markdown += `\n**Status:** ⏳ Pending - Script not loaded yet\n\n`;
105
+ markdown += `**Note:** The breakpoint has been set and will activate automatically when the script loads. `;
106
+ markdown += `Use \`navigate({ action: 'goto' })\` or \`navigate({ action: 'reload' })\` to load the page.\n\n`;
107
+ markdown += `**TIP:** Use \`breakpoint({ action: 'waitForScript', url: '${targetUrl}' })\` to wait for the script to load.`;
108
+ return {
109
+ content: [{
110
+ type: 'text',
111
+ text: markdown,
112
+ }],
113
+ };
114
+ }
115
+ // Get actual resolved location (CDP returns 0-based, convert to 1-based)
116
+ const resolvedLine = breakpoint.location.lineNumber + 1;
117
+ const resolvedColumn = breakpoint.location.columnNumber !== undefined
118
+ ? breakpoint.location.columnNumber + 1
119
+ : undefined;
120
+ // Check if location was adjusted (line or column)
121
+ // targetColumn was set earlier (line 82) and may have been modified by source mapping
122
+ const lineAdjusted = resolvedLine !== targetLine;
123
+ const columnAdjusted = targetColumn !== undefined && resolvedColumn !== undefined && resolvedColumn !== targetColumn;
124
+ const wasAdjusted = lineAdjusted || columnAdjusted;
125
+ // Inject clickable console link at resolved location
126
+ const icon = args.condition ? '🔶' : '🔴';
127
+ const label = args.condition ? 'Conditional breakpoint set at' : 'Breakpoint set at';
128
+ await targetCdpManager.injectConsoleLink(targetUrl, resolvedLine, `${icon} ${label}`);
129
+ // Build location strings for message
130
+ const resolvedLocation = resolvedColumn !== undefined
131
+ ? `line ${resolvedLine}:${resolvedColumn}`
132
+ : `line ${resolvedLine}`;
133
+ const requestedLocation = targetColumn !== undefined
134
+ ? `line ${targetLine}:${targetColumn}`
135
+ : `line ${targetLine}`;
136
+ // Return markdown-only success response with resolved location info
137
+ return createSuccessResponse('BREAKPOINT_SET_SUCCESS', {
138
+ url: targetUrl,
139
+ resolvedLine: resolvedLine,
140
+ resolvedLocation: resolvedLocation,
141
+ requestedLocation: requestedLocation,
142
+ wasAdjusted: wasAdjusted,
143
+ breakpointId: breakpoint.breakpointId,
144
+ condition: args.condition,
145
+ });
146
+ }
147
+ catch (error) {
148
+ // Build context-aware error message
149
+ let markdown = getErrorMessage('BREAKPOINT_SET_FAILED', {
150
+ url: targetUrl,
151
+ lineNumber: targetLine,
152
+ error: error.message,
153
+ });
154
+ // Add runtime-specific TIP if applicable
155
+ if (runtimeType === 'chrome' && (args.url.includes('/dist/') || args.url.includes('index.js'))) {
156
+ markdown += '\n\n**TIP:** You are connected to Chrome (browser) but trying to set a breakpoint on what looks like server code. ' +
157
+ 'If this is Node.js server code, you need to connect to the Node.js debugger separately using `connectDebugger({port: 9229})`.';
158
+ }
159
+ else if (runtimeType === 'node' && args.url.includes('/public/')) {
160
+ markdown += '\n\n**TIP:** You are connected to Node.js but trying to set a breakpoint on what looks like browser code. ' +
161
+ 'You may need to connect to Chrome using `connectDebugger({port: 9222})` for client-side debugging.';
162
+ }
163
+ return {
164
+ content: [
165
+ {
166
+ type: 'text',
167
+ text: markdown,
168
+ },
169
+ ],
170
+ isError: true,
171
+ };
172
+ }
173
+ }
174
+ case 'remove': {
175
+ if (!args.breakpointId) {
176
+ return createErrorResponse('INVALID_PARAMS', { message: 'breakpointId is required for remove action' });
177
+ }
178
+ const bpId = args.breakpointId;
179
+ // Dispatch to appropriate remove method based on ID prefix
180
+ if (bpId.startsWith('dom-bp-')) {
181
+ await targetCdpManager.removeDOMBreakpoint(bpId);
182
+ }
183
+ else if (bpId.startsWith('event-bp-')) {
184
+ await targetCdpManager.removeEventListenerBreakpoint(bpId);
185
+ }
186
+ else if (bpId.startsWith('xhr-bp-')) {
187
+ await targetCdpManager.removeXHRBreakpoint(bpId);
188
+ }
189
+ else {
190
+ // Line breakpoint or logpoint - unregister from tracker first
191
+ if (logpointTracker) {
192
+ logpointTracker.unregisterLogpoint(bpId);
193
+ }
194
+ await targetCdpManager.removeBreakpoint(bpId);
195
+ }
196
+ return createSuccessResponse('BREAKPOINT_REMOVE_SUCCESS', { breakpointId: bpId });
197
+ }
198
+ case 'list': {
199
+ const breakpoints = targetCdpManager.getBreakpoints();
200
+ const counts = targetCdpManager.getBreakpointCounts();
201
+ const domBreakpoints = targetCdpManager.getDOMBreakpoints();
202
+ const eventBreakpoints = targetCdpManager.getEventListenerBreakpoints();
203
+ const xhrBreakpoints = targetCdpManager.getXHRBreakpoints();
204
+ // Count pending breakpoints
205
+ const pendingCount = breakpoints.filter(bp => bp.status === 'pending').length;
206
+ // Calculate total across all types
207
+ const totalAll = counts.total + domBreakpoints.length + eventBreakpoints.length + xhrBreakpoints.length;
208
+ // Build markdown response
209
+ let markdown = `## Active Breakpoints\n\n`;
210
+ markdown += `**Total:** ${totalAll}`;
211
+ if (totalAll > 0) {
212
+ const parts = [];
213
+ if (counts.breakpoints > 0)
214
+ parts.push(`${counts.breakpoints} line`);
215
+ if (counts.logpoints > 0)
216
+ parts.push(`${counts.logpoints} logpoint`);
217
+ if (domBreakpoints.length > 0)
218
+ parts.push(`${domBreakpoints.length} DOM`);
219
+ if (eventBreakpoints.length > 0)
220
+ parts.push(`${eventBreakpoints.length} event`);
221
+ if (xhrBreakpoints.length > 0)
222
+ parts.push(`${xhrBreakpoints.length} XHR`);
223
+ markdown += ` (${parts.join(', ')}`;
224
+ if (pendingCount > 0) {
225
+ markdown += `, ${pendingCount} pending`;
226
+ }
227
+ markdown += `)`;
228
+ }
229
+ markdown += `\n\n`;
230
+ if (totalAll === 0) {
231
+ markdown += 'No active breakpoints.\n\n';
232
+ markdown += '**TIP:** Use `breakpoint({ action: \'set\' })` to set a line breakpoint, `breakpoint({ action: \'setDOMBreakpoint\' })` for DOM changes, or `breakpoint({ action: \'setEventBreakpoint\' })` for events.';
233
+ }
234
+ else {
235
+ markdown += '| ID | Type | Status | Details |\n';
236
+ markdown += '|---|---|---|---|\n';
237
+ // Line breakpoints and logpoints
238
+ breakpoints.forEach(bp => {
239
+ const type = bp.isLogpoint ? 'logpoint' : 'line';
240
+ const status = bp.status === 'pending' ? '⏳ pending' : '✓ resolved';
241
+ let location;
242
+ if (bp.originalLocation) {
243
+ location = `${bp.originalLocation.url}:${bp.originalLocation.lineNumber}${bp.originalLocation.columnNumber !== undefined ? `:${bp.originalLocation.columnNumber}` : ''}`;
244
+ }
245
+ else {
246
+ location = `scriptId:${bp.location.scriptId}:${bp.location.lineNumber + 1}${bp.location.columnNumber !== undefined ? `:${bp.location.columnNumber + 1}` : ''}`;
247
+ }
248
+ markdown += `| \`${bp.breakpointId}\` | ${type} | ${status} | \`${location}\` |\n`;
249
+ });
250
+ // DOM breakpoints
251
+ domBreakpoints.forEach(bp => {
252
+ markdown += `| \`${bp.breakpointId}\` | DOM | ✓ active | \`${bp.selector}\` (${bp.domBreakpointType}) |\n`;
253
+ });
254
+ // Event breakpoints
255
+ eventBreakpoints.forEach(bp => {
256
+ const target = bp.targetName ? ` on ${bp.targetName}` : '';
257
+ markdown += `| \`${bp.breakpointId}\` | event | ✓ active | ${bp.eventName}${target} |\n`;
258
+ });
259
+ // XHR breakpoints
260
+ xhrBreakpoints.forEach(bp => {
261
+ markdown += `| \`${bp.breakpointId}\` | XHR | ✓ active | URL contains \`${bp.urlPattern}\` |\n`;
262
+ });
263
+ if (pendingCount > 0) {
264
+ markdown += `\n**Note:** Pending breakpoints will activate when their scripts load.`;
265
+ }
266
+ }
267
+ return {
268
+ content: [
269
+ {
270
+ type: 'text',
271
+ text: markdown,
272
+ },
273
+ ],
274
+ };
275
+ }
276
+ case 'resetCounter': {
277
+ if (!args.breakpointId) {
278
+ return createErrorResponse('INVALID_PARAMS', { message: 'breakpointId is required for resetCounter action' });
279
+ }
280
+ // Reset the counter in the tracker
281
+ if (!logpointTracker) {
282
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
283
+ }
284
+ const metadata = logpointTracker.getLogpoint(args.breakpointId);
285
+ if (!metadata) {
286
+ return createErrorResponse('BREAKPOINT_NOT_FOUND', { breakpointId: args.breakpointId });
287
+ }
288
+ // Reset the counter in the tracker
289
+ const previousCount = metadata.executionCount;
290
+ logpointTracker.resetCounter(args.breakpointId);
291
+ // Reset the global counter in the page context
292
+ const logpointKey = `${metadata.url}:${metadata.lineNumber}`;
293
+ try {
294
+ await targetCdpManager.evaluateExpression(`
295
+ if (typeof globalThis.__llmCdpLogpointCounters !== 'undefined') {
296
+ globalThis.__llmCdpLogpointCounters['${logpointKey.replace(/'/g, "\\'")}'] = 0;
297
+ }
298
+ `);
299
+ }
300
+ catch (error) {
301
+ // Ignore errors - counter may not exist yet
302
+ }
303
+ // Clear the logpoint limit exceeded state in CDPManager
304
+ targetCdpManager.clearLogpointLimitExceeded();
305
+ // Build markdown response with details
306
+ let markdown = getErrorMessage('LOGPOINT_COUNTER_RESET', {
307
+ breakpointId: args.breakpointId,
308
+ maxExecutions: metadata.maxExecutions,
309
+ });
310
+ markdown += `\n\n**Logpoint Details:**\n`;
311
+ markdown += `- **Location:** \`${metadata.url}:${metadata.lineNumber}\`\n`;
312
+ markdown += `- **Log Message:** \`${metadata.logMessage}\`\n`;
313
+ markdown += `- **Previous Count:** ${previousCount}\n`;
314
+ markdown += `- **New Count:** 0\n`;
315
+ markdown += `\n**Next Step:** Use \`execution({ action: 'resume' })\` to continue execution.`;
316
+ return {
317
+ content: [
318
+ {
319
+ type: 'text',
320
+ text: markdown,
321
+ },
322
+ ],
323
+ };
324
+ }
325
+ case 'validate': {
326
+ if (!args.url || args.lineNumber === undefined || !args.logMessage) {
327
+ return createErrorResponse('INVALID_PARAMS', { message: 'url, lineNumber, and logMessage are required for validate action' });
328
+ }
329
+ const timeout = args.timeout || 2000;
330
+ // Parse logMessage to extract expressions
331
+ const expressionMatches = args.logMessage.matchAll(/\{([^}]+)\}/g);
332
+ const expressions = [];
333
+ for (const match of expressionMatches) {
334
+ expressions.push(match[1]);
335
+ }
336
+ if (expressions.length === 0) {
337
+ const markdown = `## Logpoint Validation\n\n` +
338
+ `**Status:** Valid\n` +
339
+ `**Message:** No expressions to validate in log message\n` +
340
+ `**Log Message:** \`${args.logMessage}\`\n\n` +
341
+ `**Note:** This log message contains no variable interpolations. It will output as-is.`;
342
+ return {
343
+ content: [
344
+ {
345
+ type: 'text',
346
+ text: markdown,
347
+ },
348
+ ],
349
+ };
350
+ }
351
+ // Set a temporary breakpoint to test the expressions
352
+ try {
353
+ const tempBreakpoint = await targetCdpManager.setBreakpoint(args.url, args.lineNumber, args.columnNumber);
354
+ // Get actual location from CDP (0-based)
355
+ const actualCdpLine = tempBreakpoint.location.lineNumber;
356
+ const actualCdpColumn = tempBreakpoint.location.columnNumber;
357
+ // Convert to 1-based for user display
358
+ const actualLineUser = actualCdpLine + 1;
359
+ const actualColumnUser = actualCdpColumn !== undefined ? actualCdpColumn + 1 : undefined;
360
+ // Check if location differs
361
+ const lineDiffers = actualLineUser !== args.lineNumber;
362
+ const columnDiffers = args.columnNumber !== undefined && actualColumnUser !== args.columnNumber;
363
+ const locationDiffers = lineDiffers || columnDiffers;
364
+ // Wait for the breakpoint to potentially be hit (configurable timeout)
365
+ await new Promise(resolve => setTimeout(resolve, timeout));
366
+ // Check if we're paused at the breakpoint
367
+ if (!targetCdpManager.isPaused()) {
368
+ // Remove temp breakpoint
369
+ await targetCdpManager.removeBreakpoint(tempBreakpoint.breakpointId);
370
+ let markdown = `## Logpoint Validation\n\n`;
371
+ markdown += `**Status:** Unknown\n`;
372
+ markdown += `**Message:** Unable to validate - code at this location has not been executed yet\n\n`;
373
+ markdown += `**Expressions:** ${expressions.map(e => `\`${e}\``).join(', ')}\n`;
374
+ markdown += `**Log Message:** \`${args.logMessage}\`\n\n`;
375
+ markdown += `**Location:**\n`;
376
+ markdown += `- **Requested:** Line ${args.lineNumber}${args.columnNumber ? `:${args.columnNumber}` : ''}\n`;
377
+ markdown += `- **Actual:** Line ${actualLineUser}${actualColumnUser ? `:${actualColumnUser}` : ''}\n`;
378
+ markdown += `- **Matched:** ${!locationDiffers ? 'Yes' : 'No'}\n\n`;
379
+ if (locationDiffers) {
380
+ markdown += `**Warning:** CDP mapped your requested location ${args.lineNumber}:${args.columnNumber || 'auto'} to ${actualLineUser}:${actualColumnUser || 'auto'}\n\n`;
381
+ }
382
+ markdown += `**Suggestion:** Trigger the code path that contains this line, or set the logpoint and check console for errors`;
383
+ return {
384
+ content: [
385
+ {
386
+ type: 'text',
387
+ text: markdown,
388
+ },
389
+ ],
390
+ };
391
+ }
392
+ // Try to evaluate each expression and collect available variables
393
+ const results = [];
394
+ let availableVariables = [];
395
+ const callFrame = targetCdpManager.getCallStack()?.[0];
396
+ if (callFrame) {
397
+ // Get available variables at this location
398
+ try {
399
+ const result = await targetCdpManager.getVariables(callFrame.callFrameId, false);
400
+ // Extract variable names from grouped data structure
401
+ const { data, responseType } = result;
402
+ if (responseType === 'full' || responseType === 'depth_reduced') {
403
+ // data is Record<string, {name, value, type}[]>
404
+ for (const vars of Object.values(data)) {
405
+ for (const v of vars) {
406
+ availableVariables.push(v.name);
407
+ }
408
+ }
409
+ }
410
+ else if (responseType === 'names_only') {
411
+ // data is Record<string, string[]>
412
+ for (const names of Object.values(data)) {
413
+ availableVariables.push(...names);
414
+ }
415
+ }
416
+ // For counts_only, we don't have names to suggest
417
+ }
418
+ catch (err) {
419
+ // Ignore errors getting variables
420
+ }
421
+ // Evaluate each expression
422
+ for (const expr of expressions) {
423
+ try {
424
+ const value = await targetCdpManager.evaluateExpression(expr, callFrame.callFrameId);
425
+ results.push({
426
+ expression: expr,
427
+ valid: true,
428
+ value,
429
+ });
430
+ }
431
+ catch (error) {
432
+ results.push({
433
+ expression: expr,
434
+ valid: false,
435
+ error: String(error),
436
+ });
437
+ }
438
+ }
439
+ }
440
+ else {
441
+ // No call frame available
442
+ for (const expr of expressions) {
443
+ results.push({
444
+ expression: expr,
445
+ valid: false,
446
+ error: 'No call frame available',
447
+ });
448
+ }
449
+ }
450
+ // Resume execution
451
+ await targetCdpManager.resume();
452
+ // Remove temp breakpoint
453
+ await targetCdpManager.removeBreakpoint(tempBreakpoint.breakpointId);
454
+ const allValid = results.every(r => r.valid);
455
+ const invalidExpressions = results.filter(r => !r.valid);
456
+ // Get code snippet (3 lines context around actual location)
457
+ let codeContext;
458
+ try {
459
+ const startLine = Math.max(1, actualLineUser - 1);
460
+ const endLine = actualLineUser + 1;
461
+ const sourceResult = await targetCdpManager.getSourceCode(args.url, startLine, endLine);
462
+ codeContext = sourceResult.code;
463
+ }
464
+ catch (err) {
465
+ // Ignore errors getting code snippet
466
+ }
467
+ // Build markdown response
468
+ let markdown = `## Logpoint Validation\n\n`;
469
+ markdown += `**Status:** ${allValid ? 'Valid ✓' : 'Failed ✗'}\n`;
470
+ markdown += `**Message:** ${allValid ? 'All expressions are valid at this location' : `${invalidExpressions.length} expression(s) failed to evaluate`}\n\n`;
471
+ // Location info
472
+ markdown += `**Location:**\n`;
473
+ markdown += `- **Requested:** Line ${args.lineNumber}${args.columnNumber ? `:${args.columnNumber}` : ''}\n`;
474
+ markdown += `- **Actual:** Line ${actualLineUser}${actualColumnUser ? `:${actualColumnUser}` : ''}\n`;
475
+ markdown += `- **Matched:** ${!locationDiffers ? 'Yes' : 'No'}\n\n`;
476
+ if (locationDiffers) {
477
+ markdown += `**Warning:** CDP mapped your requested location ${args.lineNumber}:${args.columnNumber || 'auto'} to ${actualLineUser}:${actualColumnUser || 'auto'}\n\n`;
478
+ }
479
+ // Expression results
480
+ markdown += `**Expression Results:**\n\n`;
481
+ markdown += `| Expression | Valid | Value/Error |\n`;
482
+ markdown += `|---|---|---|\n`;
483
+ results.forEach(r => {
484
+ const status = r.valid ? '✓' : '✗';
485
+ const valueStr = r.valid ? JSON.stringify(r.value) : r.error;
486
+ markdown += `| \`${r.expression}\` | ${status} | ${valueStr} |\n`;
487
+ });
488
+ markdown += `\n`;
489
+ // Available variables
490
+ if (availableVariables.length > 0) {
491
+ markdown += `**Available Variables:** ${availableVariables.map(v => `\`${v}\``).join(', ')}\n\n`;
492
+ }
493
+ // Code context
494
+ if (codeContext) {
495
+ markdown += `**Code Context:**\n\`\`\`javascript\n${codeContext}\n\`\`\`\n\n`;
496
+ }
497
+ // If validation failed, search for better locations
498
+ if (!allValid) {
499
+ try {
500
+ const suggestions = await targetCdpManager.findBestLogpointLocation(args.url, args.lineNumber, args.columnNumber, expressions, 2, // searchRadius ±2 lines
501
+ 1000 // 1 second timeout per candidate
502
+ );
503
+ if (suggestions.length > 0) {
504
+ markdown += `**Suggestions:**\n`;
505
+ suggestions.slice(0, 3).forEach((s) => {
506
+ markdown += `- Line ${s.line}${s.column ? `:${s.column}` : ''} - ${s.score}% of expressions valid\n`;
507
+ });
508
+ markdown += `\n**Recommendation:** Consider using line ${suggestions[0].line} where ${suggestions[0].score}% of expressions are valid`;
509
+ }
510
+ else {
511
+ markdown += `**Suggestion:** Check variable names and scopes. Variables must be in scope at the logpoint location.`;
512
+ }
513
+ }
514
+ catch (err) {
515
+ markdown += `**Suggestion:** Check variable names and scopes. Variables must be in scope at the logpoint location.`;
516
+ }
517
+ }
518
+ return {
519
+ content: [
520
+ {
521
+ type: 'text',
522
+ text: markdown,
523
+ },
524
+ ],
525
+ };
526
+ }
527
+ catch (error) {
528
+ return createErrorResponse('LOGPOINT_VALIDATE_FAILED', {
529
+ error: String(error),
530
+ });
531
+ }
532
+ }
533
+ case 'setLogpoint': {
534
+ if (!args.url || args.lineNumber === undefined || !args.logMessage) {
535
+ return createErrorResponse('INVALID_PARAMS', { message: 'url, lineNumber, and logMessage are required for setLogpoint action' });
536
+ }
537
+ const includeCallStack = args.includeCallStack || false;
538
+ const includeVariables = args.includeVariables || false;
539
+ const maxExecutions = args.maxExecutions || 20;
540
+ // Resolve source maps for TypeScript files
541
+ const resolved = await resolveBreakpointLocation(args.url, args.lineNumber, args.columnNumber, targetCdpManager, sourceMapHandler);
542
+ const targetUrl = resolved.url;
543
+ const targetLine = resolved.line;
544
+ const targetColumn = resolved.column;
545
+ // Parse logMessage to extract expressions in {}
546
+ const expressionMatches = args.logMessage.matchAll(/\{([^}]+)\}/g);
547
+ const expressions = [];
548
+ for (const match of expressionMatches) {
549
+ expressions.push(match[1]);
550
+ }
551
+ // Build the log expression in Chrome DevTools' own native logpoint format:
552
+ // a `console.log(...)` call immediately preceded by the exact
553
+ // `/** DEVTOOLS_LOGPOINT */` sentinel comment, with a trailing
554
+ // `//# sourceURL=debugger://logpoint` marker - verified against
555
+ // devtools-frontend's BreakpointManager.ts (LOGPOINT_PREFIX/LOGPOINT_SUFFIX
556
+ // + addSourceUrl()). This is exactly how Chrome's Sources panel implements
557
+ // logpoints, so the resulting console output is attributed/broadcast the
558
+ // same way for any DevTools/CDP client attached to the page, not just this
559
+ // tool's own connection.
560
+ const logpointKey = `${targetUrl}:${targetLine}`;
561
+ const escapedKey = logpointKey.replace(/'/g, "\\'");
562
+ // Computes the formatted log message; always returns a string so the
563
+ // outer console.log() call fires exactly once per (allowed) hit.
564
+ const messageExpression = `(function() {
565
+ try {
566
+ const values = {};
567
+ ${expressions.map(expr => {
568
+ const escapedExpr = expr.replace(/'/g, "\\'");
569
+ return `
570
+ try {
571
+ values['${escapedExpr}'] = ${expr};
572
+ } catch (e) {
573
+ values['${escapedExpr}'] = '[Error: ' + e.message + ']';
574
+ }`;
575
+ }).join('')}
576
+
577
+ const safeStringify = (value) => {
578
+ if (value === null) return 'null';
579
+ if (value === undefined) return 'undefined';
580
+ if (typeof value === 'string') return value;
581
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
582
+ try {
583
+ return JSON.stringify(value, null, 2);
584
+ } catch (e) {
585
+ return String(value);
586
+ }
587
+ };
588
+
589
+ let message = ${JSON.stringify(args.logMessage)};
590
+ ${expressions.map(expr => {
591
+ const escapedExpr = expr.replace(/'/g, "\\'");
592
+ return `message = message.replace('{${expr}}', safeStringify(values['${escapedExpr}']));`;
593
+ }).join('\n ')}
594
+
595
+ ${includeCallStack ? `
596
+ message += '\\n Call stack: ' + new Error().stack.split('\\n').slice(2, 5).join(' | ');
597
+ ` : ''}
598
+ ${includeVariables ? `
599
+ message += '\\n Variables: ' + safeStringify(values);
600
+ ` : ''}
601
+
602
+ if (globalThis.__llmCdpLogpointCounters['${escapedKey}'] === ${maxExecutions}) {
603
+ message += '\\n [Logpoint] Execution limit reached (${maxExecutions}/${maxExecutions}). Further hits will not be logged.';
604
+ }
605
+
606
+ return message;
607
+ } catch (e) {
608
+ if (typeof globalThis.__llmCdpLogpointErrors === 'undefined') {
609
+ globalThis.__llmCdpLogpointErrors = [];
610
+ }
611
+ globalThis.__llmCdpLogpointErrors.push({
612
+ type: 'logpoint-error',
613
+ location: '${targetUrl}:${targetLine}:${targetColumn || 'auto'}',
614
+ expressions: ${JSON.stringify(expressions)},
615
+ error: e.message,
616
+ stack: e.stack || e.toString(),
617
+ timestamp: new Date().toISOString()
618
+ });
619
+ if (globalThis.__llmCdpLogpointErrors.length > 50) {
620
+ globalThis.__llmCdpLogpointErrors.shift();
621
+ }
622
+ return '[Logpoint Error] ' + e.message;
623
+ }
624
+ })()`;
625
+ // Counting/capping happens in a guard evaluated before the real
626
+ // console.log call, so we stop logging once maxExecutions is hit
627
+ // instead of spamming the console forever. The Node-side
628
+ // LogpointExecutionTracker (see logpoint-execution-tracker.ts) still
629
+ // detects the maxExecutions-th message and pauses the debuggee as a
630
+ // safety net - this condition itself never returns true anymore,
631
+ // since its overall value must stay falsy to match the native
632
+ // never-pause logpoint semantics above.
633
+ let logExpression = `(function() {
634
+ if (typeof globalThis.__llmCdpLogpointCounters === 'undefined') {
635
+ globalThis.__llmCdpLogpointCounters = {};
636
+ }
637
+ const key = '${escapedKey}';
638
+ globalThis.__llmCdpLogpointCounters[key] = (globalThis.__llmCdpLogpointCounters[key] || 0) + 1;
639
+ return globalThis.__llmCdpLogpointCounters[key] <= ${maxExecutions};
640
+ })() && (/** DEVTOOLS_LOGPOINT */ console.log('[Logpoint] ${targetUrl}:${targetLine}:${targetColumn || 'auto'}:', ${messageExpression}))
641
+
642
+ //# sourceURL=debugger://logpoint`;
643
+ // If a user condition is provided, only log/count when it's true
644
+ if (args.condition) {
645
+ logExpression = `(${args.condition}) && ${logExpression}`;
646
+ }
647
+ // Use targetCdpManager.setBreakpoint to ensure proper state management
648
+ // This ensures state.breakpoints Map is updated immediately
649
+ let breakpoint;
650
+ try {
651
+ breakpoint = await targetCdpManager.setBreakpoint(targetUrl, targetLine, // targetCdpManager.setBreakpoint expects 1-based numbers
652
+ targetColumn, logExpression);
653
+ }
654
+ catch (error) {
655
+ let markdown = `## Failed to Set Logpoint\n\n`;
656
+ markdown += `**Error:** ${error.message}\n\n`;
657
+ markdown += `**Details:**\n`;
658
+ markdown += `- **Requested:** \`${args.url}:${args.lineNumber}\`\n`;
659
+ markdown += `- **Target:** \`${targetUrl}:${targetLine}\`\n\n`;
660
+ if (error.message.includes('not loaded')) {
661
+ markdown += `**Suggestion:** The script has not been loaded by the runtime yet. Try navigating to the page or reloading.`;
662
+ }
663
+ else {
664
+ markdown += `**Suggestion:** Verify the file has been loaded and the line number is valid.`;
665
+ }
666
+ return {
667
+ content: [{
668
+ type: 'text',
669
+ text: markdown,
670
+ }],
671
+ isError: true
672
+ };
673
+ }
674
+ // Mark as logpoint in the breakpoint info (state is already updated by setBreakpoint)
675
+ breakpoint.isLogpoint = true;
676
+ cdpManager.state.breakpoints.set(breakpoint.breakpointId, breakpoint);
677
+ // AUTOMATIC LINE/COLUMN MAPPING VALIDATION
678
+ // Get actual location from CDP (0-based)
679
+ const actualCdpLine = breakpoint.location.lineNumber;
680
+ const actualCdpColumn = breakpoint.location.columnNumber;
681
+ // Convert to 1-based for comparison with user input
682
+ const actualLineUser = actualCdpLine + 1;
683
+ const actualColumnUser = actualCdpColumn !== undefined ? actualCdpColumn + 1 : undefined;
684
+ // Check if location differs from what user requested
685
+ const lineDiffers = actualLineUser !== targetLine;
686
+ const columnDiffers = targetColumn !== undefined && actualColumnUser !== targetColumn;
687
+ const locationDiffers = lineDiffers || columnDiffers;
688
+ // If location differs AND we have expressions to validate
689
+ if (locationDiffers && expressions.length > 0) {
690
+ // Validate expressions at actual location
691
+ const validation = await targetCdpManager.validateLogpointAtActualLocation(targetUrl, actualLineUser, // 1-based
692
+ actualColumnUser, // 1-based
693
+ expressions, 2000 // 2 second timeout
694
+ );
695
+ // If validation failed (expressions not valid at actual location)
696
+ if (!validation.allValid) {
697
+ // Remove the breakpoint - don't keep a broken logpoint
698
+ // Unregister from tracker first
699
+ if (logpointTracker) {
700
+ logpointTracker.unregisterLogpoint(breakpoint.breakpointId);
701
+ }
702
+ try {
703
+ await targetCdpManager.removeBreakpoint(breakpoint.breakpointId);
704
+ }
705
+ catch (removeError) {
706
+ // Log but continue - state might already be cleaned up
707
+ console.error(`[cdp-tools] Warning: Failed to remove invalid logpoint: ${removeError.message}`);
708
+ }
709
+ // Get code snippet at actual location (3 lines context)
710
+ let codeContext = '';
711
+ try {
712
+ const sourceCode = await targetCdpManager.getSourceCode(targetUrl, Math.max(1, actualLineUser - 1), // 1 line before
713
+ actualLineUser + 1 // 1 line after
714
+ );
715
+ codeContext = sourceCode.code;
716
+ }
717
+ catch (e) {
718
+ codeContext = '(Could not fetch source code)';
719
+ }
720
+ // Search for better locations
721
+ let suggestions = [];
722
+ try {
723
+ suggestions = await targetCdpManager.findBestLogpointLocation(targetUrl, args.lineNumber, args.columnNumber, expressions, 2, // Search ±2 lines
724
+ 1000 // 1 second timeout per candidate
725
+ );
726
+ }
727
+ catch (e) {
728
+ // If search fails, provide a simple suggestion
729
+ suggestions = [{
730
+ line: actualLineUser - 1,
731
+ reason: 'Try the line before where variables might be in scope',
732
+ note: 'Use validateLogpoint first to test expressions'
733
+ }];
734
+ }
735
+ // Return detailed error response
736
+ let errorMarkdown = `## Logpoint Validation Failed\n\n`;
737
+ errorMarkdown += `**Error:** Logpoint expressions failed validation at actual CDP location\n\n`;
738
+ errorMarkdown += `**Requested Location:**\n`;
739
+ errorMarkdown += `- **URL:** \`${args.url}\`\n`;
740
+ errorMarkdown += `- **Line:** ${args.lineNumber}${args.columnNumber ? `:${args.columnNumber}` : ''}\n\n`;
741
+ errorMarkdown += `**Actual Location (CDP Mapped):**\n`;
742
+ errorMarkdown += `- **Line:** ${actualLineUser}${actualColumnUser ? `:${actualColumnUser}` : ''}\n`;
743
+ errorMarkdown += `- **Offset:** ${actualLineUser - args.lineNumber > 0 ? '+' : ''}${actualLineUser - args.lineNumber} lines\n`;
744
+ errorMarkdown += `- **Reason:** V8 mapped to nearest valid breakpoint location\n\n`;
745
+ const failedExprs = validation.results.filter((r) => !r.valid).map((r) => r.expression);
746
+ errorMarkdown += `**Failed Expressions:** ${failedExprs.map((e) => `\`${e}\``).join(', ')}\n\n`;
747
+ errorMarkdown += `**Code Context:**\n\`\`\`javascript\n${codeContext}\n\`\`\`\n\n`;
748
+ if (validation.availableVariables && validation.availableVariables.length > 0) {
749
+ errorMarkdown += `**Available Variables:** ${validation.availableVariables.map((v) => `\`${v}\``).join(', ')}\n\n`;
750
+ }
751
+ if (suggestions.length > 0) {
752
+ errorMarkdown += `**Suggestions:**\n`;
753
+ suggestions.forEach((s) => {
754
+ errorMarkdown += `- Line ${s.line}${s.column ? `:${s.column}` : ''} - ${s.score}% of expressions valid\n`;
755
+ });
756
+ errorMarkdown += `\n`;
757
+ if (suggestions[0].score === 100) {
758
+ errorMarkdown += `**Recommendation:** Set logpoint at line ${suggestions[0].line}:${suggestions[0].column || 'auto'} instead where all expressions are in scope.`;
759
+ }
760
+ else {
761
+ errorMarkdown += `**Recommendation:** Variables not in scope at actual location ${actualLineUser}:${actualColumnUser || 'auto'}. Try using validateLogpoint to find a better location.`;
762
+ }
763
+ }
764
+ else {
765
+ errorMarkdown += `**Recommendation:** Variables not in scope at actual location ${actualLineUser}:${actualColumnUser || 'auto'}. Try using validateLogpoint to find a better location.`;
766
+ }
767
+ return {
768
+ content: [{
769
+ type: 'text',
770
+ text: errorMarkdown,
771
+ }],
772
+ isError: true
773
+ };
774
+ }
775
+ // Validation passed but location differs - will show warning in success response below
776
+ }
777
+ // Register with logpoint execution tracker
778
+ if (logpointTracker) {
779
+ logpointTracker.registerLogpoint(breakpoint.breakpointId, targetUrl, actualLineUser, // Use the actual line where it was set (1-based)
780
+ args.logMessage, maxExecutions);
781
+ }
782
+ // Inject console notification at resolved location
783
+ await targetCdpManager.injectConsoleLink(targetUrl, actualLineUser, '📝 Logpoint set at');
784
+ // Parse expressions to include in the response
785
+ const expressionMatchesForResponse = args.logMessage.matchAll(/\{([^}]+)\}/g);
786
+ const expressionsForResponse = [];
787
+ for (const match of expressionMatchesForResponse) {
788
+ expressionsForResponse.push(match[1]);
789
+ }
790
+ // Build markdown success response
791
+ let markdown = `## Logpoint Set Successfully\n\n`;
792
+ markdown += `**Breakpoint ID:** \`${breakpoint.breakpointId}\`\n`;
793
+ markdown += `**Location:** \`${targetUrl}:${actualLineUser}${actualColumnUser ? `:${actualColumnUser}` : ''}\`\n`;
794
+ markdown += `**Log Message:** \`${args.logMessage}\`\n`;
795
+ if (expressionsForResponse.length > 0) {
796
+ markdown += `**Expressions:** ${expressionsForResponse.map(e => `\`${e}\``).join(', ')}\n`;
797
+ }
798
+ if (args.condition) {
799
+ markdown += `**Condition:** \`${args.condition}\`\n`;
800
+ }
801
+ markdown += `**Max Executions:** ${maxExecutions}\n\n`;
802
+ // If location differs, add warning and validation info
803
+ if (locationDiffers && expressions.length > 0) {
804
+ markdown += `**⚠️ Warning:** Logpoint was set at line ${actualLineUser}:${actualColumnUser || 'auto'} (not ${args.lineNumber}:${args.columnNumber || 'auto'}) due to V8 line mapping. All expressions validated successfully at this location.\n\n`;
805
+ }
806
+ else if (locationDiffers) {
807
+ markdown += `**⚠️ Note:** CDP mapped your requested location ${args.lineNumber}:${args.columnNumber || 'auto'} to ${actualLineUser}:${actualColumnUser || 'auto'}\n\n`;
808
+ }
809
+ markdown += `**Note:** This logpoint will log to the browser console without pausing execution`;
810
+ if (expressionsForResponse.length > 0) {
811
+ markdown += `\n\n**TIP:** Each expression is wrapped in try-catch. If an expression fails, it will show \`[Error: message]\` in the log.`;
812
+ markdown += `\nTo see logpoint errors, use: \`console({ action: 'search', pattern: "Logpoint Error" })\``;
813
+ }
814
+ return {
815
+ content: [
816
+ {
817
+ type: 'text',
818
+ text: markdown,
819
+ },
820
+ ],
821
+ };
822
+ }
823
+ case 'waitForScript': {
824
+ if (!args.url) {
825
+ return createErrorResponse('INVALID_PARAMS', { message: 'url is required for waitForScript action' });
826
+ }
827
+ const timeout = args.timeout || 10000;
828
+ // Check connection
829
+ if (!targetCdpManager.isConnected()) {
830
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
831
+ }
832
+ try {
833
+ // First check if script is already loaded
834
+ const existingScript = targetCdpManager.findLoadedScript(args.url);
835
+ if (existingScript) {
836
+ let markdown = `## Script Already Loaded\n\n`;
837
+ markdown += `**Pattern:** \`${args.url}\`\n`;
838
+ markdown += `**Matched URL:** \`${existingScript}\`\n`;
839
+ markdown += `**Status:** ✓ Script is already loaded\n\n`;
840
+ markdown += `**Next Step:** You can now set breakpoints on this script using \`breakpoint({ action: 'set', url: '${existingScript}', lineNumber: <line> })\``;
841
+ return {
842
+ content: [{
843
+ type: 'text',
844
+ text: markdown,
845
+ }],
846
+ };
847
+ }
848
+ // Script not loaded, wait for it
849
+ const matchedUrl = await targetCdpManager.waitForScript(args.url, timeout);
850
+ let markdown = `## Script Loaded\n\n`;
851
+ markdown += `**Pattern:** \`${args.url}\`\n`;
852
+ markdown += `**Matched URL:** \`${matchedUrl}\`\n`;
853
+ markdown += `**Status:** ✓ Script loaded successfully\n\n`;
854
+ markdown += `**Next Step:** You can now set breakpoints on this script using \`breakpoint({ action: 'set', url: '${matchedUrl}', lineNumber: <line> })\``;
855
+ return {
856
+ content: [{
857
+ type: 'text',
858
+ text: markdown,
859
+ }],
860
+ };
861
+ }
862
+ catch (error) {
863
+ // Timeout or other error
864
+ let markdown = `## Script Wait Timeout\n\n`;
865
+ markdown += `**Pattern:** \`${args.url}\`\n`;
866
+ markdown += `**Timeout:** ${timeout}ms\n`;
867
+ markdown += `**Error:** ${error.message}\n\n`;
868
+ // List some loaded scripts as hints
869
+ const loadedScripts = targetCdpManager.getLoadedScripts();
870
+ if (loadedScripts.length > 0) {
871
+ markdown += `**Currently Loaded Scripts (first 10):**\n`;
872
+ loadedScripts.slice(0, 10).forEach(url => {
873
+ markdown += `- \`${url}\`\n`;
874
+ });
875
+ if (loadedScripts.length > 10) {
876
+ markdown += `- ... and ${loadedScripts.length - 10} more\n`;
877
+ }
878
+ markdown += `\n`;
879
+ }
880
+ markdown += `**Suggestions:**\n`;
881
+ markdown += `- Check that the URL pattern is correct\n`;
882
+ markdown += `- Use \`navigate({ action: 'goto' })\` to load the page containing the script\n`;
883
+ markdown += `- Increase the timeout if the script loads slowly`;
884
+ return {
885
+ content: [{
886
+ type: 'text',
887
+ text: markdown,
888
+ }],
889
+ isError: true,
890
+ };
891
+ }
892
+ }
893
+ case 'setDOMBreakpoint': {
894
+ if (!args.selector) {
895
+ return createErrorResponse('INVALID_PARAMS', { message: 'selector is required for setDOMBreakpoint action' });
896
+ }
897
+ if (!args.domBreakpointType) {
898
+ return createErrorResponse('INVALID_PARAMS', { message: 'domBreakpointType is required for setDOMBreakpoint action' });
899
+ }
900
+ // Check connection
901
+ if (!targetCdpManager.isConnected()) {
902
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
903
+ }
904
+ try {
905
+ // Resolve selector to nodeId
906
+ const nodeId = await targetCdpManager.resolveSelector(args.selector);
907
+ // Set the DOM breakpoint
908
+ const breakpoint = await targetCdpManager.setDOMBreakpoint(nodeId, args.domBreakpointType, args.selector);
909
+ // Build success response
910
+ let markdown = `## DOM Breakpoint Set\n\n`;
911
+ markdown += `**Breakpoint ID:** \`${breakpoint.breakpointId}\`\n`;
912
+ markdown += `**Selector:** \`${args.selector}\`\n`;
913
+ markdown += `**Break on:** ${args.domBreakpointType}\n`;
914
+ markdown += `**Node ID:** ${nodeId}\n\n`;
915
+ const breakTypeDesc = {
916
+ 'subtree-modified': 'Execution will pause when children of this element are added, removed, or modified.',
917
+ 'attribute-modified': 'Execution will pause when any attribute of this element changes (class, style, data-*, etc.).',
918
+ 'node-removed': 'Execution will pause when this element is removed from the DOM.',
919
+ };
920
+ markdown += `**Note:** ${breakTypeDesc[args.domBreakpointType]}\n\n`;
921
+ markdown += `**Warning:** DOM breakpoints use internal nodeIds which are invalidated on page reload. You'll need to re-set this breakpoint after navigating.`;
922
+ return {
923
+ content: [{
924
+ type: 'text',
925
+ text: markdown,
926
+ }],
927
+ };
928
+ }
929
+ catch (error) {
930
+ let markdown = `## Failed to Set DOM Breakpoint\n\n`;
931
+ markdown += `**Error:** ${error.message}\n\n`;
932
+ markdown += `**Selector:** \`${args.selector}\`\n`;
933
+ markdown += `**Break Type:** ${args.domBreakpointType}\n\n`;
934
+ if (error.message.includes('not found')) {
935
+ markdown += `**Suggestion:** The element was not found. Verify the selector matches an element currently in the DOM.`;
936
+ }
937
+ else {
938
+ markdown += `**Suggestion:** Ensure the page is loaded and the element exists in the DOM.`;
939
+ }
940
+ return {
941
+ content: [{
942
+ type: 'text',
943
+ text: markdown,
944
+ }],
945
+ isError: true,
946
+ };
947
+ }
948
+ }
949
+ case 'setEventBreakpoint': {
950
+ if (!args.eventName) {
951
+ return createErrorResponse('INVALID_PARAMS', { message: 'eventName is required for setEventBreakpoint action' });
952
+ }
953
+ // Check connection
954
+ if (!targetCdpManager.isConnected()) {
955
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
956
+ }
957
+ try {
958
+ const breakpoint = await targetCdpManager.setEventListenerBreakpoint(args.eventName, args.targetName);
959
+ // Build success response
960
+ let markdown = `## Event Listener Breakpoint Set\n\n`;
961
+ markdown += `**Breakpoint ID:** \`${breakpoint.breakpointId}\`\n`;
962
+ markdown += `**Event:** \`${args.eventName}\`\n`;
963
+ if (args.targetName) {
964
+ markdown += `**Target:** ${args.targetName}\n`;
965
+ }
966
+ else {
967
+ markdown += `**Target:** All elements\n`;
968
+ }
969
+ markdown += `\n**Note:** Execution will pause whenever a \`${args.eventName}\` event is dispatched.\n\n`;
970
+ markdown += `**Common events:** click, submit, input, change, keydown, keyup, mousedown, touchstart, load, DOMContentLoaded`;
971
+ return {
972
+ content: [{
973
+ type: 'text',
974
+ text: markdown,
975
+ }],
976
+ };
977
+ }
978
+ catch (error) {
979
+ return {
980
+ content: [{
981
+ type: 'text',
982
+ text: `## Failed to Set Event Breakpoint\n\n**Error:** ${error.message}\n\n**Event:** \`${args.eventName}\``,
983
+ }],
984
+ isError: true,
985
+ };
986
+ }
987
+ }
988
+ case 'setXHRBreakpoint': {
989
+ if (!args.urlPattern) {
990
+ return createErrorResponse('INVALID_PARAMS', { message: 'urlPattern is required for setXHRBreakpoint action' });
991
+ }
992
+ // Check connection
993
+ if (!targetCdpManager.isConnected()) {
994
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
995
+ }
996
+ try {
997
+ const breakpoint = await targetCdpManager.setXHRBreakpoint(args.urlPattern);
998
+ // Build success response
999
+ let markdown = `## XHR/Fetch Breakpoint Set\n\n`;
1000
+ markdown += `**Breakpoint ID:** \`${breakpoint.breakpointId}\`\n`;
1001
+ markdown += `**URL Pattern:** \`${args.urlPattern}\`\n\n`;
1002
+ markdown += `**Note:** Execution will pause when any XHR or Fetch request URL contains \`${args.urlPattern}\`.\n\n`;
1003
+ markdown += `**Examples:** If pattern is \`/api/users\`, it will match:\n`;
1004
+ markdown += `- \`https://example.com/api/users\`\n`;
1005
+ markdown += `- \`https://example.com/api/users/123\`\n`;
1006
+ markdown += `- \`/api/users?page=1\``;
1007
+ return {
1008
+ content: [{
1009
+ type: 'text',
1010
+ text: markdown,
1011
+ }],
1012
+ };
1013
+ }
1014
+ catch (error) {
1015
+ return {
1016
+ content: [{
1017
+ type: 'text',
1018
+ text: `## Failed to Set XHR Breakpoint\n\n**Error:** ${error.message}\n\n**URL Pattern:** \`${args.urlPattern}\``,
1019
+ }],
1020
+ isError: true,
1021
+ };
1022
+ }
1023
+ }
1024
+ case 'await': {
1025
+ // Wait for any breakpoint to be hit, or set one first if url/lineNumber provided
1026
+ if (!targetCdpManager.isConnected()) {
1027
+ return createErrorResponse('DEBUGGER_NOT_CONNECTED');
1028
+ }
1029
+ // Already cancelled: never start waiting. (An already-aborted
1030
+ // signal fires no 'abort' event, so the listener below would
1031
+ // never resolve and this would block until pause/timeout.)
1032
+ throwIfAborted(abortSignal);
1033
+ // Track if we created a breakpoint (for cleanup on abort/timeout)
1034
+ let createdBreakpoint = null;
1035
+ const timeout = args.timeout || 300000; // Default 5 minutes
1036
+ // IMPORTANT: Start listening for pause BEFORE setting breakpoint
1037
+ // This prevents race condition where breakpoint triggers immediately
1038
+ // and pause event fires before we've registered the resolver
1039
+ let onAbort;
1040
+ const waitPromise = new Promise((resolve) => {
1041
+ // Set up abort handler (detached in the finally below - the
1042
+ // signal may be a long-lived run signal that outlives this step)
1043
+ if (abortSignal) {
1044
+ onAbort = () => resolve({ type: 'aborted' });
1045
+ abortSignal.addEventListener('abort', onAbort, { once: true });
1046
+ }
1047
+ // Wait for pause - registered before breakpoint is set
1048
+ targetCdpManager.waitForPause(timeout)
1049
+ .then(() => resolve({ type: 'paused' }))
1050
+ .catch(() => resolve({ type: 'timeout' }));
1051
+ });
1052
+ // Everything below runs inside a try/finally so the abort listener
1053
+ // is detached on EVERY exit (including the early return when
1054
+ // setBreakpoint fails): abortSignal is typically the replay run's
1055
+ // long-lived signal, and a leaked listener per step accumulates
1056
+ // for the whole run.
1057
+ try {
1058
+ // If url and lineNumber provided, set a breakpoint (after listener is registered)
1059
+ if (args.url && args.lineNumber !== undefined) {
1060
+ // Resolve source maps for TypeScript files
1061
+ const resolved = await resolveBreakpointLocation(args.url, args.lineNumber, args.columnNumber, targetCdpManager, sourceMapHandler);
1062
+ try {
1063
+ const breakpoint = await targetCdpManager.setBreakpoint(resolved.url, resolved.line, resolved.column, args.condition);
1064
+ const resolvedLine = breakpoint.location.lineNumber + 1;
1065
+ const resolvedColumn = breakpoint.location.columnNumber !== undefined
1066
+ ? breakpoint.location.columnNumber + 1
1067
+ : undefined;
1068
+ createdBreakpoint = {
1069
+ breakpointId: breakpoint.breakpointId,
1070
+ url: resolved.url,
1071
+ line: resolvedLine,
1072
+ column: resolvedColumn
1073
+ };
1074
+ }
1075
+ catch (error) {
1076
+ if (isAbortError(error))
1077
+ throw error;
1078
+ return {
1079
+ content: [{
1080
+ type: 'text',
1081
+ text: `## Failed to Set Await Breakpoint\n\n**Error:** ${error.message}\n\n**Location:** \`${resolved.url}:${resolved.line}\``,
1082
+ }],
1083
+ isError: true,
1084
+ };
1085
+ }
1086
+ }
1087
+ try {
1088
+ const result = await waitPromise;
1089
+ if (result.type === 'aborted') {
1090
+ // Clean up breakpoint on abort (only if we created one) BEFORE
1091
+ // throwing: a one-shot await breakpoint left behind would pause
1092
+ // the target the next time that line runs, long after the user
1093
+ // cancelled.
1094
+ if (createdBreakpoint) {
1095
+ try {
1096
+ await targetCdpManager.removeBreakpoint(createdBreakpoint.breakpointId);
1097
+ }
1098
+ catch {
1099
+ // Ignore cleanup errors
1100
+ }
1101
+ }
1102
+ // THROW, don't return (#110): this used to resolve a
1103
+ // success-SHAPED response (no isError), so a cancelled
1104
+ // `breakpoint.await` step was recorded `success: true` - a
1105
+ // cancelled step reported as passed. Throwing abort-shaped is
1106
+ // the same contract every other cancellable handler uses, and
1107
+ // the replay executor classifies it as
1108
+ // "Replay aborted by user".
1109
+ throw abortErrorFor(abortSignal);
1110
+ }
1111
+ if (result.type === 'timeout') {
1112
+ let timeoutMsg = `## Breakpoint Await Timeout\n\n`;
1113
+ timeoutMsg += `No breakpoint was hit within ${timeout / 1000} seconds.\n\n`;
1114
+ if (createdBreakpoint) {
1115
+ timeoutMsg += `**Note:** The breakpoint at \`${createdBreakpoint.url}:${createdBreakpoint.line}\` is still active.\n`;
1116
+ timeoutMsg += `Use \`breakpoint({ action: 'remove', breakpointId: '${createdBreakpoint.breakpointId}' })\` to remove it.`;
1117
+ }
1118
+ return {
1119
+ content: [{
1120
+ type: 'text',
1121
+ text: timeoutMsg,
1122
+ }],
1123
+ isError: true,
1124
+ };
1125
+ }
1126
+ // Paused - get call stack info
1127
+ const pauseInfo = targetCdpManager.getPausedInfo();
1128
+ // If we created a breakpoint, remove it so it doesn't hit again on resume
1129
+ if (createdBreakpoint) {
1130
+ try {
1131
+ await targetCdpManager.removeBreakpoint(createdBreakpoint.breakpointId);
1132
+ }
1133
+ catch {
1134
+ // Ignore removal errors
1135
+ }
1136
+ }
1137
+ let markdown = `## Breakpoint Hit!\n\n`;
1138
+ if (pauseInfo.paused && pauseInfo.callStack && pauseInfo.callStack.length > 0) {
1139
+ const topFrame = pauseInfo.callStack[0];
1140
+ const hitUrl = targetCdpManager.getScriptUrl(topFrame.location.scriptId) || 'unknown';
1141
+ const hitLine = topFrame.location.lineNumber + 1;
1142
+ const hitColumn = topFrame.location.columnNumber !== undefined ? topFrame.location.columnNumber + 1 : undefined;
1143
+ markdown += `**Location:** \`${hitUrl}:${hitLine}${hitColumn ? `:${hitColumn}` : ''}\`\n`;
1144
+ if (createdBreakpoint) {
1145
+ markdown += `**Created breakpoint removed** (one-shot)\n\n`;
1146
+ }
1147
+ markdown += `**Paused at:** \`${topFrame.functionName || '(anonymous)'}\`\n`;
1148
+ markdown += `**Call Frame ID:** \`${topFrame.callFrameId}\`\n\n`;
1149
+ markdown += `**Next steps:**\n`;
1150
+ markdown += `- \`inspect({ action: 'getVariables', callFrameId: '${topFrame.callFrameId}' })\` - View variables\n`;
1151
+ markdown += `- \`inspect({ action: 'evaluateExpression', expression: '...' })\` - Evaluate code\n`;
1152
+ markdown += `- \`execution({ action: 'stepOver' })\` - Step to next line\n`;
1153
+ markdown += `- \`execution({ action: 'resume' })\` - Continue execution\n`;
1154
+ }
1155
+ else {
1156
+ markdown += `Execution paused but no call stack available.\n`;
1157
+ }
1158
+ return {
1159
+ content: [{
1160
+ type: 'text',
1161
+ text: markdown,
1162
+ }],
1163
+ };
1164
+ }
1165
+ catch (error) {
1166
+ // The universal trap: this broad catch would otherwise swallow
1167
+ // the abort thrown just above and report it as an await
1168
+ // *failure*. A cancellation is not a failure of this tool.
1169
+ if (isAbortError(error))
1170
+ throw error;
1171
+ return {
1172
+ content: [{
1173
+ type: 'text',
1174
+ text: `## Await Breakpoint Error\n\n**Error:** ${error.message}`,
1175
+ }],
1176
+ isError: true,
1177
+ };
1178
+ }
1179
+ }
1180
+ finally {
1181
+ // Detach the abort listener. The waitForPause resolver it raced
1182
+ // stays registered inside cdp-manager until its own timeout
1183
+ // fires; that is harmless (resolving an already-settled promise
1184
+ // is a no-op and its rejection is caught) but it does mean the
1185
+ // 'await' step's timer outlives the cancel.
1186
+ if (abortSignal && onAbort) {
1187
+ abortSignal.removeEventListener('abort', onAbort);
1188
+ }
1189
+ }
1190
+ }
1191
+ default:
1192
+ return createErrorResponse('INVALID_ACTION', { action });
1193
+ }
1194
+ }),
1195
+ };
1196
+ }
1197
+ //# sourceMappingURL=breakpoint-tools.js.map