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,821 @@
1
+ /**
2
+ * Issues Tools
3
+ * MCP tools for tracking bugs and features as Markdown files (title + body + labels + comments)
4
+ */
5
+ import { z } from 'zod';
6
+ import { promises as fs } from 'fs';
7
+ import { join } from 'path';
8
+ import { createTool } from '../validation-helpers.js';
9
+ import { createSuccessResponse, createErrorResponse } from '../messages.js';
10
+ import { showVerificationOverlay, showTestReadyOverlay } from '../interaction-recorder.js';
11
+ import { showOverlay, getWorkOnNoSequenceConfig, } from '../overlays.js';
12
+ import { requireValidReference } from '../reference-validator.js';
13
+ import { initializeTracker, addIssue, getIssue, getIssues, updateIssueStatus, updateIssueSequenceFile, addIssueComment, acknowledgeAllBugs, getIssueSequencesDir, generateSequenceFilename, } from '../issue-tracker.js';
14
+ import { checkUrlPort } from '../utils/port-check.js';
15
+ const issuesSchema = z.object({
16
+ action: z.enum(['list', 'create', 'workOn', 'resolve', 'acknowledge', 'comment'])
17
+ .describe('Issue action: list (list all issues), create (create new issue), workOn (start working on issue), resolve (opens an interactive browser verification flow and waits for a PERSON to click Fixed/Not Fixed - a human must physically confirm before the issue is marked fixed/implemented, so an agent cannot close an issue this way and should use `comment` to record findings instead), acknowledge (acknowledge pending bugs), comment (append a comment to an issue)'),
18
+ id: z.number().optional()
19
+ .describe('Issue ID (for workOn, resolve, comment actions)'),
20
+ type: z.enum(['bug', 'feature']).optional()
21
+ .describe('Issue type (required for create, optional filter for list)'),
22
+ status: z.enum(['pending', 'acknowledged', 'in_progress', 'fixed', 'implemented']).optional()
23
+ .describe('Issue status (optional filter for list)'),
24
+ title: z.string().optional()
25
+ .describe('Short one-line issue title (required for create)'),
26
+ body: z.string().optional()
27
+ .describe('Markdown body: steps to reproduce, expected/actual, code blocks, etc (optional for create)'),
28
+ labels: z.array(z.string()).optional()
29
+ .describe('Labels to attach (create) or filter by - matches issues with ANY of the given labels (list)'),
30
+ text: z.string().optional()
31
+ .describe('Comment text in Markdown (required for comment action)'),
32
+ sequenceName: z.string().optional()
33
+ .describe('Name of existing sequence to link (for create - moves sequence to issues folder)'),
34
+ startUrl: z.string().optional()
35
+ .describe('Starting URL for manual issue verification (required for create when no sequenceName provided)'),
36
+ connectionReason: z.string().optional()
37
+ .describe('Browser connection reference (for workOn - to replay sequence)'),
38
+ connections: z.record(z.string()).optional()
39
+ .describe("workOn/resolve: rebind a multi-connection repro sequence's recorded references onto this session - { \"<recorded reference>\": \"<reference here>\" }"),
40
+ keepBrowserOpen: z.boolean().optional()
41
+ .describe('Keep browser tab open after verification (default: false, closes tab after resolve)'),
42
+ search: z.string().optional()
43
+ .describe('Search term to filter issues by title, body, comments, or recording name (for list)'),
44
+ includeCompleted: z.boolean().optional()
45
+ .describe('Include fixed/implemented issues in list (default: false, only shows active issues)'),
46
+ includeSequence: z.boolean().optional()
47
+ .describe('Include sequence recording for issue (default: true). When false, no sequence is created and Chrome does not open.'),
48
+ }).strict();
49
+ // =============================================================================
50
+ // resolve() human-verification timeout
51
+ // =============================================================================
52
+ /**
53
+ * Upper bound on how long `resolve` will wait for a human to respond to the
54
+ * interactive "ready to begin?" / "is this fixed?" overlays. Kept comfortably
55
+ * under Puppeteer's default protocolTimeout (180_000ms) so that a human
56
+ * simply walking away surfaces as our own typed ISSUES_RESOLVE_TIMEOUT error
57
+ * instead of a raw `Runtime.callFunctionOn timed out` leaking through from
58
+ * the underlying page.evaluate() call that waits on the overlay's Promise.
59
+ * Exported so tests can pass a much shorter value.
60
+ */
61
+ export const DEFAULT_RESOLVE_VERIFICATION_TIMEOUT_MS = 150_000;
62
+ /** Internal marker so the resolve handler can distinguish "human never answered" from other failures. */
63
+ class IssuesResolveTimeoutError extends Error {
64
+ issueId;
65
+ timeoutMs;
66
+ constructor(issueId, timeoutMs) {
67
+ super(`Timed out after ${timeoutMs}ms waiting for human verification on issue #${issueId}`);
68
+ this.issueId = issueId;
69
+ this.timeoutMs = timeoutMs;
70
+ this.name = 'IssuesResolveTimeoutError';
71
+ }
72
+ }
73
+ /** Race a human-response promise (overlay click) against a bounded timeout. */
74
+ async function withVerificationTimeout(promise, timeoutMs, issueId) {
75
+ let timer;
76
+ const timeout = new Promise((_, reject) => {
77
+ timer = setTimeout(() => reject(new IssuesResolveTimeoutError(issueId, timeoutMs)), timeoutMs);
78
+ });
79
+ try {
80
+ return await Promise.race([promise, timeout]);
81
+ }
82
+ finally {
83
+ clearTimeout(timer);
84
+ }
85
+ }
86
+ // =============================================================================
87
+ // Helper Functions
88
+ // =============================================================================
89
+ function formatIssuesList(issues) {
90
+ if (issues.length === 0) {
91
+ return 'No issues found.';
92
+ }
93
+ const lines = [];
94
+ // Calculate column widths
95
+ const idWidth = Math.max(2, ...issues.map(i => String(i.id).length));
96
+ const statusWidth = Math.max(6, ...issues.map(i => i.status.length));
97
+ const typeWidth = 7; // "feature" is longest
98
+ // Header
99
+ lines.push(`${'ID'.padEnd(idWidth)} ${'STATUS'.padEnd(statusWidth)} ${'TYPE'.padEnd(typeWidth)} TITLE`);
100
+ for (const issue of issues) {
101
+ const id = String(issue.id).padEnd(idWidth);
102
+ const status = issue.status.toUpperCase().padEnd(statusWidth);
103
+ const type = issue.type.padEnd(typeWidth);
104
+ const labelSuffix = issue.labels.length > 0 ? ` [${issue.labels.join(', ')}]` : '';
105
+ // Truncate title to ~60 chars (minus label suffix) for readability
106
+ const maxTitleLen = Math.max(10, 60 - labelSuffix.length);
107
+ const title = issue.title.length > maxTitleLen
108
+ ? issue.title.substring(0, maxTitleLen - 3) + '...'
109
+ : issue.title;
110
+ lines.push(`${id} ${status} ${type} ${title}${labelSuffix}`);
111
+ }
112
+ return lines.join('\n');
113
+ }
114
+ function getStatusIcon(status) {
115
+ switch (status) {
116
+ case 'pending': return '⏳';
117
+ case 'acknowledged': return '👀';
118
+ case 'in_progress': return '🔧';
119
+ case 'fixed': return '✅';
120
+ case 'implemented': return '✅';
121
+ default: return '•';
122
+ }
123
+ }
124
+ function formatIssueDetails(issue) {
125
+ const typeIcon = issue.type === 'bug' ? '🐛' : '✨';
126
+ const statusIcon = getStatusIcon(issue.status);
127
+ const lines = [
128
+ `${typeIcon} **Issue #${issue.id}** - ${issue.type.toUpperCase()}`,
129
+ `**Status:** ${statusIcon} ${issue.status}`,
130
+ `**Title:** ${issue.title}`,
131
+ ];
132
+ if (issue.labels.length > 0) {
133
+ lines.push(`**Labels:** ${issue.labels.join(', ')}`);
134
+ }
135
+ if (issue.body) {
136
+ lines.push('', '**Body:**', '', issue.body);
137
+ }
138
+ lines.push('', `**Recording:** ${issue.recordingName || 'none'}`, `**Reported:** ${issue.reportedAt.toISOString()}`);
139
+ if (issue.sequenceFile) {
140
+ lines.push(`**Sequence:** \`${issue.sequenceFile}\``);
141
+ }
142
+ if (issue.acknowledgedAt) {
143
+ lines.push(`**Acknowledged:** ${issue.acknowledgedAt.toISOString()}`);
144
+ }
145
+ if (issue.startedAt) {
146
+ lines.push(`**Started:** ${issue.startedAt.toISOString()}`);
147
+ }
148
+ if (issue.resolvedAt) {
149
+ lines.push(`**Resolved:** ${issue.resolvedAt.toISOString()}`);
150
+ }
151
+ if (issue.comments.length > 0) {
152
+ lines.push('', '**Comments:**');
153
+ for (const c of issue.comments) {
154
+ lines.push(`- ${c.timestamp.toISOString()}: ${c.text}`);
155
+ }
156
+ }
157
+ return lines.join('\n');
158
+ }
159
+ function formatCommentTimeline(issue) {
160
+ if (issue.comments.length === 0)
161
+ return 'No comments yet.';
162
+ return issue.comments.map(c => `- ${c.timestamp.toISOString()}: ${c.text}`).join('\n');
163
+ }
164
+ // =============================================================================
165
+ // Tool Export
166
+ // =============================================================================
167
+ export function createIssuesTools(executeToolCall, getSequencePath, getPageForConnection) {
168
+ return {
169
+ issues: createTool('Track and manage bugs and features as Markdown issues (title, Markdown body, labels, comments). Actions: list (show all issues with optional filters), create (create new issue with title/body/labels, optionally linking a sequence), workOn (start working on issue with auto-replay), resolve (HUMAN-ONLY interactive verification: opens a browser overlay and waits for a person to confirm the fix before marking fixed/implemented - agents are refused immediately, use `comment` instead), acknowledge (acknowledge pending bugs to unblock tools), comment (append a Markdown comment to an issue)', issuesSchema, async (args, abortSignal) => {
170
+ // Initialize tracker on first use
171
+ await initializeTracker();
172
+ switch (args.action) {
173
+ case 'list': {
174
+ const filter = {};
175
+ if (args.type)
176
+ filter.type = args.type;
177
+ if (args.status)
178
+ filter.status = args.status;
179
+ if (args.includeCompleted)
180
+ filter.includeCompleted = true;
181
+ if (args.labels && args.labels.length > 0)
182
+ filter.labels = args.labels;
183
+ let issues = await getIssues(filter);
184
+ // Apply search filter
185
+ if (args.search) {
186
+ const searchLower = args.search.toLowerCase();
187
+ issues = issues.filter(i => i.id.toString() === args.search ||
188
+ i.title.toLowerCase().includes(searchLower) ||
189
+ i.body.toLowerCase().includes(searchLower) ||
190
+ i.recordingName.toLowerCase().includes(searchLower) ||
191
+ i.comments.some(c => c.text.toLowerCase().includes(searchLower)));
192
+ }
193
+ // Get counts from filtered list
194
+ const bugCount = issues.filter(i => i.type === 'bug').length;
195
+ const featureCount = issues.filter(i => i.type === 'feature').length;
196
+ const pendingCount = issues.filter(i => i.status === 'pending').length;
197
+ return createSuccessResponse('ISSUES_LIST', {
198
+ count: issues.length,
199
+ bugCount,
200
+ featureCount,
201
+ pendingCount,
202
+ issuesList: formatIssuesList(issues),
203
+ search: args.search || null,
204
+ includeCompleted: args.includeCompleted || false,
205
+ });
206
+ }
207
+ case 'create': {
208
+ if (!args.type) {
209
+ return createErrorResponse('ISSUES_MISSING_TYPE', {
210
+ message: 'Issue type is required (bug or feature)',
211
+ });
212
+ }
213
+ if (!args.title) {
214
+ return createErrorResponse('ISSUES_MISSING_TITLE', {
215
+ message: 'Issue title is required',
216
+ });
217
+ }
218
+ // Check if sequence should be included (default: true)
219
+ const includeSequence = args.includeSequence !== false;
220
+ // Reject about:blank as user-provided startUrl (reserved as sentinel for includeSequence: false)
221
+ if (args.startUrl === 'about:blank') {
222
+ return createErrorResponse('ISSUES_INVALID_START_URL', {
223
+ message: 'about:blank is not allowed as startUrl. Use includeSequence: false to create an issue without sequence recording.',
224
+ });
225
+ }
226
+ // Check if localhost URL has an active server
227
+ if (args.startUrl) {
228
+ const portCheck = await checkUrlPort(args.startUrl);
229
+ if (portCheck && !portCheck.open) {
230
+ return createErrorResponse('ISSUES_LOCALHOST_NOT_ACTIVE', {
231
+ startUrl: args.startUrl,
232
+ port: portCheck.port,
233
+ message: `No server running on localhost:${portCheck.port}. Start the server before creating the issue.`,
234
+ });
235
+ }
236
+ }
237
+ // Require startUrl when no sequence is provided and includeSequence is true
238
+ if (includeSequence && !args.sequenceName && !args.startUrl) {
239
+ return createErrorResponse('ISSUES_MISSING_START_URL', {
240
+ message: 'startUrl is required when no sequenceName is provided (needed for verification). Use includeSequence: false to skip sequence creation.',
241
+ });
242
+ }
243
+ let sequenceFile = '';
244
+ // If sequenceName provided, move/copy sequence to issues folder
245
+ if (args.sequenceName && getSequencePath) {
246
+ const sourcePath = await getSequencePath(args.sequenceName);
247
+ if (sourcePath) {
248
+ // Generate new filename for issues folder
249
+ // We'll use a temporary ID, then update after creating the issue
250
+ const tempId = Date.now();
251
+ const newFilename = generateSequenceFilename(args.type, tempId, args.title);
252
+ const destPath = join(getIssueSequencesDir(), newFilename);
253
+ try {
254
+ // Copy the sequence file
255
+ await fs.copyFile(sourcePath, destPath);
256
+ sequenceFile = newFilename;
257
+ }
258
+ catch (error) {
259
+ return createErrorResponse('ISSUES_SEQUENCE_COPY_FAILED', {
260
+ sequenceName: args.sequenceName,
261
+ error: error.message,
262
+ });
263
+ }
264
+ }
265
+ else {
266
+ return createErrorResponse('ISSUES_SEQUENCE_NOT_FOUND', {
267
+ sequenceName: args.sequenceName,
268
+ message: `Sequence "${args.sequenceName}" not found`,
269
+ });
270
+ }
271
+ }
272
+ // Manually created issues start as acknowledged (no blocking)
273
+ // When includeSequence is false, use about:blank as sentinel to skip recording on resolve
274
+ const effectiveStartUrl = !includeSequence ? 'about:blank' : (args.startUrl || '');
275
+ const issue = await addIssue({
276
+ type: args.type,
277
+ title: args.title,
278
+ sequenceFile,
279
+ recordingName: args.sequenceName || 'manual',
280
+ initialStatus: 'acknowledged',
281
+ startUrl: effectiveStartUrl,
282
+ body: args.body,
283
+ labels: args.labels,
284
+ });
285
+ // If we created a sequence file with temp ID, rename it with real ID
286
+ if (sequenceFile && args.sequenceName) {
287
+ const correctFilename = generateSequenceFilename(args.type, issue.id, args.title);
288
+ if (correctFilename !== sequenceFile) {
289
+ const oldPath = join(getIssueSequencesDir(), sequenceFile);
290
+ const newPath = join(getIssueSequencesDir(), correctFilename);
291
+ try {
292
+ await fs.rename(oldPath, newPath);
293
+ await updateIssueSequenceFile(issue.id, correctFilename);
294
+ issue.sequenceFile = correctFilename;
295
+ }
296
+ catch {
297
+ // Keep old filename if rename fails
298
+ }
299
+ }
300
+ }
301
+ return createSuccessResponse('ISSUES_CREATED', {
302
+ id: issue.id,
303
+ type: issue.type,
304
+ title: issue.title,
305
+ sequenceFile: issue.sequenceFile || null,
306
+ });
307
+ }
308
+ case 'workOn': {
309
+ if (!args.id) {
310
+ return createErrorResponse('ISSUES_MISSING_ID', {
311
+ message: 'Issue ID is required',
312
+ });
313
+ }
314
+ const issue = await getIssue(args.id);
315
+ if (!issue) {
316
+ return createErrorResponse('ISSUES_NOT_FOUND', {
317
+ id: args.id,
318
+ message: `Issue #${args.id} not found`,
319
+ });
320
+ }
321
+ // Update status to in_progress
322
+ await updateIssueStatus(args.id, 'in_progress');
323
+ // Use provided connectionReason or generate one
324
+ let connectionRef = null;
325
+ if (args.connectionReason) {
326
+ connectionRef = requireValidReference(args.connectionReason);
327
+ }
328
+ else {
329
+ connectionRef = `${issue.type} ${issue.id} workOn`;
330
+ }
331
+ const hasSequence = !!issue.sequenceFile;
332
+ // Register cleanup on abort signal to close browser tab if the
333
+ // call is cancelled mid-work. The listener MUST be detached once
334
+ // this handler settles: as a sequence step the signal is the
335
+ // RUN's long-lived signal, so a permanent listener would (a)
336
+ // accumulate one per issues step and (b) close this step's tab
337
+ // when the run is cancelled minutes after the step finished.
338
+ let detachAbortListener;
339
+ if (abortSignal && connectionRef) {
340
+ const onAbort = () => {
341
+ executeToolCall('tab', { action: 'close', reference: connectionRef }).catch(() => { });
342
+ };
343
+ abortSignal.addEventListener('abort', onAbort, { once: true });
344
+ detachAbortListener = () => abortSignal.removeEventListener('abort', onAbort);
345
+ }
346
+ try {
347
+ if (hasSequence) {
348
+ // Auto-replay sequence if available
349
+ const sequencePath = join(getIssueSequencesDir(), issue.sequenceFile);
350
+ const sequenceName = issue.sequenceFile.replace(/\.json$/, '');
351
+ // Load and run sequence (errors propagate via ToolError)
352
+ await executeToolCall('replay', {
353
+ action: 'load',
354
+ filename: sequencePath,
355
+ });
356
+ await executeToolCall('replay', {
357
+ action: 'run',
358
+ // Blocking: workOn's response reports the replay's outcome, so
359
+ // the run must complete (or fail) before we return.
360
+ wait: true,
361
+ name: sequenceName,
362
+ connectionReason: connectionRef,
363
+ // A repro that spans two browsers has per-step references from
364
+ // the session that recorded it; without this there is no way to
365
+ // rebind them and the repro cannot run here at all.
366
+ ...(args.connections && { connections: args.connections }),
367
+ showReplayOverlay: true,
368
+ issueId: issue.id,
369
+ issueType: issue.type,
370
+ issueTitle: issue.title,
371
+ });
372
+ }
373
+ else if (issue.startUrl && getPageForConnection) {
374
+ // No sequence but has startUrl - launch browser, navigate, and show options overlay
375
+ let page = await getPageForConnection(connectionRef);
376
+ if (!page) {
377
+ // Auto-launch Chrome
378
+ try {
379
+ await executeToolCall('launchChrome', {
380
+ reference: connectionRef,
381
+ });
382
+ page = await getPageForConnection(connectionRef);
383
+ }
384
+ catch (error) {
385
+ return createErrorResponse('ISSUES_CHROME_LAUNCH_FAILED', {
386
+ message: `Failed to launch Chrome: ${error.message}`,
387
+ });
388
+ }
389
+ }
390
+ if (!page) {
391
+ return createErrorResponse('ISSUES_PAGE_ERROR', {
392
+ message: 'Failed to get browser page after launch',
393
+ });
394
+ }
395
+ // Navigate to startUrl
396
+ await executeToolCall('navigate', {
397
+ action: 'goto',
398
+ connectionReason: connectionRef,
399
+ url: issue.startUrl,
400
+ waitUntil: 'load',
401
+ });
402
+ // Refresh page reference after navigation
403
+ page = await getPageForConnection(connectionRef);
404
+ if (!page) {
405
+ return createErrorResponse('ISSUES_PAGE_ERROR', {
406
+ message: 'Lost browser page after navigation',
407
+ });
408
+ }
409
+ // Show overlay with options: Cancel, Explore, or Record
410
+ const overlayConfig = getWorkOnNoSequenceConfig(issue.type, issue.id, issue.title);
411
+ const result = await showOverlay(page, overlayConfig);
412
+ if (result.action === 'cancel') {
413
+ return createSuccessResponse('ISSUES_WORK_CANCELLED', {
414
+ id: issue.id,
415
+ type: issue.type,
416
+ title: issue.title,
417
+ message: 'Work session cancelled by user',
418
+ });
419
+ }
420
+ if (result.action === 'record') {
421
+ // Start recording user's actions - this blocks until recording completes
422
+ const recordingResult = await executeToolCall('replay', {
423
+ action: 'recordInteraction',
424
+ connectionReason: connectionRef,
425
+ name: `${issue.type}-${issue.id}-repro`,
426
+ startUrl: issue.startUrl,
427
+ issueId: issue.id,
428
+ issueType: issue.type,
429
+ issueTitle: issue.title,
430
+ });
431
+ // Return the recording result directly so user sees what was recorded
432
+ return recordingResult;
433
+ }
434
+ // action === 'explore' - just leave browser open for manual exploration
435
+ }
436
+ return createSuccessResponse('ISSUES_WORK_STARTED', {
437
+ id: issue.id,
438
+ type: issue.type,
439
+ title: issue.title,
440
+ sequenceFile: issue.sequenceFile || null,
441
+ details: formatIssueDetails(issue),
442
+ replayStarted: hasSequence,
443
+ browserLaunched: !hasSequence && !!issue.startUrl,
444
+ connectionReason: connectionRef,
445
+ });
446
+ }
447
+ finally {
448
+ detachAbortListener?.();
449
+ }
450
+ }
451
+ case 'resolve': {
452
+ if (!args.id) {
453
+ return createErrorResponse('ISSUES_MISSING_ID', {
454
+ message: 'Issue ID is required',
455
+ });
456
+ }
457
+ // resolve is human-gated by construction: the only thing that can
458
+ // settle showTestReadyOverlay/showVerificationOverlay is a real
459
+ // click in the browser, so an agent calling this cannot close an
460
+ // issue - it can only wait. That wait is what the bounded timeout
461
+ // below exists to cap. We deliberately do NOT try to detect an
462
+ // agent caller up front: the overlay already enforces the policy,
463
+ // and every available signal for "who is calling" is a heuristic
464
+ // that risks refusing a genuine human.
465
+ if (!getPageForConnection) {
466
+ return createErrorResponse('ISSUES_NO_PAGE_ACCESS', {
467
+ message: 'Cannot access browser page for verification',
468
+ });
469
+ }
470
+ const issue = await getIssue(args.id);
471
+ if (!issue) {
472
+ return createErrorResponse('ISSUES_NOT_FOUND', {
473
+ id: args.id,
474
+ message: `Issue #${args.id} not found`,
475
+ });
476
+ }
477
+ // Generate a unique reference for this resolve session
478
+ const connectionRef = `${issue.type} ${issue.id} resolve`;
479
+ // Always create a fresh tab for resolve verification
480
+ let page = await getPageForConnection(connectionRef);
481
+ if (!page) {
482
+ // Try to create a new tab first (if Chrome is already running)
483
+ try {
484
+ await executeToolCall('tab', {
485
+ action: 'create',
486
+ reference: connectionRef,
487
+ });
488
+ page = await getPageForConnection(connectionRef);
489
+ }
490
+ catch {
491
+ // Chrome not running - launch it
492
+ try {
493
+ await executeToolCall('launchChrome', {
494
+ reference: connectionRef,
495
+ });
496
+ page = await getPageForConnection(connectionRef);
497
+ }
498
+ catch (error) {
499
+ return createErrorResponse('ISSUES_CHROME_LAUNCH_FAILED', {
500
+ message: `Failed to launch Chrome: ${error.message}`,
501
+ });
502
+ }
503
+ }
504
+ }
505
+ if (!page) {
506
+ return createErrorResponse('ISSUES_PAGE_ERROR', {
507
+ message: 'Failed to get browser page after launch',
508
+ });
509
+ }
510
+ const hasSequence = !!issue.sequenceFile;
511
+ // about:blank with no sequence means skip straight to completion overlay
512
+ const skipToCompletion = !hasSequence && issue.startUrl === 'about:blank';
513
+ // Navigate to startUrl first (before showing overlay) if no sequence
514
+ if (!hasSequence) {
515
+ // Use startUrl if available, otherwise about:blank
516
+ const targetUrl = issue.startUrl || 'about:blank';
517
+ // executeToolCall throws on error
518
+ await executeToolCall('navigate', {
519
+ action: 'goto',
520
+ connectionReason: connectionRef,
521
+ url: targetUrl,
522
+ waitUntil: 'load',
523
+ });
524
+ // Refresh page reference after navigation
525
+ page = await getPageForConnection(connectionRef);
526
+ if (!page) {
527
+ return createErrorResponse('ISSUES_PAGE_ERROR', {
528
+ message: 'Lost browser page after navigation',
529
+ });
530
+ }
531
+ }
532
+ // Skip "Ready to begin?" overlay if this is a no-sequence issue
533
+ let readyAction;
534
+ if (skipToCompletion) {
535
+ readyAction = 'begin'; // Simulate clicking begin
536
+ }
537
+ else {
538
+ // Bound the wait for a human response: if nobody ever clicks the
539
+ // overlay (e.g. the person walked away), fail with a typed error
540
+ // instead of letting Puppeteer's own ~180s protocolTimeout leak
541
+ // through as a raw "Runtime.callFunctionOn timed out".
542
+ try {
543
+ readyAction = await withVerificationTimeout(showTestReadyOverlay(page, issue.type, issue.title, issue.id, hasSequence), DEFAULT_RESOLVE_VERIFICATION_TIMEOUT_MS, issue.id);
544
+ }
545
+ catch (error) {
546
+ if (error instanceof IssuesResolveTimeoutError) {
547
+ if (!args.keepBrowserOpen) {
548
+ try {
549
+ await executeToolCall('tab', { action: 'close', reference: connectionRef });
550
+ }
551
+ catch {
552
+ // Non-fatal
553
+ }
554
+ }
555
+ return createErrorResponse('ISSUES_RESOLVE_TIMEOUT', {
556
+ id: issue.id,
557
+ timeoutSeconds: Math.round(DEFAULT_RESOLVE_VERIFICATION_TIMEOUT_MS / 1000),
558
+ });
559
+ }
560
+ throw error;
561
+ }
562
+ }
563
+ if (readyAction === 'cancel') {
564
+ return createSuccessResponse('ISSUES_VERIFICATION_CANCELLED', {
565
+ id: issue.id,
566
+ type: issue.type,
567
+ title: issue.title,
568
+ message: 'Verification cancelled by user',
569
+ });
570
+ }
571
+ // Handle re-record: start recording instead of replaying
572
+ if (readyAction === 'rerecord') {
573
+ // Start recording user's actions to replace existing sequence
574
+ // recordInteraction will navigate to startUrl if provided
575
+ const recordingResult = await executeToolCall('replay', {
576
+ action: 'recordInteraction',
577
+ connectionReason: connectionRef,
578
+ name: `${issue.type}-${issue.id}-repro`,
579
+ startUrl: issue.startUrl || 'about:blank',
580
+ issueId: issue.id,
581
+ issueType: issue.type,
582
+ issueTitle: issue.title,
583
+ overwrite: true,
584
+ });
585
+ // Cancellation from `_meta`: searching the sentence for
586
+ // "cancelled" also matched a recorded page whose own text
587
+ // happened to contain the word.
588
+ const resultText = recordingResult?.content?.[0]?.text || '';
589
+ if (recordingResult?._meta?.replay?.cancelled) {
590
+ return recordingResult;
591
+ }
592
+ // Return with clear instruction to run resolve again
593
+ return createSuccessResponse('ISSUES_SEQUENCE_RERECORDED', {
594
+ type: issue.type,
595
+ id: issue.id,
596
+ recordingDetails: resultText,
597
+ });
598
+ }
599
+ // Play the sequence if available, otherwise record user actions
600
+ // Track replay execution results to surface to user
601
+ let replayResult = null;
602
+ if (hasSequence) {
603
+ const sequencePath = join(getIssueSequencesDir(), issue.sequenceFile);
604
+ const sequenceName = issue.sequenceFile.replace(/\.json$/, '');
605
+ const closeVerificationTab = async () => {
606
+ if (args.keepBrowserOpen)
607
+ return;
608
+ try {
609
+ await executeToolCall('tab', { action: 'close', reference: connectionRef });
610
+ }
611
+ catch {
612
+ // Non-fatal
613
+ }
614
+ };
615
+ // A run that FAILS returns normally and is read below; a run that
616
+ // cannot start at all (missing sequence file, Chrome refused to
617
+ // launch) THROWS. That throw used to escape this handler, so the
618
+ // verification browser was left open on the one path where the
619
+ // user is least likely to be watching it.
620
+ let replayText;
621
+ try {
622
+ await executeToolCall('replay', {
623
+ action: 'load',
624
+ filename: sequencePath,
625
+ });
626
+ replayResult = await executeToolCall('replay', {
627
+ action: 'run',
628
+ // Blocking: the failure check below parses the run's result.
629
+ wait: true,
630
+ name: sequenceName,
631
+ connectionReason: connectionRef,
632
+ ...(args.connections && { connections: args.connections }),
633
+ showReplayOverlay: true,
634
+ issueId: issue.id,
635
+ issueType: issue.type,
636
+ issueTitle: issue.title,
637
+ });
638
+ replayText = replayResult?.content?.[0]?.text || '';
639
+ }
640
+ catch (replayError) {
641
+ await closeVerificationTab();
642
+ return createErrorResponse('ISSUES_REPLAY_FAILED', {
643
+ id: issue.id,
644
+ type: issue.type,
645
+ title: issue.title,
646
+ replayDetails: replayError?.response?.content?.[0]?.text
647
+ || replayError?.message
648
+ || 'The replay tool failed to run the sequence.',
649
+ });
650
+ }
651
+ // From the run's own `_meta`, not its rendered summary: the text
652
+ // form coupled this to the exact "**Failed:** 0" wording in
653
+ // replay-formatters, so a reformat there would have silently
654
+ // turned every failed verification into a pass.
655
+ const runMeta = replayResult?._meta?.replay;
656
+ const replayFailed = runMeta?.success === false || (runMeta?.failedSteps ?? 0) > 0;
657
+ if (replayFailed) {
658
+ await closeVerificationTab();
659
+ // Return error immediately with replay details
660
+ return createErrorResponse('ISSUES_REPLAY_FAILED', {
661
+ id: issue.id,
662
+ type: issue.type,
663
+ title: issue.title,
664
+ replayDetails: replayText,
665
+ });
666
+ }
667
+ }
668
+ else if (!skipToCompletion) {
669
+ // No sequence and not skipping - start recording user's actions (executeToolCall throws on error)
670
+ const recordingResult = await executeToolCall('replay', {
671
+ action: 'recordInteraction',
672
+ connectionReason: connectionRef,
673
+ name: `verify-${issue.type}-${issue.id}`,
674
+ startUrl: issue.startUrl || 'about:blank',
675
+ // Pass issue info so recording saves to issues folder
676
+ issueId: issue.id,
677
+ issueType: issue.type,
678
+ issueTitle: issue.title,
679
+ });
680
+ // Cancellation from `_meta`: searching the sentence for
681
+ // "cancelled" also matched a recorded page whose own text
682
+ // happened to contain the word.
683
+ const resultText = recordingResult?.content?.[0]?.text || '';
684
+ if (recordingResult?._meta?.replay?.cancelled) {
685
+ return recordingResult;
686
+ }
687
+ // Return with instruction to run resolve again to verify with new sequence
688
+ return createSuccessResponse('ISSUES_SEQUENCE_RERECORDED', {
689
+ type: issue.type,
690
+ id: issue.id,
691
+ recordingDetails: resultText,
692
+ });
693
+ }
694
+ // If skipToCompletion, we fall through directly to verification overlay
695
+ // Refresh page reference after replay (in case it changed)
696
+ page = await getPageForConnection(connectionRef);
697
+ if (!page) {
698
+ return createErrorResponse('ISSUES_PAGE_ERROR', {
699
+ message: 'Lost browser page during replay',
700
+ });
701
+ }
702
+ // Show verification overlay and wait for user response - bounded
703
+ // the same way as the "ready to begin?" overlay above.
704
+ let verification;
705
+ try {
706
+ verification = await withVerificationTimeout(showVerificationOverlay(page, issue.type, issue.title, issue.id), DEFAULT_RESOLVE_VERIFICATION_TIMEOUT_MS, issue.id);
707
+ }
708
+ catch (error) {
709
+ if (error instanceof IssuesResolveTimeoutError) {
710
+ if (!args.keepBrowserOpen) {
711
+ try {
712
+ await executeToolCall('tab', { action: 'close', reference: connectionRef });
713
+ }
714
+ catch {
715
+ // Non-fatal
716
+ }
717
+ }
718
+ return createErrorResponse('ISSUES_RESOLVE_TIMEOUT', {
719
+ id: issue.id,
720
+ timeoutSeconds: Math.round(DEFAULT_RESOLVE_VERIFICATION_TIMEOUT_MS / 1000),
721
+ });
722
+ }
723
+ throw error;
724
+ }
725
+ // Close the tab after verification (unless keepBrowserOpen is true)
726
+ if (!args.keepBrowserOpen) {
727
+ try {
728
+ await executeToolCall('tab', {
729
+ action: 'close',
730
+ reference: connectionRef,
731
+ });
732
+ }
733
+ catch (error) {
734
+ // Non-fatal - tab close failed but verification completed
735
+ }
736
+ }
737
+ // Extract replay execution details if available
738
+ let replayDetails = null;
739
+ if (replayResult?.content?.[0]?.text) {
740
+ replayDetails = replayResult.content[0].text;
741
+ }
742
+ // Fold the verification comment into the issue's permanent Markdown timeline
743
+ if (verification.comment) {
744
+ await addIssueComment(args.id, verification.comment);
745
+ }
746
+ if (verification.resolved) {
747
+ // User confirmed resolution
748
+ const newStatus = issue.type === 'bug' ? 'fixed' : 'implemented';
749
+ await updateIssueStatus(args.id, newStatus);
750
+ return createSuccessResponse('ISSUES_RESOLVED', {
751
+ id: issue.id,
752
+ type: issue.type,
753
+ status: newStatus,
754
+ title: issue.title,
755
+ userComment: verification.comment || null,
756
+ replayDetails,
757
+ });
758
+ }
759
+ else {
760
+ // User said not resolved - include replay details so user can see what happened
761
+ return createSuccessResponse('ISSUES_NOT_RESOLVED', {
762
+ id: issue.id,
763
+ type: issue.type,
764
+ status: issue.status,
765
+ title: issue.title,
766
+ userComment: verification.comment || null,
767
+ replayDetails,
768
+ });
769
+ }
770
+ }
771
+ case 'acknowledge': {
772
+ const acknowledged = await acknowledgeAllBugs();
773
+ if (acknowledged.length === 0) {
774
+ return createSuccessResponse('ISSUES_NONE_PENDING', {
775
+ message: 'No pending bugs to acknowledge',
776
+ });
777
+ }
778
+ const bugList = acknowledged.map(b => `- #${b.id}: ${b.title}`).join('\n');
779
+ return createSuccessResponse('ISSUES_ACKNOWLEDGED', {
780
+ count: acknowledged.length,
781
+ bugList,
782
+ });
783
+ }
784
+ case 'comment': {
785
+ if (!args.id) {
786
+ return createErrorResponse('ISSUES_MISSING_ID', {
787
+ message: 'Issue ID is required',
788
+ });
789
+ }
790
+ if (!args.text) {
791
+ return createErrorResponse('ISSUES_MISSING_TEXT', {
792
+ message: 'Comment text is required',
793
+ });
794
+ }
795
+ const issue = await getIssue(args.id);
796
+ if (!issue) {
797
+ return createErrorResponse('ISSUES_NOT_FOUND', {
798
+ id: args.id,
799
+ message: `Issue #${args.id} not found`,
800
+ });
801
+ }
802
+ const updated = await addIssueComment(args.id, args.text);
803
+ return createSuccessResponse('ISSUES_COMMENT_ADDED', {
804
+ id: issue.id,
805
+ type: issue.type,
806
+ title: issue.title,
807
+ commentCount: updated?.comments.length ?? issue.comments.length,
808
+ timeline: formatCommentTimeline(updated ?? issue),
809
+ });
810
+ }
811
+ default: {
812
+ return createErrorResponse('ISSUES_INVALID_ACTION', {
813
+ action: args.action,
814
+ message: `Unknown action: ${args.action}`,
815
+ });
816
+ }
817
+ }
818
+ }),
819
+ };
820
+ }
821
+ //# sourceMappingURL=issues-tools.js.map