claude-chrome-parallel 1.0.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 (395) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +501 -0
  3. package/assets/demo.svg +278 -0
  4. package/dist/cdp/client.d.ts +218 -0
  5. package/dist/cdp/client.d.ts.map +1 -0
  6. package/dist/cdp/client.js +797 -0
  7. package/dist/cdp/client.js.map +1 -0
  8. package/dist/cdp/connection-pool.d.ts +125 -0
  9. package/dist/cdp/connection-pool.d.ts.map +1 -0
  10. package/dist/cdp/connection-pool.js +443 -0
  11. package/dist/cdp/connection-pool.js.map +1 -0
  12. package/dist/cdp/screenshot-scheduler.d.ts +54 -0
  13. package/dist/cdp/screenshot-scheduler.d.ts.map +1 -0
  14. package/dist/cdp/screenshot-scheduler.js +87 -0
  15. package/dist/cdp/screenshot-scheduler.js.map +1 -0
  16. package/dist/chrome/launcher.d.ts +55 -0
  17. package/dist/chrome/launcher.d.ts.map +1 -0
  18. package/dist/chrome/launcher.js +383 -0
  19. package/dist/chrome/launcher.js.map +1 -0
  20. package/dist/chrome/pool.d.ts +54 -0
  21. package/dist/chrome/pool.d.ts.map +1 -0
  22. package/dist/chrome/pool.js +301 -0
  23. package/dist/chrome/pool.js.map +1 -0
  24. package/dist/chrome/profile-detector.d.ts +52 -0
  25. package/dist/chrome/profile-detector.d.ts.map +1 -0
  26. package/dist/chrome/profile-detector.js +246 -0
  27. package/dist/chrome/profile-detector.js.map +1 -0
  28. package/dist/cli/claude-session.d.ts +11 -0
  29. package/dist/cli/claude-session.js +349 -0
  30. package/dist/cli/claude-session.js.map +1 -0
  31. package/dist/cli/index.d.ts +14 -0
  32. package/dist/cli/index.js +858 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/install.d.ts +16 -0
  35. package/dist/cli/install.js +185 -0
  36. package/dist/cli/install.js.map +1 -0
  37. package/dist/cli/uninstall.d.ts +7 -0
  38. package/dist/cli/uninstall.js +126 -0
  39. package/dist/cli/uninstall.js.map +1 -0
  40. package/dist/cli/update-check.d.ts +9 -0
  41. package/dist/cli/update-check.js +141 -0
  42. package/dist/cli/update-check.js.map +1 -0
  43. package/dist/config/config-recovery.d.ts +69 -0
  44. package/dist/config/config-recovery.d.ts.map +1 -0
  45. package/dist/config/config-recovery.js +302 -0
  46. package/dist/config/config-recovery.js.map +1 -0
  47. package/dist/config/global.d.ts +49 -0
  48. package/dist/config/global.d.ts.map +1 -0
  49. package/dist/config/global.js +24 -0
  50. package/dist/config/global.js.map +1 -0
  51. package/dist/config/index.d.ts +7 -0
  52. package/dist/config/index.d.ts.map +1 -0
  53. package/dist/config/index.js +23 -0
  54. package/dist/config/index.js.map +1 -0
  55. package/dist/config/session-isolator.d.ts +76 -0
  56. package/dist/config/session-isolator.d.ts.map +1 -0
  57. package/dist/config/session-isolator.js +268 -0
  58. package/dist/config/session-isolator.js.map +1 -0
  59. package/dist/dashboard/activity-tracker.d.ts +76 -0
  60. package/dist/dashboard/activity-tracker.d.ts.map +1 -0
  61. package/dist/dashboard/activity-tracker.js +219 -0
  62. package/dist/dashboard/activity-tracker.js.map +1 -0
  63. package/dist/dashboard/ansi.d.ts +117 -0
  64. package/dist/dashboard/ansi.d.ts.map +1 -0
  65. package/dist/dashboard/ansi.js +199 -0
  66. package/dist/dashboard/ansi.js.map +1 -0
  67. package/dist/dashboard/index.d.ts +110 -0
  68. package/dist/dashboard/index.d.ts.map +1 -0
  69. package/dist/dashboard/index.js +412 -0
  70. package/dist/dashboard/index.js.map +1 -0
  71. package/dist/dashboard/keyboard-handler.d.ts +43 -0
  72. package/dist/dashboard/keyboard-handler.d.ts.map +1 -0
  73. package/dist/dashboard/keyboard-handler.js +215 -0
  74. package/dist/dashboard/keyboard-handler.js.map +1 -0
  75. package/dist/dashboard/operation-controller.d.ts +76 -0
  76. package/dist/dashboard/operation-controller.d.ts.map +1 -0
  77. package/dist/dashboard/operation-controller.js +167 -0
  78. package/dist/dashboard/operation-controller.js.map +1 -0
  79. package/dist/dashboard/renderer.d.ts +76 -0
  80. package/dist/dashboard/renderer.d.ts.map +1 -0
  81. package/dist/dashboard/renderer.js +193 -0
  82. package/dist/dashboard/renderer.js.map +1 -0
  83. package/dist/dashboard/types.d.ts +56 -0
  84. package/dist/dashboard/types.d.ts.map +1 -0
  85. package/dist/dashboard/types.js +12 -0
  86. package/dist/dashboard/types.js.map +1 -0
  87. package/dist/dashboard/views/main-view.d.ts +23 -0
  88. package/dist/dashboard/views/main-view.d.ts.map +1 -0
  89. package/dist/dashboard/views/main-view.js +143 -0
  90. package/dist/dashboard/views/main-view.js.map +1 -0
  91. package/dist/dashboard/views/sessions-view.d.ts +22 -0
  92. package/dist/dashboard/views/sessions-view.d.ts.map +1 -0
  93. package/dist/dashboard/views/sessions-view.js +104 -0
  94. package/dist/dashboard/views/sessions-view.js.map +1 -0
  95. package/dist/dashboard/views/tabs-view.d.ts +21 -0
  96. package/dist/dashboard/views/tabs-view.d.ts.map +1 -0
  97. package/dist/dashboard/views/tabs-view.js +92 -0
  98. package/dist/dashboard/views/tabs-view.js.map +1 -0
  99. package/dist/hints/hint-engine.d.ts +77 -0
  100. package/dist/hints/hint-engine.d.ts.map +1 -0
  101. package/dist/hints/hint-engine.js +191 -0
  102. package/dist/hints/hint-engine.js.map +1 -0
  103. package/dist/hints/index.d.ts +8 -0
  104. package/dist/hints/index.d.ts.map +1 -0
  105. package/dist/hints/index.js +11 -0
  106. package/dist/hints/index.js.map +1 -0
  107. package/dist/hints/pattern-learner.d.ts +76 -0
  108. package/dist/hints/pattern-learner.d.ts.map +1 -0
  109. package/dist/hints/pattern-learner.js +254 -0
  110. package/dist/hints/pattern-learner.js.map +1 -0
  111. package/dist/hints/rules/composite-suggestions.d.ts +6 -0
  112. package/dist/hints/rules/composite-suggestions.d.ts.map +1 -0
  113. package/dist/hints/rules/composite-suggestions.js +66 -0
  114. package/dist/hints/rules/composite-suggestions.js.map +1 -0
  115. package/dist/hints/rules/error-recovery.d.ts +7 -0
  116. package/dist/hints/rules/error-recovery.d.ts.map +1 -0
  117. package/dist/hints/rules/error-recovery.js +55 -0
  118. package/dist/hints/rules/error-recovery.js.map +1 -0
  119. package/dist/hints/rules/learned-rules.d.ts +13 -0
  120. package/dist/hints/rules/learned-rules.d.ts.map +1 -0
  121. package/dist/hints/rules/learned-rules.js +27 -0
  122. package/dist/hints/rules/learned-rules.js.map +1 -0
  123. package/dist/hints/rules/repetition-detection.d.ts +7 -0
  124. package/dist/hints/rules/repetition-detection.d.ts.map +1 -0
  125. package/dist/hints/rules/repetition-detection.js +82 -0
  126. package/dist/hints/rules/repetition-detection.js.map +1 -0
  127. package/dist/hints/rules/sequence-detection.d.ts +6 -0
  128. package/dist/hints/rules/sequence-detection.d.ts.map +1 -0
  129. package/dist/hints/rules/sequence-detection.js +89 -0
  130. package/dist/hints/rules/sequence-detection.js.map +1 -0
  131. package/dist/hints/rules/success-hints.d.ts +6 -0
  132. package/dist/hints/rules/success-hints.d.ts.map +1 -0
  133. package/dist/hints/rules/success-hints.js +62 -0
  134. package/dist/hints/rules/success-hints.js.map +1 -0
  135. package/dist/index.d.ts +10 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +272 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/lightpanda/launcher.d.ts +58 -0
  140. package/dist/lightpanda/launcher.d.ts.map +1 -0
  141. package/dist/lightpanda/launcher.js +199 -0
  142. package/dist/lightpanda/launcher.js.map +1 -0
  143. package/dist/mcp-server.d.ts +129 -0
  144. package/dist/mcp-server.d.ts.map +1 -0
  145. package/dist/mcp-server.js +641 -0
  146. package/dist/mcp-server.js.map +1 -0
  147. package/dist/memory/domain-memory.d.ts +68 -0
  148. package/dist/memory/domain-memory.d.ts.map +1 -0
  149. package/dist/memory/domain-memory.js +227 -0
  150. package/dist/memory/domain-memory.js.map +1 -0
  151. package/dist/orchestration/plan-executor.d.ts +19 -0
  152. package/dist/orchestration/plan-executor.d.ts.map +1 -0
  153. package/dist/orchestration/plan-executor.js +284 -0
  154. package/dist/orchestration/plan-executor.js.map +1 -0
  155. package/dist/orchestration/plan-registry.d.ts +55 -0
  156. package/dist/orchestration/plan-registry.d.ts.map +1 -0
  157. package/dist/orchestration/plan-registry.js +255 -0
  158. package/dist/orchestration/plan-registry.js.map +1 -0
  159. package/dist/orchestration/state-manager.d.ts +127 -0
  160. package/dist/orchestration/state-manager.d.ts.map +1 -0
  161. package/dist/orchestration/state-manager.js +438 -0
  162. package/dist/orchestration/state-manager.js.map +1 -0
  163. package/dist/orchestration/workflow-engine.d.ts +162 -0
  164. package/dist/orchestration/workflow-engine.d.ts.map +1 -0
  165. package/dist/orchestration/workflow-engine.js +731 -0
  166. package/dist/orchestration/workflow-engine.js.map +1 -0
  167. package/dist/resources/usage-guide.d.ts +13 -0
  168. package/dist/resources/usage-guide.d.ts.map +1 -0
  169. package/dist/resources/usage-guide.js +101 -0
  170. package/dist/resources/usage-guide.js.map +1 -0
  171. package/dist/router/browser-router.d.ts +51 -0
  172. package/dist/router/browser-router.d.ts.map +1 -0
  173. package/dist/router/browser-router.js +178 -0
  174. package/dist/router/browser-router.js.map +1 -0
  175. package/dist/router/cookie-sync.d.ts +48 -0
  176. package/dist/router/cookie-sync.d.ts.map +1 -0
  177. package/dist/router/cookie-sync.js +106 -0
  178. package/dist/router/cookie-sync.js.map +1 -0
  179. package/dist/router/index.d.ts +5 -0
  180. package/dist/router/index.d.ts.map +1 -0
  181. package/dist/router/index.js +10 -0
  182. package/dist/router/index.js.map +1 -0
  183. package/dist/router/tool-routing-registry.d.ts +21 -0
  184. package/dist/router/tool-routing-registry.d.ts.map +1 -0
  185. package/dist/router/tool-routing-registry.js +90 -0
  186. package/dist/router/tool-routing-registry.js.map +1 -0
  187. package/dist/session-manager.d.ts +251 -0
  188. package/dist/session-manager.d.ts.map +1 -0
  189. package/dist/session-manager.js +912 -0
  190. package/dist/session-manager.js.map +1 -0
  191. package/dist/tools/batch-execute.d.ts +11 -0
  192. package/dist/tools/batch-execute.d.ts.map +1 -0
  193. package/dist/tools/batch-execute.js +226 -0
  194. package/dist/tools/batch-execute.js.map +1 -0
  195. package/dist/tools/click-element.d.ts +8 -0
  196. package/dist/tools/click-element.d.ts.map +1 -0
  197. package/dist/tools/click-element.js +455 -0
  198. package/dist/tools/click-element.js.map +1 -0
  199. package/dist/tools/computer.d.ts +6 -0
  200. package/dist/tools/computer.d.ts.map +1 -0
  201. package/dist/tools/computer.js +638 -0
  202. package/dist/tools/computer.js.map +1 -0
  203. package/dist/tools/console-capture.d.ts +6 -0
  204. package/dist/tools/console-capture.d.ts.map +1 -0
  205. package/dist/tools/console-capture.js +320 -0
  206. package/dist/tools/console-capture.js.map +1 -0
  207. package/dist/tools/cookies.d.ts +6 -0
  208. package/dist/tools/cookies.d.ts.map +1 -0
  209. package/dist/tools/cookies.js +263 -0
  210. package/dist/tools/cookies.js.map +1 -0
  211. package/dist/tools/drag-drop.d.ts +6 -0
  212. package/dist/tools/drag-drop.d.ts.map +1 -0
  213. package/dist/tools/drag-drop.js +252 -0
  214. package/dist/tools/drag-drop.js.map +1 -0
  215. package/dist/tools/emulate-device.d.ts +6 -0
  216. package/dist/tools/emulate-device.d.ts.map +1 -0
  217. package/dist/tools/emulate-device.js +221 -0
  218. package/dist/tools/emulate-device.js.map +1 -0
  219. package/dist/tools/file-upload.d.ts +6 -0
  220. package/dist/tools/file-upload.d.ts.map +1 -0
  221. package/dist/tools/file-upload.js +208 -0
  222. package/dist/tools/file-upload.js.map +1 -0
  223. package/dist/tools/fill-form.d.ts +8 -0
  224. package/dist/tools/fill-form.d.ts.map +1 -0
  225. package/dist/tools/fill-form.js +342 -0
  226. package/dist/tools/fill-form.js.map +1 -0
  227. package/dist/tools/find.d.ts +6 -0
  228. package/dist/tools/find.d.ts.map +1 -0
  229. package/dist/tools/find.js +330 -0
  230. package/dist/tools/find.js.map +1 -0
  231. package/dist/tools/form-input.d.ts +6 -0
  232. package/dist/tools/form-input.d.ts.map +1 -0
  233. package/dist/tools/form-input.js +181 -0
  234. package/dist/tools/form-input.js.map +1 -0
  235. package/dist/tools/geolocation.d.ts +6 -0
  236. package/dist/tools/geolocation.d.ts.map +1 -0
  237. package/dist/tools/geolocation.js +172 -0
  238. package/dist/tools/geolocation.js.map +1 -0
  239. package/dist/tools/http-auth.d.ts +6 -0
  240. package/dist/tools/http-auth.d.ts.map +1 -0
  241. package/dist/tools/http-auth.js +136 -0
  242. package/dist/tools/http-auth.js.map +1 -0
  243. package/dist/tools/index.d.ts +6 -0
  244. package/dist/tools/index.d.ts.map +1 -0
  245. package/dist/tools/index.js +104 -0
  246. package/dist/tools/index.js.map +1 -0
  247. package/dist/tools/javascript.d.ts +6 -0
  248. package/dist/tools/javascript.d.ts.map +1 -0
  249. package/dist/tools/javascript.js +138 -0
  250. package/dist/tools/javascript.js.map +1 -0
  251. package/dist/tools/lightweight-scroll.d.ts +11 -0
  252. package/dist/tools/lightweight-scroll.d.ts.map +1 -0
  253. package/dist/tools/lightweight-scroll.js +266 -0
  254. package/dist/tools/lightweight-scroll.js.map +1 -0
  255. package/dist/tools/memory.d.ts +10 -0
  256. package/dist/tools/memory.d.ts.map +1 -0
  257. package/dist/tools/memory.js +141 -0
  258. package/dist/tools/memory.js.map +1 -0
  259. package/dist/tools/navigate.d.ts +6 -0
  260. package/dist/tools/navigate.d.ts.map +1 -0
  261. package/dist/tools/navigate.js +241 -0
  262. package/dist/tools/navigate.js.map +1 -0
  263. package/dist/tools/network.d.ts +6 -0
  264. package/dist/tools/network.d.ts.map +1 -0
  265. package/dist/tools/network.js +215 -0
  266. package/dist/tools/network.js.map +1 -0
  267. package/dist/tools/orchestration.d.ts +6 -0
  268. package/dist/tools/orchestration.d.ts.map +1 -0
  269. package/dist/tools/orchestration.js +746 -0
  270. package/dist/tools/orchestration.js.map +1 -0
  271. package/dist/tools/page-content.d.ts +6 -0
  272. package/dist/tools/page-content.d.ts.map +1 -0
  273. package/dist/tools/page-content.js +120 -0
  274. package/dist/tools/page-content.js.map +1 -0
  275. package/dist/tools/page-pdf.d.ts +6 -0
  276. package/dist/tools/page-pdf.d.ts.map +1 -0
  277. package/dist/tools/page-pdf.js +245 -0
  278. package/dist/tools/page-pdf.js.map +1 -0
  279. package/dist/tools/page-reload.d.ts +6 -0
  280. package/dist/tools/page-reload.d.ts.map +1 -0
  281. package/dist/tools/page-reload.js +89 -0
  282. package/dist/tools/page-reload.js.map +1 -0
  283. package/dist/tools/performance-metrics.d.ts +6 -0
  284. package/dist/tools/performance-metrics.d.ts.map +1 -0
  285. package/dist/tools/performance-metrics.js +158 -0
  286. package/dist/tools/performance-metrics.js.map +1 -0
  287. package/dist/tools/read-page.d.ts +6 -0
  288. package/dist/tools/read-page.d.ts.map +1 -0
  289. package/dist/tools/read-page.js +287 -0
  290. package/dist/tools/read-page.js.map +1 -0
  291. package/dist/tools/request-intercept.d.ts +6 -0
  292. package/dist/tools/request-intercept.d.ts.map +1 -0
  293. package/dist/tools/request-intercept.js +439 -0
  294. package/dist/tools/request-intercept.js.map +1 -0
  295. package/dist/tools/selector-query.d.ts +6 -0
  296. package/dist/tools/selector-query.d.ts.map +1 -0
  297. package/dist/tools/selector-query.js +206 -0
  298. package/dist/tools/selector-query.js.map +1 -0
  299. package/dist/tools/shutdown.d.ts +12 -0
  300. package/dist/tools/shutdown.d.ts.map +1 -0
  301. package/dist/tools/shutdown.js +120 -0
  302. package/dist/tools/shutdown.js.map +1 -0
  303. package/dist/tools/storage.d.ts +6 -0
  304. package/dist/tools/storage.d.ts.map +1 -0
  305. package/dist/tools/storage.js +264 -0
  306. package/dist/tools/storage.js.map +1 -0
  307. package/dist/tools/tabs-close.d.ts +6 -0
  308. package/dist/tools/tabs-close.d.ts.map +1 -0
  309. package/dist/tools/tabs-close.js +124 -0
  310. package/dist/tools/tabs-close.js.map +1 -0
  311. package/dist/tools/tabs-context.d.ts +6 -0
  312. package/dist/tools/tabs-context.d.ts.map +1 -0
  313. package/dist/tools/tabs-context.js +92 -0
  314. package/dist/tools/tabs-context.js.map +1 -0
  315. package/dist/tools/tabs-create.d.ts +6 -0
  316. package/dist/tools/tabs-create.d.ts.map +1 -0
  317. package/dist/tools/tabs-create.js +73 -0
  318. package/dist/tools/tabs-create.js.map +1 -0
  319. package/dist/tools/user-agent.d.ts +6 -0
  320. package/dist/tools/user-agent.d.ts.map +1 -0
  321. package/dist/tools/user-agent.js +128 -0
  322. package/dist/tools/user-agent.js.map +1 -0
  323. package/dist/tools/wait-and-click.d.ts +8 -0
  324. package/dist/tools/wait-and-click.d.ts.map +1 -0
  325. package/dist/tools/wait-and-click.js +290 -0
  326. package/dist/tools/wait-and-click.js.map +1 -0
  327. package/dist/tools/wait-for.d.ts +6 -0
  328. package/dist/tools/wait-for.d.ts.map +1 -0
  329. package/dist/tools/wait-for.js +248 -0
  330. package/dist/tools/wait-for.js.map +1 -0
  331. package/dist/tools/worker-create.d.ts +7 -0
  332. package/dist/tools/worker-create.d.ts.map +1 -0
  333. package/dist/tools/worker-create.js +62 -0
  334. package/dist/tools/worker-create.js.map +1 -0
  335. package/dist/tools/worker-delete.d.ts +6 -0
  336. package/dist/tools/worker-delete.d.ts.map +1 -0
  337. package/dist/tools/worker-delete.js +80 -0
  338. package/dist/tools/worker-delete.js.map +1 -0
  339. package/dist/tools/worker-list.d.ts +6 -0
  340. package/dist/tools/worker-list.d.ts.map +1 -0
  341. package/dist/tools/worker-list.js +67 -0
  342. package/dist/tools/worker-list.js.map +1 -0
  343. package/dist/tools/xpath-query.d.ts +6 -0
  344. package/dist/tools/xpath-query.d.ts.map +1 -0
  345. package/dist/tools/xpath-query.js +230 -0
  346. package/dist/tools/xpath-query.js.map +1 -0
  347. package/dist/types/browser-backend.d.ts +30 -0
  348. package/dist/types/browser-backend.d.ts.map +1 -0
  349. package/dist/types/browser-backend.js +9 -0
  350. package/dist/types/browser-backend.js.map +1 -0
  351. package/dist/types/index.d.ts +3 -0
  352. package/dist/types/index.d.ts.map +1 -0
  353. package/dist/types/index.js +19 -0
  354. package/dist/types/index.js.map +1 -0
  355. package/dist/types/mcp.d.ts +54 -0
  356. package/dist/types/mcp.d.ts.map +1 -0
  357. package/dist/types/mcp.js +14 -0
  358. package/dist/types/mcp.js.map +1 -0
  359. package/dist/types/plan-cache.d.ts +121 -0
  360. package/dist/types/plan-cache.d.ts.map +1 -0
  361. package/dist/types/plan-cache.js +9 -0
  362. package/dist/types/plan-cache.js.map +1 -0
  363. package/dist/types/profile.d.ts +76 -0
  364. package/dist/types/profile.d.ts.map +1 -0
  365. package/dist/types/profile.js +35 -0
  366. package/dist/types/profile.js.map +1 -0
  367. package/dist/types/session.d.ts +65 -0
  368. package/dist/types/session.d.ts.map +1 -0
  369. package/dist/types/session.js +6 -0
  370. package/dist/types/session.js.map +1 -0
  371. package/dist/types/tool-manifest.d.ts +52 -0
  372. package/dist/types/tool-manifest.d.ts.map +1 -0
  373. package/dist/types/tool-manifest.js +37 -0
  374. package/dist/types/tool-manifest.js.map +1 -0
  375. package/dist/utils/atomic-file.d.ts +50 -0
  376. package/dist/utils/atomic-file.d.ts.map +1 -0
  377. package/dist/utils/atomic-file.js +217 -0
  378. package/dist/utils/atomic-file.js.map +1 -0
  379. package/dist/utils/index.d.ts +6 -0
  380. package/dist/utils/index.d.ts.map +1 -0
  381. package/dist/utils/index.js +22 -0
  382. package/dist/utils/index.js.map +1 -0
  383. package/dist/utils/json-validator.d.ts +40 -0
  384. package/dist/utils/json-validator.d.ts.map +1 -0
  385. package/dist/utils/json-validator.js +295 -0
  386. package/dist/utils/json-validator.js.map +1 -0
  387. package/dist/utils/ref-id-manager.d.ts +26 -0
  388. package/dist/utils/ref-id-manager.d.ts.map +1 -0
  389. package/dist/utils/ref-id-manager.js +81 -0
  390. package/dist/utils/ref-id-manager.js.map +1 -0
  391. package/dist/utils/request-queue.d.ts +37 -0
  392. package/dist/utils/request-queue.d.ts.map +1 -0
  393. package/dist/utils/request-queue.js +110 -0
  394. package/dist/utils/request-queue.js.map +1 -0
  395. package/package.json +78 -0
