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,894 @@
1
+ /**
2
+ * Storage Access Tools
3
+ */
4
+ import { z } from 'zod';
5
+ import { executeWithPauseDetection } from '../debugger-aware-wrapper.js';
6
+ import { createTool } from '../validation-helpers.js';
7
+ import { createSuccessResponse, createErrorResponse, formatCodeBlock } from '../messages.js';
8
+ /**
9
+ * Describe an arbitrary structured-clone value as JSON-expressible data.
10
+ *
11
+ * IndexedDB stores structured-clone values, and several of the most interesting
12
+ * ones (a non-extractable `CryptoKey`, a `Blob`, an `ArrayBuffer`) serialize to
13
+ * `{}` under JSON - which is exactly the case the caller most wants to assert
14
+ * on. Instead of dropping them, emit a typed descriptor:
15
+ *
16
+ * { __type: 'CryptoKey', keyType, algorithm, extractable, usages }
17
+ *
18
+ * so "an unwrappable signing key is present, P-256, non-extractable" is
19
+ * observable even though the key material is not.
20
+ *
21
+ * BUDGETS: `maxDepth`/`maxItems` are per-path and per-container, so they
22
+ * multiply rather than bound - a 500-wide array whose elements share a 500-wide
23
+ * array, repeated, is 500^6 visited nodes and pins the page's main thread. Two
24
+ * TOTAL budgets bound the whole walk instead: `maxNodes` (values visited) and
25
+ * `maxTotalChars` (characters emitted). Long strings are capped individually by
26
+ * `maxStringLength`. Whenever a budget or a string cap trips, an explicit
27
+ * marker is emitted ({__type:'BudgetExceeded'} / {__type:'String',truncated})
28
+ * and the top-level result is flagged, so a truncated read is never mistaken
29
+ * for a complete one.
30
+ *
31
+ * IMPORTANT: this function is injected into the page by stringifying it (see
32
+ * `SERIALIZER_SOURCE`), so it must be entirely self-contained - no imports, no
33
+ * closure variables, no references to anything outside its own body. Everything
34
+ * it needs is defined inline. It is exported so it can be unit-tested directly
35
+ * in Node without a browser.
36
+ */
37
+ export function describeStructuredValue(value, options) {
38
+ const opts = options || {};
39
+ const maxDepth = typeof opts.maxDepth === 'number' ? opts.maxDepth : 6;
40
+ const maxItems = typeof opts.maxItems === 'number' ? opts.maxItems : 500;
41
+ // Total (not per-container) budgets: these are what actually bound the walk.
42
+ const maxNodes = typeof opts.maxNodes === 'number' ? opts.maxNodes : 10000;
43
+ const maxTotalChars = typeof opts.maxTotalChars === 'number' ? opts.maxTotalChars : 250000;
44
+ const maxStringLength = typeof opts.maxStringLength === 'number' ? opts.maxStringLength : 10000;
45
+ let nodes = 0;
46
+ let chars = 0;
47
+ // '' while inside budget, otherwise the name of the budget that tripped.
48
+ let budgetHit = '';
49
+ // Ancestor stack, not a global "seen" set: two siblings pointing at the same
50
+ // object is a DAG, not a cycle, and should serialize twice rather than be
51
+ // reported as circular.
52
+ const stack = [];
53
+ const stackPaths = [];
54
+ // Host constructors are looked up off the global rather than referenced
55
+ // directly: this body is stringified and eval'd in the page, and `CryptoKey`
56
+ // is not even a name the server's own realm knows.
57
+ const g = typeof globalThis !== 'undefined' ? globalThis : {};
58
+ function className(v) {
59
+ try {
60
+ return v && v.constructor && v.constructor.name ? String(v.constructor.name) : '';
61
+ }
62
+ catch {
63
+ return '';
64
+ }
65
+ }
66
+ function describe(v, depth, path) {
67
+ // Total budget check before anything else: every unit of work in this walk
68
+ // happens inside a describe() call, so gating here bounds all of it.
69
+ if (budgetHit)
70
+ return { __type: 'BudgetExceeded', limit: budgetHit };
71
+ nodes++;
72
+ if (nodes > maxNodes) {
73
+ budgetHit = 'maxNodes';
74
+ return { __type: 'BudgetExceeded', limit: 'maxNodes' };
75
+ }
76
+ if (chars > maxTotalChars) {
77
+ budgetHit = 'maxTotalChars';
78
+ return { __type: 'BudgetExceeded', limit: 'maxTotalChars' };
79
+ }
80
+ chars += 4; // rough per-value overhead, so a wide tree of tiny values still costs
81
+ if (v === null)
82
+ return null;
83
+ const t = typeof v;
84
+ if (t === 'undefined')
85
+ return { __type: 'Undefined' };
86
+ if (t === 'boolean')
87
+ return v;
88
+ if (t === 'string') {
89
+ // A single record can hold a multi-megabyte string; returning it verbatim
90
+ // would put the whole thing in the MCP response.
91
+ if (v.length > maxStringLength) {
92
+ chars += maxStringLength;
93
+ return { __type: 'String', length: v.length, truncated: true, value: v.slice(0, maxStringLength) };
94
+ }
95
+ chars += v.length;
96
+ return v;
97
+ }
98
+ if (t === 'number') {
99
+ // NaN/Infinity are not JSON-expressible; keep them visible.
100
+ return isFinite(v) ? v : { __type: 'Number', value: String(v) };
101
+ }
102
+ if (t === 'bigint')
103
+ return { __type: 'BigInt', value: String(v) };
104
+ if (t === 'symbol')
105
+ return { __type: 'Symbol', description: String(v) };
106
+ if (t === 'function')
107
+ return { __type: 'Function', name: v.name || '(anonymous)' };
108
+ // Cycle check first, so a cycle is reported as a cycle even at max depth.
109
+ const seenAt = stack.indexOf(v);
110
+ if (seenAt !== -1)
111
+ return { __type: 'Circular', path: stackPaths[seenAt] };
112
+ if (depth > maxDepth)
113
+ return { __type: 'MaxDepth', className: className(v) || 'Object' };
114
+ // A value with a throwing Symbol.toStringTag getter would otherwise abort
115
+ // the entire read through the caller's catch.
116
+ let tag = '';
117
+ try {
118
+ tag = Object.prototype.toString.call(v);
119
+ }
120
+ catch {
121
+ tag = '';
122
+ }
123
+ const ctor = className(v);
124
+ if (tag === '[object Date]') {
125
+ const time = v.getTime();
126
+ return { __type: 'Date', iso: isFinite(time) ? v.toISOString() : null, time: isFinite(time) ? time : null };
127
+ }
128
+ if (tag === '[object RegExp]') {
129
+ return { __type: 'RegExp', source: v.source, flags: v.flags };
130
+ }
131
+ if (tag === '[object Error]' || (typeof Error !== 'undefined' && v instanceof Error)) {
132
+ return { __type: 'Error', name: String(v.name), message: String(v.message) };
133
+ }
134
+ // Host objects: match on constructor name too, since a value from another
135
+ // realm fails `instanceof` even though it is the real thing.
136
+ if (ctor === 'CryptoKey' || (g.CryptoKey && v instanceof g.CryptoKey)) {
137
+ return {
138
+ __type: 'CryptoKey',
139
+ keyType: v.type,
140
+ extractable: v.extractable,
141
+ usages: v.usages ? Array.prototype.slice.call(v.usages) : [],
142
+ algorithm: describe(v.algorithm, depth + 1, path + '.algorithm'),
143
+ };
144
+ }
145
+ if (ctor === 'File' || (g.File && v instanceof g.File)) {
146
+ return { __type: 'File', name: v.name, size: v.size, mimeType: v.type, lastModified: v.lastModified };
147
+ }
148
+ if (ctor === 'Blob' || (g.Blob && v instanceof g.Blob)) {
149
+ return { __type: 'Blob', size: v.size, mimeType: v.type };
150
+ }
151
+ if (tag === '[object ArrayBuffer]' || tag === '[object SharedArrayBuffer]') {
152
+ return { __type: ctor === 'SharedArrayBuffer' ? 'SharedArrayBuffer' : 'ArrayBuffer', byteLength: v.byteLength };
153
+ }
154
+ if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView(v)) {
155
+ const out = {
156
+ __type: ctor || 'ArrayBufferView',
157
+ byteLength: v.byteLength,
158
+ byteOffset: v.byteOffset,
159
+ };
160
+ if (tag !== '[object DataView]') {
161
+ out.length = v.length;
162
+ const preview = Array.prototype.slice.call(v, 0, 16);
163
+ out.preview = preview.map((n) => (typeof n === 'bigint' ? String(n) : n));
164
+ if (v.length > preview.length)
165
+ out.previewTruncated = true;
166
+ }
167
+ return out;
168
+ }
169
+ stack.push(v);
170
+ stackPaths.push(path);
171
+ try {
172
+ if (tag === '[object Map]') {
173
+ const entries = [];
174
+ let i = 0;
175
+ v.forEach((val, k) => {
176
+ if (i < maxItems && !budgetHit) {
177
+ entries.push([describe(k, depth + 1, path + '.<key ' + i + '>'), describe(val, depth + 1, path + '.<value ' + i + '>')]);
178
+ }
179
+ i++;
180
+ });
181
+ const out = { __type: 'Map', size: v.size, entries };
182
+ if (v.size > entries.length)
183
+ out.truncated = true;
184
+ return out;
185
+ }
186
+ if (tag === '[object Set]') {
187
+ const values = [];
188
+ let i = 0;
189
+ v.forEach((val) => {
190
+ if (i < maxItems && !budgetHit)
191
+ values.push(describe(val, depth + 1, path + '[' + i + ']'));
192
+ i++;
193
+ });
194
+ const out = { __type: 'Set', size: v.size, values };
195
+ if (v.size > values.length)
196
+ out.truncated = true;
197
+ return out;
198
+ }
199
+ if (Array.isArray(v)) {
200
+ const limit = Math.min(v.length, maxItems);
201
+ const out = [];
202
+ for (let i = 0; i < limit; i++) {
203
+ if (budgetHit)
204
+ break;
205
+ out.push(describe(v[i], depth + 1, path + '[' + i + ']'));
206
+ }
207
+ if (v.length > limit)
208
+ out.push({ __type: 'Truncated', omitted: v.length - limit });
209
+ return out;
210
+ }
211
+ const out = {};
212
+ if (ctor && ctor !== 'Object')
213
+ out.__class = ctor;
214
+ let keys = [];
215
+ try {
216
+ keys = Object.keys(v);
217
+ }
218
+ catch {
219
+ keys = [];
220
+ }
221
+ const limit = Math.min(keys.length, maxItems);
222
+ for (let i = 0; i < limit; i++) {
223
+ if (budgetHit)
224
+ break;
225
+ const k = keys[i];
226
+ chars += k.length + 4;
227
+ let child;
228
+ try {
229
+ child = v[k];
230
+ }
231
+ catch (e) {
232
+ out[k] = { __type: 'Unreadable', reason: String(e && e.message ? e.message : e) };
233
+ continue;
234
+ }
235
+ out[k] = describe(child, depth + 1, path + '.' + k);
236
+ }
237
+ if (keys.length > limit)
238
+ out.__truncated = keys.length - limit;
239
+ return out;
240
+ }
241
+ finally {
242
+ stack.pop();
243
+ stackPaths.pop();
244
+ }
245
+ }
246
+ const result = describe(value, 0, '$');
247
+ // Silent truncation is worse than the unbounded walk: flag the top level so a
248
+ // caller can tell a partial read from a complete one without hunting for an
249
+ // inline marker.
250
+ if (budgetHit) {
251
+ if (Array.isArray(result)) {
252
+ result.push({ __type: 'BudgetExceeded', limit: budgetHit });
253
+ }
254
+ else if (result && typeof result === 'object') {
255
+ try {
256
+ result.__budgetExceeded = budgetHit;
257
+ }
258
+ catch {
259
+ /* frozen or exotic result object - the inline markers still show it */
260
+ }
261
+ }
262
+ }
263
+ return result;
264
+ }
265
+ /**
266
+ * The serializer's own source, injected into the page as a string argument and
267
+ * re-created there with `eval`. `page.evaluate` stringifies the callback, so a
268
+ * lexical reference to `describeStructuredValue` would be undefined in-page.
269
+ */
270
+ const SERIALIZER_SOURCE = describeStructuredValue.toString();
271
+ /**
272
+ * Presence for a localStorage/sessionStorage read, structurally. `getItem`
273
+ * returns null only when the key is absent, so a stored empty string still
274
+ * counts as present - which reading the rendered JSON could not tell apart.
275
+ */
276
+ export function webStorageMeta(items, key) {
277
+ if (key === undefined) {
278
+ return { count: Object.keys(items ?? {}).length };
279
+ }
280
+ const name = String(key);
281
+ return { key: name, found: items?.[name] !== null && items?.[name] !== undefined };
282
+ }
283
+ // Consolidated schema for storage tools
284
+ const storageSchema = z.object({
285
+ action: z.enum([
286
+ 'getCookies', 'setCookie',
287
+ 'getLocalStorage', 'setLocalStorage', 'removeLocalStorage',
288
+ 'getSessionStorage', 'setSessionStorage', 'removeSessionStorage',
289
+ 'idbListDatabases', 'idbListStores', 'idbGet', 'idbGetAll', 'idbPut', 'idbDelete',
290
+ 'clear',
291
+ ]).describe('Storage action: getCookies, setCookie, getLocalStorage, setLocalStorage, removeLocalStorage (delete one localStorage key), getSessionStorage, setSessionStorage, removeSessionStorage (delete one sessionStorage key), idbListDatabases, idbListStores, idbGet, idbGetAll, idbPut, idbDelete, clear (clear storage)'),
292
+ connectionReason: z.string().optional().describe('Connection reference (use the reference from launchChrome output, e.g., "unnamed-connection-default" or your renamed tab)'),
293
+ // Parameters for getCookies action
294
+ url: z.string().optional().describe('URL to get cookies for (optional for getCookies action)'),
295
+ // Parameters for setCookie action
296
+ name: z.string().optional().describe('Cookie name (required for setCookie action)'),
297
+ value: z.string().optional().describe('Cookie/storage value (required for setCookie and setLocalStorage actions)'),
298
+ domain: z.string().optional().describe('Cookie domain (optional for setCookie action)'),
299
+ path: z.string().optional().describe('Cookie path (optional for setCookie action)'),
300
+ expires: z.number().optional().describe('Cookie expiration timestamp (optional for setCookie action)'),
301
+ httpOnly: z.boolean().optional().describe('HTTP only cookie (optional for setCookie action, default: false)'),
302
+ secure: z.boolean().optional().describe('Secure cookie (optional for setCookie action, default: false)'),
303
+ // Parameters for localStorage/sessionStorage and IndexedDB key lookups
304
+ key: z.union([z.string(), z.number()]).optional().describe('Storage key. Optional for getLocalStorage/getSessionStorage (omit to read the whole store), required for setLocalStorage/setSessionStorage/removeLocalStorage/removeSessionStorage/idbGet/idbDelete. Numbers are only meaningful for IndexedDB keys'),
305
+ // Parameters for IndexedDB actions
306
+ db: z.string().optional().describe('IndexedDB database name (required for idbListStores/idbGet/idbGetAll/idbPut/idbDelete)'),
307
+ store: z.string().optional().describe('IndexedDB object store name (required for idbGet/idbGetAll/idbPut/idbDelete)'),
308
+ record: z.any().optional().describe('Value to write for idbPut. Must be JSON-expressible - structured-clone-only types (CryptoKey, Blob/File, ArrayBuffer, Map/Set) cannot be created from JSON and so cannot be written through this tool'),
309
+ limit: z.number().optional().describe('Maximum records to return for idbGetAll (default: 50)'),
310
+ // Parameters for clear action
311
+ reason: z.string().optional().describe('Why storage needs to be cleared (required for clear action)'),
312
+ types: z.array(z.enum(['cookies', 'localStorage', 'sessionStorage', 'indexedDB'])).optional().describe('Storage types to clear (for clear action, default: cookies + localStorage + sessionStorage; indexedDB must be requested explicitly)'),
313
+ }).strict();
314
+ export function createStorageTools(puppeteerManager, cdpManager, resolveConnectionFromReason) {
315
+ return {
316
+ storage: createTool('Access and manage browser storage (cookies, localStorage, sessionStorage, IndexedDB). ' +
317
+ 'Cookies: getCookies, setCookie. ' +
318
+ 'localStorage: getLocalStorage (omit key to read the whole store), setLocalStorage, removeLocalStorage (delete one key). ' +
319
+ 'sessionStorage: getSessionStorage, setSessionStorage, removeSessionStorage - a full peer of localStorage. ' +
320
+ 'IndexedDB: idbListDatabases, idbListStores({db}), idbGet({db,store,key}), idbGetAll({db,store,limit}), idbPut({db,store,record,key?}), idbDelete({db,store,key}). ' +
321
+ 'IndexedDB reads return values that JSON cannot represent as typed descriptors instead of dropping them - e.g. {__type:"CryptoKey",keyType,algorithm,extractable,usages}, and the same for Blob/File, ArrayBuffer and typed arrays, Map, Set, Date, RegExp and BigInt; cycles come back as {__type:"Circular",path}. That makes a non-extractable key assertable even though its material cannot be read. ' +
322
+ 'Very large values are bounded rather than returned whole: an oversized read is marked with {__type:"BudgetExceeded"} (plus "__budgetExceeded" at the top level) and a long string comes back as {__type:"String",length,truncated:true,value}, so a partial read is always distinguishable from a complete one. ' +
323
+ 'idbPut is the reverse and is limited: "record" must be JSON-expressible, so structured-clone-only values (CryptoKey, Blob/File, ArrayBuffer, Map/Set) cannot be written through this tool - create those in-page with inspect({action:"evaluateExpression"}). ' +
324
+ 'clear wipes storage by type (cookies, localStorage, sessionStorage, and indexedDB when explicitly requested).', storageSchema, async (args) => {
325
+ const { action, connectionReason } = args;
326
+ // Validate required parameters for each action
327
+ if (action === 'setCookie') {
328
+ if (!args.name) {
329
+ return createErrorResponse('MISSING_PARAMETER', {
330
+ action: 'setCookie',
331
+ missing: 'name',
332
+ message: 'The "setCookie" action requires a "name" parameter'
333
+ });
334
+ }
335
+ // `=== undefined`, not falsy: '' is a legitimate value (clearing a
336
+ // flag) and 0 is a legitimate key.
337
+ if (args.value === undefined) {
338
+ return createErrorResponse('MISSING_PARAMETER', {
339
+ action: 'setCookie',
340
+ missing: 'value',
341
+ message: 'The "setCookie" action requires a "value" parameter'
342
+ });
343
+ }
344
+ }
345
+ if (action === 'setLocalStorage') {
346
+ if (args.key === undefined) {
347
+ return createErrorResponse('MISSING_PARAMETER', {
348
+ action: 'setLocalStorage',
349
+ missing: 'key',
350
+ message: 'The "setLocalStorage" action requires a "key" parameter'
351
+ });
352
+ }
353
+ if (args.value === undefined) {
354
+ return createErrorResponse('MISSING_PARAMETER', {
355
+ action: 'setLocalStorage',
356
+ missing: 'value',
357
+ message: 'The "setLocalStorage" action requires a "value" parameter'
358
+ });
359
+ }
360
+ }
361
+ if (action === 'setSessionStorage') {
362
+ if (args.key === undefined) {
363
+ return createErrorResponse('MISSING_PARAMETER', {
364
+ action: 'setSessionStorage',
365
+ missing: 'key',
366
+ message: 'The "setSessionStorage" action requires a "key" parameter'
367
+ });
368
+ }
369
+ if (args.value === undefined) {
370
+ return createErrorResponse('MISSING_PARAMETER', {
371
+ action: 'setSessionStorage',
372
+ missing: 'value',
373
+ message: 'The "setSessionStorage" action requires a "value" parameter'
374
+ });
375
+ }
376
+ }
377
+ if ((action === 'removeLocalStorage' || action === 'removeSessionStorage') && args.key === undefined) {
378
+ return createErrorResponse('MISSING_PARAMETER', {
379
+ action,
380
+ missing: 'key',
381
+ message: `The "${action}" action requires a "key" parameter`
382
+ });
383
+ }
384
+ // IndexedDB actions: db/store/key requirements
385
+ if (action === 'idbListStores' && !args.db) {
386
+ return createErrorResponse('MISSING_PARAMETER', {
387
+ action,
388
+ missing: 'db',
389
+ message: 'The "idbListStores" action requires a "db" parameter (use idbListDatabases to discover names)'
390
+ });
391
+ }
392
+ if (action === 'idbGet' || action === 'idbGetAll' || action === 'idbPut' || action === 'idbDelete') {
393
+ if (!args.db) {
394
+ return createErrorResponse('MISSING_PARAMETER', {
395
+ action,
396
+ missing: 'db',
397
+ message: `The "${action}" action requires a "db" parameter (use idbListDatabases to discover names)`
398
+ });
399
+ }
400
+ if (!args.store) {
401
+ return createErrorResponse('MISSING_PARAMETER', {
402
+ action,
403
+ missing: 'store',
404
+ message: `The "${action}" action requires a "store" parameter (use idbListStores to discover names)`
405
+ });
406
+ }
407
+ }
408
+ if ((action === 'idbGet' || action === 'idbDelete') && args.key === undefined) {
409
+ return createErrorResponse('MISSING_PARAMETER', {
410
+ action,
411
+ missing: 'key',
412
+ message: `The "${action}" action requires a "key" parameter`
413
+ });
414
+ }
415
+ if (action === 'idbPut' && args.record === undefined) {
416
+ return createErrorResponse('MISSING_PARAMETER', {
417
+ action: 'idbPut',
418
+ missing: 'record',
419
+ message: 'The "idbPut" action requires a "record" parameter (the JSON-expressible value to store)'
420
+ });
421
+ }
422
+ if (action === 'clear' && !args.reason) {
423
+ return createErrorResponse('MISSING_PARAMETER', {
424
+ action: 'clear',
425
+ missing: 'reason',
426
+ message: 'The "clear" action requires a "reason" parameter'
427
+ });
428
+ }
429
+ // Resolve connection if connectionReason is provided
430
+ let targetPuppeteerManager = puppeteerManager;
431
+ let targetCdpManager = cdpManager;
432
+ if (connectionReason && resolveConnectionFromReason) {
433
+ const resolved = await resolveConnectionFromReason(connectionReason);
434
+ if (!resolved || !resolved.puppeteerManager) {
435
+ return createErrorResponse('PUPPETEER_NOT_CONNECTED');
436
+ }
437
+ targetPuppeteerManager = resolved.puppeteerManager;
438
+ targetCdpManager = resolved.cdpManager;
439
+ }
440
+ if (!targetPuppeteerManager.isConnected()) {
441
+ return createErrorResponse('PUPPETEER_NOT_CONNECTED');
442
+ }
443
+ const page = targetPuppeteerManager.getPage();
444
+ /**
445
+ * Run one IndexedDB operation inside the page.
446
+ *
447
+ * Everything IndexedDB-shaped lives in this single in-page function:
448
+ * open the database, run the request, wait for the transaction to
449
+ * settle, close. Values come back through the injected serializer so
450
+ * structured-clone-only types survive as descriptors instead of `{}`.
451
+ */
452
+ const runIdbOperation = (op, payload) => executeWithPauseDetection(targetCdpManager, () => page.evaluate(async (input, serializerSource) => {
453
+ const describe = (0, eval)('(' + serializerSource + ')');
454
+ const indexedDB = globalThis.indexedDB;
455
+ const asRequest = (r) => new Promise((resolve, reject) => {
456
+ r.onsuccess = () => resolve(r.result);
457
+ r.onerror = () => reject(r.error || new Error('IndexedDB request failed'));
458
+ });
459
+ try {
460
+ if (input.op === 'idbListDatabases') {
461
+ if (!indexedDB || typeof indexedDB.databases !== 'function') {
462
+ return { ok: false, error: 'indexedDB.databases() is not supported in this browser' };
463
+ }
464
+ const dbs = await indexedDB.databases();
465
+ return { ok: true, databases: dbs.map((d) => ({ name: d.name, version: d.version })) };
466
+ }
467
+ // Opening a name that does not exist would silently CREATE an
468
+ // empty database - a read must not have that side effect, so
469
+ // detect the upgrade and undo it.
470
+ let created = false;
471
+ const openReq = indexedDB.open(input.db);
472
+ openReq.onupgradeneeded = () => { created = true; };
473
+ const db = await new Promise((resolve, reject) => {
474
+ openReq.onsuccess = () => resolve(openReq.result);
475
+ openReq.onerror = () => reject(openReq.error || new Error('Failed to open database'));
476
+ openReq.onblocked = () => reject(new Error('Opening the database is blocked by another connection'));
477
+ });
478
+ if (created) {
479
+ db.close();
480
+ indexedDB.deleteDatabase(input.db);
481
+ return { ok: false, error: 'Database "' + input.db + '" does not exist', notFound: true };
482
+ }
483
+ const version = db.version;
484
+ if (input.op === 'idbListStores') {
485
+ const names = Array.prototype.slice.call(db.objectStoreNames);
486
+ const stores = [];
487
+ if (names.length > 0) {
488
+ const tx = db.transaction(names, 'readonly');
489
+ for (const n of names) {
490
+ const s = tx.objectStore(n);
491
+ stores.push({
492
+ name: n,
493
+ keyPath: s.keyPath === null ? null : s.keyPath,
494
+ autoIncrement: s.autoIncrement,
495
+ indexes: Array.prototype.slice.call(s.indexNames),
496
+ count: await asRequest(s.count()),
497
+ });
498
+ }
499
+ }
500
+ db.close();
501
+ return { ok: true, database: input.db, version, stores };
502
+ }
503
+ if (!db.objectStoreNames.contains(input.store)) {
504
+ const available = Array.prototype.slice.call(db.objectStoreNames);
505
+ db.close();
506
+ return {
507
+ ok: false,
508
+ error: 'Object store "' + input.store + '" not found in database "' + input.db + '"',
509
+ availableStores: available,
510
+ };
511
+ }
512
+ const writing = input.op === 'idbPut' || input.op === 'idbDelete';
513
+ const tx = db.transaction(input.store, writing ? 'readwrite' : 'readonly');
514
+ // Attach settle handlers immediately: a read-only transaction can
515
+ // complete before the awaits below finish, and a handler attached
516
+ // after the fact would never fire.
517
+ const txSettled = new Promise((resolve, reject) => {
518
+ tx.oncomplete = () => resolve();
519
+ tx.onerror = () => reject(tx.error || new Error('Transaction failed'));
520
+ tx.onabort = () => reject(tx.error || new Error('Transaction aborted'));
521
+ });
522
+ // The validation branches below abort the transaction and return
523
+ // early without awaiting it; keep that from surfacing as an
524
+ // unhandled rejection in the page.
525
+ txSettled.catch(() => { });
526
+ const store = tx.objectStore(input.store);
527
+ let out = {};
528
+ if (input.op === 'idbGet') {
529
+ const raw = await asRequest(store.get(input.key));
530
+ out = { found: raw !== undefined, key: input.key, value: raw === undefined ? null : describe(raw) };
531
+ }
532
+ else if (input.op === 'idbGetAll') {
533
+ const keys = await asRequest(store.getAllKeys(null, input.limit));
534
+ const values = await asRequest(store.getAll(null, input.limit));
535
+ const total = await asRequest(store.count());
536
+ out = {
537
+ count: values.length,
538
+ total,
539
+ truncated: total > values.length,
540
+ records: values.map((v, i) => ({ key: describe(keys[i]), value: describe(v) })),
541
+ };
542
+ }
543
+ else if (input.op === 'idbPut') {
544
+ const hasKey = input.key !== undefined && input.key !== null;
545
+ if (store.keyPath !== null && hasKey) {
546
+ tx.abort();
547
+ db.close();
548
+ return {
549
+ ok: false,
550
+ error: 'Object store "' + input.store + '" uses an in-line key (keyPath ' + JSON.stringify(store.keyPath) + '), so "key" must not be supplied - put the key inside "record" instead',
551
+ };
552
+ }
553
+ if (store.keyPath === null && !hasKey && !store.autoIncrement) {
554
+ tx.abort();
555
+ db.close();
556
+ return {
557
+ ok: false,
558
+ error: 'Object store "' + input.store + '" uses out-of-line keys without autoIncrement, so a "key" parameter is required',
559
+ };
560
+ }
561
+ const resultKey = hasKey
562
+ ? await asRequest(store.put(input.record, input.key))
563
+ : await asRequest(store.put(input.record));
564
+ out = { key: describe(resultKey) };
565
+ }
566
+ else if (input.op === 'idbDelete') {
567
+ const existing = await asRequest(store.get(input.key));
568
+ await asRequest(store.delete(input.key));
569
+ out = { existed: existing !== undefined, key: input.key };
570
+ }
571
+ else {
572
+ tx.abort();
573
+ db.close();
574
+ return { ok: false, error: 'Unknown IndexedDB operation: ' + String(input.op) };
575
+ }
576
+ await txSettled;
577
+ db.close();
578
+ return Object.assign({ ok: true, database: input.db, store: input.store }, out);
579
+ }
580
+ catch (e) {
581
+ return { ok: false, error: String(e && e.message ? e.message : e) };
582
+ }
583
+ }, Object.assign({ op }, payload), SERIALIZER_SOURCE), op);
584
+ // Handle each action
585
+ switch (action) {
586
+ case 'getCookies': {
587
+ const cookies = args.url ? await page.cookies(args.url) : await page.cookies();
588
+ const markdown = `## Browser Cookies\n\n**Count:** ${cookies.length}\n\n${formatCodeBlock(cookies)}`;
589
+ return {
590
+ content: [
591
+ {
592
+ type: 'text',
593
+ text: markdown,
594
+ },
595
+ ],
596
+ // Names structurally, so a caller asking "is this cookie set" never
597
+ // has to grep the rendered JSON - where another cookie's VALUE can
598
+ // contain the text being searched for.
599
+ _meta: {
600
+ tool: 'storage',
601
+ action,
602
+ timestamp: Date.now(),
603
+ storage: { cookieNames: cookies.map((c) => c.name), count: cookies.length },
604
+ },
605
+ };
606
+ }
607
+ case 'setCookie': {
608
+ const cookie = {
609
+ name: args.name,
610
+ value: args.value,
611
+ domain: args.domain,
612
+ path: args.path || '/',
613
+ expires: args.expires,
614
+ httpOnly: args.httpOnly ?? false,
615
+ secure: args.secure ?? false,
616
+ };
617
+ await page.setCookie(cookie);
618
+ return createSuccessResponse('COOKIE_SET_SUCCESS', {
619
+ name: args.name
620
+ }, cookie);
621
+ }
622
+ case 'getLocalStorage': {
623
+ const result = await executeWithPauseDetection(targetCdpManager, () => page.evaluate((key) => {
624
+ if (key) {
625
+ return { [key]: localStorage.getItem(key) };
626
+ }
627
+ else {
628
+ const items = {};
629
+ for (let i = 0; i < localStorage.length; i++) {
630
+ const k = localStorage.key(i);
631
+ if (k) {
632
+ items[k] = localStorage.getItem(k);
633
+ }
634
+ }
635
+ return items;
636
+ }
637
+ }, args.key === undefined ? undefined : String(args.key)), 'getLocalStorage');
638
+ const markdown = `## localStorage\n\n${formatCodeBlock(result.result)}`;
639
+ return {
640
+ content: [
641
+ {
642
+ type: 'text',
643
+ text: markdown,
644
+ },
645
+ ],
646
+ _meta: {
647
+ tool: 'storage',
648
+ action,
649
+ timestamp: Date.now(),
650
+ storage: webStorageMeta(result.result, args.key),
651
+ },
652
+ };
653
+ }
654
+ case 'setLocalStorage': {
655
+ await executeWithPauseDetection(targetCdpManager, () => page.evaluate((key, value) => {
656
+ localStorage.setItem(key, value);
657
+ }, String(args.key), args.value), 'setLocalStorage');
658
+ return createSuccessResponse('LOCAL_STORAGE_SET_SUCCESS', {
659
+ key: args.key,
660
+ value: args.value
661
+ });
662
+ }
663
+ case 'removeLocalStorage': {
664
+ const result = await executeWithPauseDetection(targetCdpManager, () => page.evaluate((key) => {
665
+ const existed = localStorage.getItem(key) !== null;
666
+ localStorage.removeItem(key);
667
+ return { existed };
668
+ }, String(args.key)), 'removeLocalStorage');
669
+ return createSuccessResponse('STORAGE_KEY_REMOVED', {
670
+ storageType: 'localStorage',
671
+ key: args.key,
672
+ existedNote: result.result && !result.result.existed ? ' (key was not present)' : ''
673
+ });
674
+ }
675
+ case 'getSessionStorage': {
676
+ const result = await executeWithPauseDetection(targetCdpManager, () => page.evaluate((key) => {
677
+ if (key) {
678
+ return { [key]: sessionStorage.getItem(key) };
679
+ }
680
+ else {
681
+ const items = {};
682
+ for (let i = 0; i < sessionStorage.length; i++) {
683
+ const k = sessionStorage.key(i);
684
+ if (k) {
685
+ items[k] = sessionStorage.getItem(k);
686
+ }
687
+ }
688
+ return items;
689
+ }
690
+ }, args.key === undefined ? undefined : String(args.key)), 'getSessionStorage');
691
+ const markdown = `## sessionStorage\n\n${formatCodeBlock(result.result)}`;
692
+ return {
693
+ content: [
694
+ {
695
+ type: 'text',
696
+ text: markdown,
697
+ },
698
+ ],
699
+ _meta: {
700
+ tool: 'storage',
701
+ action,
702
+ timestamp: Date.now(),
703
+ storage: webStorageMeta(result.result, args.key),
704
+ },
705
+ };
706
+ }
707
+ case 'setSessionStorage': {
708
+ await executeWithPauseDetection(targetCdpManager, () => page.evaluate((key, value) => {
709
+ sessionStorage.setItem(key, value);
710
+ }, String(args.key), args.value), 'setSessionStorage');
711
+ return createSuccessResponse('SESSION_STORAGE_SET_SUCCESS', {
712
+ key: args.key,
713
+ value: args.value
714
+ });
715
+ }
716
+ case 'removeSessionStorage': {
717
+ const result = await executeWithPauseDetection(targetCdpManager, () => page.evaluate((key) => {
718
+ const existed = sessionStorage.getItem(key) !== null;
719
+ sessionStorage.removeItem(key);
720
+ return { existed };
721
+ }, String(args.key)), 'removeSessionStorage');
722
+ return createSuccessResponse('STORAGE_KEY_REMOVED', {
723
+ storageType: 'sessionStorage',
724
+ key: args.key,
725
+ existedNote: result.result && !result.result.existed ? ' (key was not present)' : ''
726
+ });
727
+ }
728
+ case 'idbListDatabases': {
729
+ const result = await runIdbOperation('idbListDatabases', {});
730
+ const idb = result.result;
731
+ if (!idb || !idb.ok) {
732
+ return createErrorResponse('INDEXEDDB_ERROR', { action, error: idb ? idb.error : 'No result returned from the page' });
733
+ }
734
+ const markdown = `## IndexedDB Databases\n\n**Count:** ${idb.databases.length}\n\n${formatCodeBlock(idb.databases)}`;
735
+ return { content: [{ type: 'text', text: markdown }] };
736
+ }
737
+ case 'idbListStores': {
738
+ const result = await runIdbOperation('idbListStores', { db: args.db });
739
+ const idb = result.result;
740
+ if (!idb || !idb.ok) {
741
+ return createErrorResponse('INDEXEDDB_ERROR', { action, error: idb ? idb.error : 'No result returned from the page' });
742
+ }
743
+ const markdown = `## IndexedDB Object Stores\n\n**Database:** ${idb.database} (v${idb.version})\n**Stores:** ${idb.stores.length}\n\n${formatCodeBlock(idb.stores)}`;
744
+ return { content: [{ type: 'text', text: markdown }] };
745
+ }
746
+ case 'idbGet': {
747
+ const result = await runIdbOperation('idbGet', { db: args.db, store: args.store, key: args.key });
748
+ const idb = result.result;
749
+ if (!idb || !idb.ok) {
750
+ return createErrorResponse('INDEXEDDB_ERROR', { action, error: idb ? idb.error : 'No result returned from the page' });
751
+ }
752
+ const markdown = idb.found
753
+ ? `## IndexedDB Record\n\n**Database:** ${idb.database}\n**Store:** ${idb.store}\n**Key:** ${JSON.stringify(idb.key)}\n\n${formatCodeBlock(idb.value)}`
754
+ : `## IndexedDB Record\n\n**Database:** ${idb.database}\n**Store:** ${idb.store}\n**Key:** ${JSON.stringify(idb.key)}\n\nNo record found for this key.`;
755
+ return {
756
+ content: [{ type: 'text', text: markdown }],
757
+ _meta: {
758
+ tool: 'storage',
759
+ action,
760
+ timestamp: Date.now(),
761
+ storage: { database: idb.database, store: idb.store, found: !!idb.found },
762
+ },
763
+ };
764
+ }
765
+ case 'idbGetAll': {
766
+ const limit = args.limit ?? 50;
767
+ const result = await runIdbOperation('idbGetAll', { db: args.db, store: args.store, limit });
768
+ const idb = result.result;
769
+ if (!idb || !idb.ok) {
770
+ return createErrorResponse('INDEXEDDB_ERROR', { action, error: idb ? idb.error : 'No result returned from the page' });
771
+ }
772
+ const truncatedNote = idb.truncated ? ` (showing ${idb.count} of ${idb.total}, raise "limit" to see more)` : '';
773
+ const markdown = `## IndexedDB Records\n\n**Database:** ${idb.database}\n**Store:** ${idb.store}\n**Count:** ${idb.count}${truncatedNote}\n\n${formatCodeBlock(idb.records)}`;
774
+ return {
775
+ content: [{ type: 'text', text: markdown }],
776
+ _meta: {
777
+ tool: 'storage',
778
+ action,
779
+ timestamp: Date.now(),
780
+ storage: {
781
+ database: idb.database,
782
+ store: idb.store,
783
+ count: idb.count,
784
+ ...(idb.total !== undefined && { total: idb.total }),
785
+ },
786
+ },
787
+ };
788
+ }
789
+ case 'idbPut': {
790
+ const result = await runIdbOperation('idbPut', {
791
+ db: args.db,
792
+ store: args.store,
793
+ key: args.key,
794
+ record: args.record,
795
+ });
796
+ const idb = result.result;
797
+ if (!idb || !idb.ok) {
798
+ return createErrorResponse('INDEXEDDB_ERROR', { action, error: idb ? idb.error : 'No result returned from the page' });
799
+ }
800
+ return createSuccessResponse('IDB_PUT_SUCCESS', {
801
+ db: idb.database,
802
+ store: idb.store,
803
+ key: JSON.stringify(idb.key)
804
+ }, args.record);
805
+ }
806
+ case 'idbDelete': {
807
+ const result = await runIdbOperation('idbDelete', { db: args.db, store: args.store, key: args.key });
808
+ const idb = result.result;
809
+ if (!idb || !idb.ok) {
810
+ return createErrorResponse('INDEXEDDB_ERROR', { action, error: idb ? idb.error : 'No result returned from the page' });
811
+ }
812
+ return createSuccessResponse('IDB_DELETE_SUCCESS', {
813
+ db: idb.database,
814
+ store: idb.store,
815
+ key: JSON.stringify(idb.key),
816
+ existedNote: idb.existed ? '' : ' (no record existed for this key)'
817
+ });
818
+ }
819
+ case 'clear': {
820
+ // Log the reason for audit purposes
821
+ const types = args.types || ['cookies', 'localStorage', 'sessionStorage'];
822
+ console.error(`[cdp-tools] clearStorage called - Reason: ${args.reason}, Types: ${types.join(', ')}, Connection: ${connectionReason || 'default'}`);
823
+ const result = await executeWithPauseDetection(targetCdpManager, async () => {
824
+ const cleared = [];
825
+ if (types.includes('cookies')) {
826
+ const cookies = await page.cookies();
827
+ if (cookies.length > 0) {
828
+ await page.deleteCookie(...cookies);
829
+ }
830
+ cleared.push('cookies');
831
+ }
832
+ if (types.includes('localStorage') || types.includes('sessionStorage')) {
833
+ await page.evaluate((storageTypes) => {
834
+ if (storageTypes.includes('localStorage')) {
835
+ localStorage.clear();
836
+ }
837
+ if (storageTypes.includes('sessionStorage')) {
838
+ sessionStorage.clear();
839
+ }
840
+ }, types);
841
+ if (types.includes('localStorage'))
842
+ cleared.push('localStorage');
843
+ if (types.includes('sessionStorage'))
844
+ cleared.push('sessionStorage');
845
+ }
846
+ if (types.includes('indexedDB')) {
847
+ const idbResult = await page.evaluate(async () => {
848
+ const indexedDB = globalThis.indexedDB;
849
+ if (!indexedDB || typeof indexedDB.databases !== 'function') {
850
+ return { supported: false, deleted: [], blocked: [] };
851
+ }
852
+ const dbs = await indexedDB.databases();
853
+ const deleted = [];
854
+ const blocked = [];
855
+ for (const info of dbs) {
856
+ if (!info.name)
857
+ continue;
858
+ // deleteDatabase never settles while another connection
859
+ // holds the database open, so bound the wait and report
860
+ // the survivors rather than hanging the tool.
861
+ const ok = await new Promise((resolve) => {
862
+ const req = indexedDB.deleteDatabase(info.name);
863
+ const done = (v) => resolve(v);
864
+ req.onsuccess = () => done(true);
865
+ req.onerror = () => done(false);
866
+ req.onblocked = () => done(false);
867
+ setTimeout(() => done(false), 3000);
868
+ });
869
+ (ok ? deleted : blocked).push(info.name);
870
+ }
871
+ return { supported: true, deleted, blocked };
872
+ });
873
+ if (idbResult.supported) {
874
+ cleared.push(`indexedDB (${idbResult.deleted.length} deleted${idbResult.blocked.length ? `, ${idbResult.blocked.length} blocked: ${idbResult.blocked.join(', ')}` : ''})`);
875
+ }
876
+ else {
877
+ cleared.push('indexedDB (skipped: indexedDB.databases() unsupported)');
878
+ }
879
+ }
880
+ return { cleared };
881
+ }, 'clearStorage');
882
+ if (!result.result) {
883
+ return createSuccessResponse('STORAGE_CLEARED', { types: types.join(', ') });
884
+ }
885
+ const storageResult = result.result;
886
+ return createSuccessResponse('STORAGE_CLEARED', { types: storageResult.cleared.join(', ') });
887
+ }
888
+ default:
889
+ return createErrorResponse('INVALID_ACTION', { action });
890
+ }
891
+ }),
892
+ };
893
+ }
894
+ //# sourceMappingURL=storage-tools.js.map