@@ -0,0 +1,912 @@
1
+ "use strict";
2
+ /**
3
+ * Session Manager - Manages lifecycle of parallel Claude Code sessions
4
+ * Supports multiple Workers within a single session for parallel browser operations
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.SessionManager = void 0;
8
+ exports.getSessionManager = getSessionManager;
9
+ const client_1 = require("./cdp/client");
10
+ const connection_pool_1 = require("./cdp/connection-pool");
11
+ const pool_1 = require("./chrome/pool");
12
+ const global_1 = require("./config/global");
13
+ const request_queue_1 = require("./utils/request-queue");
14
+ const ref_id_manager_1 = require("./utils/ref-id-manager");
15
+ const router_1 = require("./router");
16
+ // Helper to get target ID (internal puppeteer property)
17
+ function getTargetId(target) {
18
+ return target._targetId;
19
+ }
20
+ const DEFAULT_CONFIG = {
21
+ sessionTTL: 30 * 60 * 1000, // 30 minutes
22
+ cleanupInterval: 60 * 1000, // 1 minute
23
+ autoCleanup: true,
24
+ maxSessions: 100,
25
+ maxWorkersPerSession: 50,
26
+ useConnectionPool: true, // Enabled by default for faster page creation
27
+ useDefaultContext: true, // Use Chrome profile's cookies/sessions by default
28
+ usePool: false, // Disabled by default; enable for multi-Chrome origin isolation
29
+ };
30
+ class SessionManager {
31
+ sessions = new Map();
32
+ targetToWorker = new Map();
33
+ cdpClient;
34
+ connectionPool = null;
35
+ chromePool = null;
36
+ cdpFactory;
37
+ queueManager;
38
+ eventListeners = [];
39
+ browserRouter = null;
40
+ // TTL & Stats
41
+ config;
42
+ cleanupTimer = null;
43
+ startTime = Date.now();
44
+ totalSessionsCreated = 0;
45
+ totalSessionsCleaned = 0;
46
+ lastCleanupTime = null;
47
+ constructor(cdpClient, config) {
48
+ this.cdpClient = cdpClient || (0, client_1.getCDPClient)();
49
+ this.queueManager = new request_queue_1.RequestQueueManager();
50
+ this.config = { ...DEFAULT_CONFIG, ...config };
51
+ this.cdpFactory = (0, client_1.getCDPClientFactory)();
52
+ if (this.config.useConnectionPool) {
53
+ this.connectionPool = (0, connection_pool_1.getCDPConnectionPool)();
54
+ }
55
+ if (this.config.usePool) {
56
+ this.chromePool = (0, pool_1.getChromePool)({ autoLaunch: (0, global_1.getGlobalConfig)().autoLaunch });
57
+ }
58
+ if (this.config.autoCleanup) {
59
+ this.startAutoCleanup();
60
+ }
61
+ // Register target destroyed listener
62
+ this.cdpClient.addTargetDestroyedListener((targetId) => {
63
+ this.onTargetClosed(targetId);
64
+ });
65
+ }
66
+ /**
67
+ * Get the CDPClient for a specific worker (may be on a different Chrome instance)
68
+ */
69
+ getCDPClientForWorker(sessionId, workerId) {
70
+ const worker = this.getWorker(sessionId, workerId);
71
+ if (worker?.port) {
72
+ const client = this.cdpFactory.get(worker.port);
73
+ if (client)
74
+ return client;
75
+ }
76
+ return this.cdpClient;
77
+ }
78
+ /**
79
+ * Start automatic cleanup interval
80
+ */
81
+ startAutoCleanup() {
82
+ if (this.cleanupTimer) {
83
+ clearInterval(this.cleanupTimer);
84
+ }
85
+ this.cleanupTimer = setInterval(async () => {
86
+ try {
87
+ const deleted = await this.cleanupInactiveSessions(this.config.sessionTTL);
88
+ if (deleted.length > 0) {
89
+ console.error(`[SessionManager] Auto-cleanup: removed ${deleted.length} inactive session(s)`);
90
+ }
91
+ this.lastCleanupTime = Date.now();
92
+ }
93
+ catch (error) {
94
+ console.error('[SessionManager] Auto-cleanup error:', error);
95
+ }
96
+ }, this.config.cleanupInterval);
97
+ // Don't prevent process exit
98
+ this.cleanupTimer.unref();
99
+ }
100
+ /**
101
+ * Stop automatic cleanup
102
+ */
103
+ stopAutoCleanup() {
104
+ if (this.cleanupTimer) {
105
+ clearInterval(this.cleanupTimer);
106
+ this.cleanupTimer = null;
107
+ }
108
+ }
109
+ /**
110
+ * Get session manager statistics
111
+ */
112
+ getStats() {
113
+ let totalTargets = 0;
114
+ let totalWorkers = 0;
115
+ for (const session of this.sessions.values()) {
116
+ totalWorkers += session.workers.size;
117
+ for (const worker of session.workers.values()) {
118
+ totalTargets += worker.targets.size;
119
+ }
120
+ // Also count legacy targets
121
+ totalTargets += session.targets.size;
122
+ }
123
+ const stats = {
124
+ activeSessions: this.sessions.size,
125
+ totalTargets,
126
+ totalWorkers,
127
+ totalSessionsCreated: this.totalSessionsCreated,
128
+ totalSessionsCleaned: this.totalSessionsCleaned,
129
+ uptime: Date.now() - this.startTime,
130
+ lastCleanup: this.lastCleanupTime,
131
+ memoryUsage: process.memoryUsage().heapUsed,
132
+ };
133
+ if (this.connectionPool) {
134
+ stats.connectionPool = this.connectionPool.getStats();
135
+ }
136
+ return stats;
137
+ }
138
+ /**
139
+ * Get current configuration
140
+ */
141
+ getConfig() {
142
+ return { ...this.config };
143
+ }
144
+ /**
145
+ * Update configuration
146
+ */
147
+ updateConfig(config) {
148
+ this.config = { ...this.config, ...config };
149
+ // Restart cleanup timer if interval changed
150
+ if (config.cleanupInterval !== undefined || config.autoCleanup !== undefined) {
151
+ this.stopAutoCleanup();
152
+ if (this.config.autoCleanup) {
153
+ this.startAutoCleanup();
154
+ }
155
+ }
156
+ }
157
+ /**
158
+ * Ensure connected to Chrome
159
+ */
160
+ async ensureConnected() {
161
+ if (!this.cdpClient.isConnected()) {
162
+ await this.cdpClient.connect();
163
+ }
164
+ }
165
+ // ==================== SESSION MANAGEMENT ====================
166
+ /**
167
+ * Create a new session with a default worker
168
+ */
169
+ async createSession(options = {}) {
170
+ await this.ensureConnected();
171
+ const id = options.id || crypto.randomUUID();
172
+ if (this.sessions.has(id)) {
173
+ return this.sessions.get(id);
174
+ }
175
+ // Check max sessions limit
176
+ if (this.sessions.size >= this.config.maxSessions) {
177
+ const deleted = await this.cleanupInactiveSessions(this.config.sessionTTL);
178
+ if (deleted.length === 0 && this.sessions.size >= this.config.maxSessions) {
179
+ throw new Error(`Maximum session limit (${this.config.maxSessions}) reached.`);
180
+ }
181
+ }
182
+ const name = options.name || `Session ${id.slice(0, 8)}`;
183
+ const defaultWorkerId = 'default';
184
+ // Create default worker - use default context if configured (shares Chrome profile's cookies)
185
+ // or create isolated browser context for session isolation
186
+ const defaultContext = this.config.useDefaultContext
187
+ ? null // null means use default browser context (shares cookies with Chrome profile)
188
+ : await this.cdpClient.createBrowserContext();
189
+ const defaultWorker = {
190
+ id: defaultWorkerId,
191
+ name: 'Default Worker',
192
+ targets: new Set(),
193
+ context: defaultContext,
194
+ createdAt: Date.now(),
195
+ lastActivityAt: Date.now(),
196
+ };
197
+ const session = {
198
+ id,
199
+ workers: new Map([[defaultWorkerId, defaultWorker]]),
200
+ defaultWorkerId,
201
+ targets: new Set(), // Legacy support
202
+ createdAt: Date.now(),
203
+ lastActivityAt: Date.now(),
204
+ name,
205
+ context: defaultContext, // Legacy support
206
+ };
207
+ this.sessions.set(id, session);
208
+ this.totalSessionsCreated++;
209
+ this.emitEvent({ type: 'session:created', sessionId: id, timestamp: Date.now() });
210
+ console.error(`[SessionManager] Created session ${id} with default worker`);
211
+ return session;
212
+ }
213
+ /**
214
+ * Get or create a session
215
+ */
216
+ async getOrCreateSession(sessionId) {
217
+ let session = this.sessions.get(sessionId);
218
+ if (!session) {
219
+ session = await this.createSession({ id: sessionId });
220
+ }
221
+ return session;
222
+ }
223
+ /**
224
+ * Get an existing session
225
+ */
226
+ getSession(sessionId) {
227
+ return this.sessions.get(sessionId);
228
+ }
229
+ /**
230
+ * Update last activity timestamp
231
+ */
232
+ touchSession(sessionId) {
233
+ const session = this.sessions.get(sessionId);
234
+ if (session) {
235
+ session.lastActivityAt = Date.now();
236
+ }
237
+ }
238
+ /**
239
+ * Delete a session and clean up all workers
240
+ */
241
+ async deleteSession(sessionId) {
242
+ const session = this.sessions.get(sessionId);
243
+ if (!session) {
244
+ return;
245
+ }
246
+ // Delete all workers
247
+ for (const workerId of session.workers.keys()) {
248
+ await this.deleteWorkerInternal(session, workerId);
249
+ }
250
+ // Clean up all worker queues
251
+ for (const workerId of session.workers.keys()) {
252
+ this.queueManager.deleteQueue(`${sessionId}:${workerId}`);
253
+ }
254
+ this.queueManager.deleteQueue(sessionId);
255
+ // Clean up ref IDs
256
+ (0, ref_id_manager_1.getRefIdManager)().clearSessionRefs(sessionId);
257
+ // Remove session
258
+ this.sessions.delete(sessionId);
259
+ this.emitEvent({ type: 'session:deleted', sessionId, timestamp: Date.now() });
260
+ console.error(`[SessionManager] Deleted session ${sessionId}`);
261
+ }
262
+ /**
263
+ * Clean up inactive sessions
264
+ */
265
+ async cleanupInactiveSessions(maxAgeMs) {
266
+ const now = Date.now();
267
+ const deletedSessions = [];
268
+ for (const [sessionId, session] of this.sessions) {
269
+ if (now - session.lastActivityAt > maxAgeMs) {
270
+ await this.deleteSession(sessionId);
271
+ deletedSessions.push(sessionId);
272
+ this.totalSessionsCleaned++;
273
+ }
274
+ }
275
+ // Trigger browser-level GC after bulk cleanup
276
+ if (deletedSessions.length > 0) {
277
+ try {
278
+ const pages = await this.cdpClient.getPages();
279
+ if (pages.length > 0) {
280
+ await this.cdpClient.triggerGC(pages[0]);
281
+ }
282
+ }
283
+ catch {
284
+ // Best-effort GC
285
+ }
286
+ }
287
+ return deletedSessions;
288
+ }
289
+ /**
290
+ * Force cleanup all sessions
291
+ */
292
+ async cleanupAllSessions() {
293
+ const count = this.sessions.size;
294
+ const sessionIds = Array.from(this.sessions.keys());
295
+ for (const sessionId of sessionIds) {
296
+ await this.deleteSession(sessionId);
297
+ this.totalSessionsCleaned++;
298
+ }
299
+ // Clean up Chrome pool and factory connections
300
+ if (this.chromePool) {
301
+ await this.chromePool.cleanup();
302
+ }
303
+ await this.cdpFactory.disconnectAll();
304
+ return count;
305
+ }
306
+ // ==================== WORKER MANAGEMENT ====================
307
+ /**
308
+ * Create a new worker within a session
309
+ * Each worker has its own isolated browser context (cookies, localStorage, etc.)
310
+ */
311
+ async createWorker(sessionId, options = {}) {
312
+ await this.ensureConnected();
313
+ const session = await this.getOrCreateSession(sessionId);
314
+ // Check max workers limit
315
+ if (session.workers.size >= this.config.maxWorkersPerSession) {
316
+ throw new Error(`Maximum workers per session (${this.config.maxWorkersPerSession}) reached.`);
317
+ }
318
+ const workerId = options.id || `worker-${crypto.randomUUID().slice(0, 8)}`;
319
+ if (session.workers.has(workerId)) {
320
+ return session.workers.get(workerId);
321
+ }
322
+ const name = options.name || `Worker ${workerId}`;
323
+ // Create browser context: shared (null = copies cookies from Chrome profile) or isolated
324
+ const context = options.shareCookies
325
+ ? null
326
+ : await this.cdpClient.createBrowserContext();
327
+ // If pool is enabled and targetUrl provided, acquire a separate Chrome instance
328
+ let workerPort;
329
+ let workerPoolOrigin;
330
+ if (this.chromePool && options.targetUrl) {
331
+ try {
332
+ const origin = new URL(options.targetUrl).origin;
333
+ const poolInstance = await this.chromePool.acquireInstance(origin);
334
+ workerPort = poolInstance.port;
335
+ workerPoolOrigin = origin;
336
+ // Ensure CDPClient for this port is connected
337
+ const workerCdpClient = this.cdpFactory.getOrCreate(workerPort, {
338
+ autoLaunch: (0, global_1.getGlobalConfig)().autoLaunch,
339
+ });
340
+ if (!workerCdpClient.isConnected()) {
341
+ await workerCdpClient.connect();
342
+ }
343
+ console.error(`[SessionManager] Worker ${workerId} assigned to Chrome instance on port ${workerPort} for origin ${origin}`);
344
+ }
345
+ catch (err) {
346
+ console.error(`[SessionManager] Pool acquisition failed, falling back to default:`, err);
347
+ workerPort = undefined;
348
+ workerPoolOrigin = undefined;
349
+ }
350
+ }
351
+ const worker = {
352
+ id: workerId,
353
+ name,
354
+ targets: new Set(),
355
+ context,
356
+ createdAt: Date.now(),
357
+ lastActivityAt: Date.now(),
358
+ port: workerPort,
359
+ poolOrigin: workerPoolOrigin,
360
+ };
361
+ session.workers.set(workerId, worker);
362
+ this.touchSession(sessionId);
363
+ this.emitEvent({
364
+ type: 'worker:created',
365
+ sessionId,
366
+ workerId,
367
+ timestamp: Date.now(),
368
+ });
369
+ console.error(`[SessionManager] Created worker ${workerId} in session ${sessionId}`);
370
+ return worker;
371
+ }
372
+ /**
373
+ * Get a worker by ID
374
+ */
375
+ getWorker(sessionId, workerId) {
376
+ const session = this.sessions.get(sessionId);
377
+ if (!session)
378
+ return undefined;
379
+ return session.workers.get(workerId);
380
+ }
381
+ /**
382
+ * Get or create a worker
383
+ */
384
+ async getOrCreateWorker(sessionId, workerId) {
385
+ const session = await this.getOrCreateSession(sessionId);
386
+ // If no workerId specified, use default worker
387
+ const targetWorkerId = workerId || session.defaultWorkerId;
388
+ let worker = session.workers.get(targetWorkerId);
389
+ if (!worker) {
390
+ worker = await this.createWorker(sessionId, { id: targetWorkerId });
391
+ }
392
+ return worker;
393
+ }
394
+ /**
395
+ * List all workers in a session
396
+ */
397
+ getWorkers(sessionId) {
398
+ const session = this.sessions.get(sessionId);
399
+ if (!session)
400
+ return [];
401
+ const workers = [];
402
+ for (const worker of session.workers.values()) {
403
+ workers.push({
404
+ id: worker.id,
405
+ name: worker.name,
406
+ targetCount: worker.targets.size,
407
+ createdAt: worker.createdAt,
408
+ lastActivityAt: worker.lastActivityAt,
409
+ });
410
+ }
411
+ return workers;
412
+ }
413
+ /**
414
+ * Delete a worker and its resources
415
+ */
416
+ async deleteWorker(sessionId, workerId) {
417
+ const session = this.sessions.get(sessionId);
418
+ if (!session)
419
+ return;
420
+ // Can't delete default worker
421
+ if (workerId === session.defaultWorkerId) {
422
+ throw new Error('Cannot delete the default worker. Delete the session instead.');
423
+ }
424
+ await this.deleteWorkerInternal(session, workerId);
425
+ this.emitEvent({
426
+ type: 'worker:deleted',
427
+ sessionId,
428
+ workerId,
429
+ timestamp: Date.now(),
430
+ });
431
+ }
432
+ /**
433
+ * Internal worker deletion (also used for cleanup)
434
+ */
435
+ async deleteWorkerInternal(session, workerId) {
436
+ const worker = session.workers.get(workerId);
437
+ if (!worker)
438
+ return;
439
+ // Determine which CDPClient to use for this worker
440
+ const workerCdpClient = worker.port
441
+ ? (this.cdpFactory.get(worker.port) || this.cdpClient)
442
+ : this.cdpClient;
443
+ // Close all pages in this worker (return to pool if available)
444
+ for (const targetId of worker.targets) {
445
+ try {
446
+ if (this.connectionPool && this.config.useConnectionPool) {
447
+ const page = await workerCdpClient.getPageByTargetId(targetId);
448
+ if (page && !page.isClosed()) {
449
+ await this.connectionPool.releasePage(page);
450
+ }
451
+ else {
452
+ await workerCdpClient.closePage(targetId);
453
+ }
454
+ }
455
+ else {
456
+ await workerCdpClient.closePage(targetId);
457
+ }
458
+ }
459
+ catch {
460
+ // Page might already be closed
461
+ }
462
+ this.targetToWorker.delete(targetId);
463
+ }
464
+ // Close the browser context (only if it's an isolated context, not the default)
465
+ if (worker.context) {
466
+ try {
467
+ await workerCdpClient.closeBrowserContext(worker.context);
468
+ }
469
+ catch {
470
+ // Context might already be closed
471
+ }
472
+ }
473
+ // Release Chrome pool instance if worker had one
474
+ if (worker.port && worker.poolOrigin && this.chromePool) {
475
+ this.chromePool.releaseInstance(worker.port, worker.poolOrigin);
476
+ console.error(`[SessionManager] Released pool instance port ${worker.port} for origin ${worker.poolOrigin}`);
477
+ }
478
+ // Clean up ref IDs for this worker
479
+ for (const targetId of worker.targets) {
480
+ (0, ref_id_manager_1.getRefIdManager)().clearTargetRefs(session.id, targetId);
481
+ }
482
+ session.workers.delete(workerId);
483
+ console.error(`[SessionManager] Deleted worker ${workerId} from session ${session.id}`);
484
+ }
485
+ // ==================== TARGET/PAGE MANAGEMENT ====================
486
+ /**
487
+ * Create a new page/target for a worker
488
+ * @param sessionId Session ID
489
+ * @param url Optional URL to navigate to
490
+ * @param workerId Optional worker ID (uses default worker if not specified)
491
+ */
492
+ async createTarget(sessionId, url, workerId) {
493
+ await this.ensureConnected();
494
+ const worker = await this.getOrCreateWorker(sessionId, workerId);
495
+ // Create page — try connection pool first for pre-warmed pages, fall back to direct creation
496
+ const cdpClient = this.getCDPClientForWorker(sessionId, worker.id);
497
+ let page;
498
+ if (this.connectionPool && this.config.useConnectionPool) {
499
+ try {
500
+ const poolPage = await this.connectionPool.acquirePage();
501
+ // Navigate the pre-warmed page to the target URL
502
+ if (url) {
503
+ await poolPage.goto(url, { waitUntil: 'domcontentloaded' });
504
+ }
505
+ // Copy cookies from the worker's browser context if available
506
+ // (pool pages start blank — replicate what cdpClient.createPage() does for contexts)
507
+ if (worker.context) {
508
+ try {
509
+ const cookies = await worker.context.cookies();
510
+ if (cookies.length > 0) {
511
+ await poolPage.setCookie(...cookies);
512
+ }
513
+ }
514
+ catch {
515
+ // Best-effort cookie copy
516
+ }
517
+ }
518
+ page = poolPage;
519
+ console.error(`[SessionManager] Acquired page from pool for session ${sessionId}`);
520
+ }
521
+ catch (err) {
522
+ console.error(`[SessionManager] Pool acquire failed, falling back to direct creation:`, err);
523
+ page = await cdpClient.createPage(url, worker.context);
524
+ }
525
+ }
526
+ else {
527
+ page = await cdpClient.createPage(url, worker.context);
528
+ }
529
+ const targetId = getTargetId(page.target());
530
+ worker.targets.add(targetId);
531
+ worker.lastActivityAt = Date.now();
532
+ this.targetToWorker.set(targetId, { sessionId, workerId: worker.id });
533
+ this.emitEvent({
534
+ type: 'session:target-added',
535
+ sessionId,
536
+ workerId: worker.id,
537
+ targetId,
538
+ timestamp: Date.now(),
539
+ });
540
+ this.touchSession(sessionId);
541
+ return { targetId, page, workerId: worker.id };
542
+ }
543
+ /**
544
+ * Register a pre-acquired page as a target for a worker.
545
+ * Used by workflow engine when pages are batch-acquired from the pool
546
+ * to avoid per-page replenishment (about:blank proliferation fix).
547
+ */
548
+ registerExistingTarget(sessionId, workerId, targetId) {
549
+ const session = this.sessions.get(sessionId);
550
+ if (!session) {
551
+ throw new Error(`Session ${sessionId} not found`);
552
+ }
553
+ const worker = session.workers.get(workerId);
554
+ if (!worker) {
555
+ throw new Error(`Worker ${workerId} not found in session ${sessionId}`);
556
+ }
557
+ worker.targets.add(targetId);
558
+ worker.lastActivityAt = Date.now();
559
+ this.targetToWorker.set(targetId, { sessionId, workerId });
560
+ this.emitEvent({
561
+ type: 'session:target-added',
562
+ sessionId,
563
+ workerId,
564
+ targetId,
565
+ timestamp: Date.now(),
566
+ });
567
+ this.touchSession(sessionId);
568
+ }
569
+ /**
570
+ * Check if a target is still valid (page not closed)
571
+ */
572
+ async isTargetValid(targetId) {
573
+ try {
574
+ const page = await this.cdpClient.getPageByTargetId(targetId);
575
+ return page !== null && !page.isClosed();
576
+ }
577
+ catch {
578
+ return false;
579
+ }
580
+ }
581
+ /**
582
+ * Get page for a target
583
+ * @param sessionId Session ID
584
+ * @param targetId Target/Tab ID
585
+ * @param workerId Optional worker ID for validation
586
+ * @param toolName Optional MCP tool name for hybrid BrowserRouter routing
587
+ */
588
+ async getPage(sessionId, targetId, workerId, toolName) {
589
+ const ownerInfo = this.targetToWorker.get(targetId);
590
+ if (!ownerInfo || ownerInfo.sessionId !== sessionId) {
591
+ throw new Error(`Target ${targetId} does not belong to session ${sessionId}`);
592
+ }
593
+ if (workerId && ownerInfo.workerId !== workerId) {
594
+ throw new Error(`Target ${targetId} does not belong to worker ${workerId}`);
595
+ }
596
+ const cdpClient = this.getCDPClientForWorker(sessionId, ownerInfo.workerId);
597
+ // Validate target is still valid
598
+ try {
599
+ const page = await cdpClient.getPageByTargetId(targetId);
600
+ if (!page || page.isClosed()) {
601
+ this.onTargetClosed(targetId);
602
+ return null;
603
+ }
604
+ // Route through BrowserRouter if hybrid mode is active and toolName provided
605
+ if (this.browserRouter && toolName) {
606
+ const result = await this.browserRouter.route(toolName, page);
607
+ return result.page;
608
+ }
609
+ return page;
610
+ }
611
+ catch {
612
+ this.onTargetClosed(targetId);
613
+ return null;
614
+ }
615
+ }
616
+ /**
617
+ * Get all pages for a worker
618
+ */
619
+ async getWorkerPages(sessionId, workerId) {
620
+ const worker = this.getWorker(sessionId, workerId);
621
+ if (!worker)
622
+ return [];
623
+ const cdpClient = this.getCDPClientForWorker(sessionId, workerId);
624
+ const pages = [];
625
+ for (const targetId of worker.targets) {
626
+ const page = await cdpClient.getPageByTargetId(targetId);
627
+ if (page) {
628
+ pages.push(page);
629
+ }
630
+ }
631
+ return pages;
632
+ }
633
+ /**
634
+ * Get target IDs for a session (all workers)
635
+ */
636
+ getSessionTargetIds(sessionId) {
637
+ const session = this.sessions.get(sessionId);
638
+ if (!session)
639
+ return [];
640
+ const allTargets = [];
641
+ for (const worker of session.workers.values()) {
642
+ allTargets.push(...worker.targets);
643
+ }
644
+ return allTargets;
645
+ }
646
+ /**
647
+ * Get target IDs for a specific worker
648
+ */
649
+ getWorkerTargetIds(sessionId, workerId) {
650
+ const worker = this.getWorker(sessionId, workerId);
651
+ if (!worker)
652
+ return [];
653
+ return Array.from(worker.targets);
654
+ }
655
+ /**
656
+ * Validate target ownership (legacy method, checks session only)
657
+ */
658
+ validateTargetOwnership(sessionId, targetId) {
659
+ const ownerInfo = this.targetToWorker.get(targetId);
660
+ return ownerInfo?.sessionId === sessionId;
661
+ }
662
+ /**
663
+ * Get the worker ID that owns a target
664
+ */
665
+ getTargetWorkerId(targetId) {
666
+ return this.targetToWorker.get(targetId)?.workerId;
667
+ }
668
+ /**
669
+ * Close a specific target/tab
670
+ * @param sessionId Session ID
671
+ * @param targetId Target/Tab ID to close
672
+ * @returns true if closed, false if not found
673
+ */
674
+ async closeTarget(sessionId, targetId) {
675
+ const ownerInfo = this.targetToWorker.get(targetId);
676
+ if (!ownerInfo || ownerInfo.sessionId !== sessionId) {
677
+ return false;
678
+ }
679
+ try {
680
+ // Close the page via CDP (use worker's CDPClient if on pool)
681
+ const cdpClient = this.getCDPClientForWorker(sessionId, ownerInfo.workerId);
682
+ if (this.connectionPool && this.config.useConnectionPool) {
683
+ // Return the page to the pool for reuse instead of destroying it
684
+ try {
685
+ const page = await cdpClient.getPageByTargetId(targetId);
686
+ if (page && !page.isClosed()) {
687
+ await this.connectionPool.releasePage(page);
688
+ }
689
+ else {
690
+ await cdpClient.closePage(targetId);
691
+ }
692
+ }
693
+ catch {
694
+ // If pool release fails, fall back to direct close
695
+ await cdpClient.closePage(targetId);
696
+ }
697
+ }
698
+ else {
699
+ // closePage() already triggers GC internally before closing
700
+ await cdpClient.closePage(targetId);
701
+ }
702
+ // Clean up internal state
703
+ const session = this.sessions.get(sessionId);
704
+ if (session) {
705
+ const worker = session.workers.get(ownerInfo.workerId);
706
+ if (worker) {
707
+ worker.targets.delete(targetId);
708
+ }
709
+ }
710
+ // Clean up ref IDs
711
+ (0, ref_id_manager_1.getRefIdManager)().clearTargetRefs(sessionId, targetId);
712
+ // Remove from mapping
713
+ this.targetToWorker.delete(targetId);
714
+ this.emitEvent({
715
+ type: 'session:target-closed',
716
+ sessionId,
717
+ workerId: ownerInfo.workerId,
718
+ targetId,
719
+ timestamp: Date.now(),
720
+ });
721
+ return true;
722
+ }
723
+ catch (error) {
724
+ // Page might already be closed
725
+ this.onTargetClosed(targetId);
726
+ return true;
727
+ }
728
+ }
729
+ /**
730
+ * Close all tabs in a worker (without deleting the worker)
731
+ * @param sessionId Session ID
732
+ * @param workerId Worker ID
733
+ * @returns Number of tabs closed
734
+ */
735
+ async closeWorkerTabs(sessionId, workerId) {
736
+ const worker = this.getWorker(sessionId, workerId);
737
+ if (!worker)
738
+ return 0;
739
+ const targetIds = Array.from(worker.targets);
740
+ let closedCount = 0;
741
+ for (const targetId of targetIds) {
742
+ if (await this.closeTarget(sessionId, targetId)) {
743
+ closedCount++;
744
+ }
745
+ }
746
+ return closedCount;
747
+ }
748
+ /**
749
+ * Execute a CDP command through the session's queue
750
+ */
751
+ async executeCDP(sessionId, targetId, method, params) {
752
+ if (!this.validateTargetOwnership(sessionId, targetId)) {
753
+ throw new Error(`Target ${targetId} does not belong to session ${sessionId}`);
754
+ }
755
+ this.touchSession(sessionId);
756
+ const ownerInfo = this.targetToWorker.get(targetId);
757
+ const cdpClient = ownerInfo
758
+ ? this.getCDPClientForWorker(sessionId, ownerInfo.workerId)
759
+ : this.cdpClient;
760
+ const workerQueueKey = ownerInfo ? `${sessionId}:${ownerInfo.workerId}` : sessionId;
761
+ return this.queueManager.enqueue(workerQueueKey, async () => {
762
+ const page = await cdpClient.getPageByTargetId(targetId);
763
+ if (!page) {
764
+ throw new Error(`Page not found for target ${targetId}`);
765
+ }
766
+ return cdpClient.send(page, method, params);
767
+ });
768
+ }
769
+ /**
770
+ * Handle target closed event
771
+ */
772
+ onTargetClosed(targetId) {
773
+ const ownerInfo = this.targetToWorker.get(targetId);
774
+ if (ownerInfo) {
775
+ const session = this.sessions.get(ownerInfo.sessionId);
776
+ if (session) {
777
+ const worker = session.workers.get(ownerInfo.workerId);
778
+ if (worker) {
779
+ worker.targets.delete(targetId);
780
+ }
781
+ this.targetToWorker.delete(targetId);
782
+ this.emitEvent({
783
+ type: 'session:target-removed',
784
+ sessionId: ownerInfo.sessionId,
785
+ workerId: ownerInfo.workerId,
786
+ targetId,
787
+ timestamp: Date.now(),
788
+ });
789
+ }
790
+ }
791
+ }
792
+ // ==================== SESSION INFO ====================
793
+ /**
794
+ * Get session info (for serialization)
795
+ */
796
+ getSessionInfo(sessionId) {
797
+ const session = this.sessions.get(sessionId);
798
+ if (!session)
799
+ return undefined;
800
+ let totalTargets = 0;
801
+ const workers = [];
802
+ for (const worker of session.workers.values()) {
803
+ totalTargets += worker.targets.size;
804
+ workers.push({
805
+ id: worker.id,
806
+ name: worker.name,
807
+ targetCount: worker.targets.size,
808
+ createdAt: worker.createdAt,
809
+ lastActivityAt: worker.lastActivityAt,
810
+ });
811
+ }
812
+ return {
813
+ id: session.id,
814
+ targetCount: totalTargets,
815
+ workerCount: session.workers.size,
816
+ workers,
817
+ createdAt: session.createdAt,
818
+ lastActivityAt: session.lastActivityAt,
819
+ name: session.name,
820
+ };
821
+ }
822
+ /**
823
+ * Get all session infos
824
+ */
825
+ getAllSessionInfos() {
826
+ const infos = [];
827
+ for (const sessionId of this.sessions.keys()) {
828
+ const info = this.getSessionInfo(sessionId);
829
+ if (info) {
830
+ infos.push(info);
831
+ }
832
+ }
833
+ return infos;
834
+ }
835
+ // ==================== EVENT HANDLING ====================
836
+ /**
837
+ * Add event listener
838
+ */
839
+ addEventListener(listener) {
840
+ this.eventListeners.push(listener);
841
+ }
842
+ /**
843
+ * Remove event listener
844
+ */
845
+ removeEventListener(listener) {
846
+ const index = this.eventListeners.indexOf(listener);
847
+ if (index !== -1) {
848
+ this.eventListeners.splice(index, 1);
849
+ }
850
+ }
851
+ /**
852
+ * Emit event to all listeners
853
+ */
854
+ emitEvent(event) {
855
+ for (const listener of this.eventListeners) {
856
+ try {
857
+ listener(event);
858
+ }
859
+ catch (e) {
860
+ console.error('Session event listener error:', e);
861
+ }
862
+ }
863
+ }
864
+ /**
865
+ * Get the number of active sessions
866
+ */
867
+ get sessionCount() {
868
+ return this.sessions.size;
869
+ }
870
+ /**
871
+ * Get CDPClient
872
+ */
873
+ getCDPClient() {
874
+ return this.cdpClient;
875
+ }
876
+ /**
877
+ * Initialize hybrid mode with BrowserRouter
878
+ */
879
+ async initHybrid(config) {
880
+ if (this.browserRouter)
881
+ return; // Already initialized
882
+ this.browserRouter = new router_1.BrowserRouter(config);
883
+ await this.browserRouter.initialize();
884
+ console.error('[SessionManager] Hybrid mode initialized');
885
+ }
886
+ /**
887
+ * Get the BrowserRouter (for stats/escalation)
888
+ */
889
+ getBrowserRouter() {
890
+ return this.browserRouter;
891
+ }
892
+ /**
893
+ * Cleanup hybrid mode
894
+ */
895
+ async cleanupHybrid() {
896
+ if (this.browserRouter) {
897
+ await this.browserRouter.cleanup();
898
+ this.browserRouter = null;
899
+ console.error('[SessionManager] Hybrid mode cleaned up');
900
+ }
901
+ }
902
+ }
903
+ exports.SessionManager = SessionManager;
904
+ // Singleton instance
905
+ let sessionManagerInstance = null;
906
+ function getSessionManager() {
907
+ if (!sessionManagerInstance) {
908
+ sessionManagerInstance = new SessionManager();
909
+ }
910
+ return sessionManagerInstance;
911
+ }
912
+ //# sourceMappingURL=session-manager.js.map