opendevbrowser 0.0.15 → 0.0.17

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 (646) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +262 -43
  3. package/dist/annotate/direct-annotator.d.ts +22 -0
  4. package/dist/annotate/direct-annotator.d.ts.map +1 -0
  5. package/dist/annotate/output.d.ts +10 -0
  6. package/dist/annotate/output.d.ts.map +1 -0
  7. package/dist/browser/annotation-manager.d.ts +33 -0
  8. package/dist/browser/annotation-manager.d.ts.map +1 -0
  9. package/dist/browser/browser-manager.d.ts +402 -0
  10. package/dist/browser/browser-manager.d.ts.map +1 -0
  11. package/dist/browser/canvas-client.d.ts +53 -0
  12. package/dist/browser/canvas-client.d.ts.map +1 -0
  13. package/dist/browser/canvas-code-sync-manager.d.ts +79 -0
  14. package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -0
  15. package/dist/browser/canvas-manager.d.ts +94 -0
  16. package/dist/browser/canvas-manager.d.ts.map +1 -0
  17. package/dist/browser/canvas-runtime-preview-bridge.d.ts +20 -0
  18. package/dist/browser/canvas-runtime-preview-bridge.d.ts.map +1 -0
  19. package/dist/browser/canvas-session-sync-manager.d.ts +21 -0
  20. package/dist/browser/canvas-session-sync-manager.d.ts.map +1 -0
  21. package/dist/browser/fingerprint/adapters.d.ts +26 -0
  22. package/dist/browser/fingerprint/adapters.d.ts.map +1 -0
  23. package/dist/browser/fingerprint/canary.d.ts +25 -0
  24. package/dist/browser/fingerprint/canary.d.ts.map +1 -0
  25. package/dist/browser/fingerprint/profiles.d.ts +16 -0
  26. package/dist/browser/fingerprint/profiles.d.ts.map +1 -0
  27. package/dist/browser/fingerprint/tier1-coherence.d.ts +36 -0
  28. package/dist/browser/fingerprint/tier1-coherence.d.ts.map +1 -0
  29. package/dist/browser/fingerprint/tier2-runtime.d.ts +40 -0
  30. package/dist/browser/fingerprint/tier2-runtime.d.ts.map +1 -0
  31. package/dist/browser/fingerprint/tier3-adaptive.d.ts +30 -0
  32. package/dist/browser/fingerprint/tier3-adaptive.d.ts.map +1 -0
  33. package/dist/browser/manager-types.d.ts +15 -0
  34. package/dist/browser/manager-types.d.ts.map +1 -0
  35. package/dist/browser/ops-browser-manager.d.ts +141 -0
  36. package/dist/browser/ops-browser-manager.d.ts.map +1 -0
  37. package/dist/browser/ops-client.d.ts +56 -0
  38. package/dist/browser/ops-client.d.ts.map +1 -0
  39. package/dist/browser/parallelism-governor.d.ts +31 -0
  40. package/dist/browser/parallelism-governor.d.ts.map +1 -0
  41. package/dist/browser/script-runner.d.ts +23 -0
  42. package/dist/browser/script-runner.d.ts.map +1 -0
  43. package/dist/browser/session-store.d.ts +63 -0
  44. package/dist/browser/session-store.d.ts.map +1 -0
  45. package/dist/browser/target-manager.d.ts +36 -0
  46. package/dist/browser/target-manager.d.ts.map +1 -0
  47. package/dist/cache/chrome-locator.d.ts +2 -0
  48. package/dist/cache/chrome-locator.d.ts.map +1 -0
  49. package/dist/cache/downloader.d.ts +6 -0
  50. package/dist/cache/downloader.d.ts.map +1 -0
  51. package/dist/cache/paths.d.ts +9 -0
  52. package/dist/cache/paths.d.ts.map +1 -0
  53. package/dist/canvas/code-sync/apply-tsx.d.ts +23 -0
  54. package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -0
  55. package/dist/canvas/code-sync/graph.d.ts +5 -0
  56. package/dist/canvas/code-sync/graph.d.ts.map +1 -0
  57. package/dist/canvas/code-sync/hash.d.ts +3 -0
  58. package/dist/canvas/code-sync/hash.d.ts.map +1 -0
  59. package/dist/canvas/code-sync/import.d.ts +18 -0
  60. package/dist/canvas/code-sync/import.d.ts.map +1 -0
  61. package/dist/canvas/code-sync/manifest.d.ts +5 -0
  62. package/dist/canvas/code-sync/manifest.d.ts.map +1 -0
  63. package/dist/canvas/code-sync/tsx-adapter.d.ts +8 -0
  64. package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -0
  65. package/dist/canvas/code-sync/types.d.ts +152 -0
  66. package/dist/canvas/code-sync/types.d.ts.map +1 -0
  67. package/dist/canvas/code-sync/write.d.ts +9 -0
  68. package/dist/canvas/code-sync/write.d.ts.map +1 -0
  69. package/dist/canvas/document-store.d.ts +81 -0
  70. package/dist/canvas/document-store.d.ts.map +1 -0
  71. package/dist/canvas/export.d.ts +12 -0
  72. package/dist/canvas/export.d.ts.map +1 -0
  73. package/dist/canvas/repo-store.d.ts +10 -0
  74. package/dist/canvas/repo-store.d.ts.map +1 -0
  75. package/dist/canvas/surface-palette.d.ts +15 -0
  76. package/dist/canvas/surface-palette.d.ts.map +1 -0
  77. package/dist/canvas/types.d.ts +255 -0
  78. package/dist/canvas/types.d.ts.map +1 -0
  79. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js +7 -0
  80. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js.map +1 -0
  81. package/dist/chunk-5J3IFL3X.js +16706 -0
  82. package/dist/chunk-5J3IFL3X.js.map +1 -0
  83. package/dist/chunk-D633UO34.js +8149 -0
  84. package/dist/chunk-D633UO34.js.map +1 -0
  85. package/dist/chunk-FUSXMW3G.js +169 -0
  86. package/dist/chunk-FUSXMW3G.js.map +1 -0
  87. package/dist/chunk-TBUCZX4A.js +34 -0
  88. package/dist/chunk-TBUCZX4A.js.map +1 -0
  89. package/dist/chunk-V7KUDHDG.js +276 -0
  90. package/dist/chunk-V7KUDHDG.js.map +1 -0
  91. package/dist/chunk-Y2KL55OG.js +59 -0
  92. package/dist/chunk-Y2KL55OG.js.map +1 -0
  93. package/dist/cli/args.d.ts +25 -0
  94. package/dist/cli/args.d.ts.map +1 -0
  95. package/dist/cli/client.d.ts +2 -0
  96. package/dist/cli/client.d.ts.map +1 -0
  97. package/dist/cli/commands/annotate.d.ts +38 -0
  98. package/dist/cli/commands/annotate.d.ts.map +1 -0
  99. package/dist/cli/commands/artifacts.d.ts +24 -0
  100. package/dist/cli/commands/artifacts.d.ts.map +1 -0
  101. package/dist/cli/commands/canvas.d.ts +45 -0
  102. package/dist/cli/commands/canvas.d.ts.map +1 -0
  103. package/dist/cli/commands/daemon.d.ts +35 -0
  104. package/dist/cli/commands/daemon.d.ts.map +1 -0
  105. package/dist/cli/commands/devtools/console-poll.d.ts +7 -0
  106. package/dist/cli/commands/devtools/console-poll.d.ts.map +1 -0
  107. package/dist/cli/commands/devtools/debug-trace-snapshot.d.ts +20 -0
  108. package/dist/cli/commands/devtools/debug-trace-snapshot.d.ts.map +1 -0
  109. package/dist/cli/commands/devtools/network-poll.d.ts +7 -0
  110. package/dist/cli/commands/devtools/network-poll.d.ts.map +1 -0
  111. package/dist/cli/commands/devtools/perf.d.ts +7 -0
  112. package/dist/cli/commands/devtools/perf.d.ts.map +1 -0
  113. package/dist/cli/commands/devtools/screenshot.d.ts +18 -0
  114. package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -0
  115. package/dist/cli/commands/dom/attr.d.ts +7 -0
  116. package/dist/cli/commands/dom/attr.d.ts.map +1 -0
  117. package/dist/cli/commands/dom/checked.d.ts +7 -0
  118. package/dist/cli/commands/dom/checked.d.ts.map +1 -0
  119. package/dist/cli/commands/dom/enabled.d.ts +7 -0
  120. package/dist/cli/commands/dom/enabled.d.ts.map +1 -0
  121. package/dist/cli/commands/dom/html.d.ts +7 -0
  122. package/dist/cli/commands/dom/html.d.ts.map +1 -0
  123. package/dist/cli/commands/dom/text.d.ts +7 -0
  124. package/dist/cli/commands/dom/text.d.ts.map +1 -0
  125. package/dist/cli/commands/dom/value.d.ts +7 -0
  126. package/dist/cli/commands/dom/value.d.ts.map +1 -0
  127. package/dist/cli/commands/dom/visible.d.ts +7 -0
  128. package/dist/cli/commands/dom/visible.d.ts.map +1 -0
  129. package/dist/cli/commands/export/clone-component.d.ts +16 -0
  130. package/dist/cli/commands/export/clone-component.d.ts.map +1 -0
  131. package/dist/cli/commands/export/clone-page.d.ts +15 -0
  132. package/dist/cli/commands/export/clone-page.d.ts.map +1 -0
  133. package/dist/cli/commands/interact/check.d.ts +7 -0
  134. package/dist/cli/commands/interact/check.d.ts.map +1 -0
  135. package/dist/cli/commands/interact/click.d.ts +7 -0
  136. package/dist/cli/commands/interact/click.d.ts.map +1 -0
  137. package/dist/cli/commands/interact/hover.d.ts +7 -0
  138. package/dist/cli/commands/interact/hover.d.ts.map +1 -0
  139. package/dist/cli/commands/interact/press.d.ts +7 -0
  140. package/dist/cli/commands/interact/press.d.ts.map +1 -0
  141. package/dist/cli/commands/interact/scroll-into-view.d.ts +7 -0
  142. package/dist/cli/commands/interact/scroll-into-view.d.ts.map +1 -0
  143. package/dist/cli/commands/interact/scroll.d.ts +7 -0
  144. package/dist/cli/commands/interact/scroll.d.ts.map +1 -0
  145. package/dist/cli/commands/interact/select.d.ts +7 -0
  146. package/dist/cli/commands/interact/select.d.ts.map +1 -0
  147. package/dist/cli/commands/interact/type.d.ts +7 -0
  148. package/dist/cli/commands/interact/type.d.ts.map +1 -0
  149. package/dist/cli/commands/interact/uncheck.d.ts +7 -0
  150. package/dist/cli/commands/interact/uncheck.d.ts.map +1 -0
  151. package/dist/cli/commands/macro-resolve.d.ts +18 -0
  152. package/dist/cli/commands/macro-resolve.d.ts.map +1 -0
  153. package/dist/cli/commands/native.d.ts +93 -0
  154. package/dist/cli/commands/native.d.ts.map +1 -0
  155. package/dist/cli/commands/nav/goto.d.ts +7 -0
  156. package/dist/cli/commands/nav/goto.d.ts.map +1 -0
  157. package/dist/cli/commands/nav/snapshot.d.ts +7 -0
  158. package/dist/cli/commands/nav/snapshot.d.ts.map +1 -0
  159. package/dist/cli/commands/nav/wait.d.ts +7 -0
  160. package/dist/cli/commands/nav/wait.d.ts.map +1 -0
  161. package/dist/cli/commands/pages/close.d.ts +6 -0
  162. package/dist/cli/commands/pages/close.d.ts.map +1 -0
  163. package/dist/cli/commands/pages/list.d.ts +7 -0
  164. package/dist/cli/commands/pages/list.d.ts.map +1 -0
  165. package/dist/cli/commands/pages/open.d.ts +7 -0
  166. package/dist/cli/commands/pages/open.d.ts.map +1 -0
  167. package/dist/cli/commands/product-video.d.ts +25 -0
  168. package/dist/cli/commands/product-video.d.ts.map +1 -0
  169. package/dist/cli/commands/registry.d.ts +5 -0
  170. package/dist/cli/commands/registry.d.ts.map +1 -0
  171. package/dist/cli/commands/research.d.ts +27 -0
  172. package/dist/cli/commands/research.d.ts.map +1 -0
  173. package/dist/cli/commands/rpc.d.ts +28 -0
  174. package/dist/cli/commands/rpc.d.ts.map +1 -0
  175. package/dist/cli/commands/run.d.ts +17 -0
  176. package/dist/cli/commands/run.d.ts.map +1 -0
  177. package/dist/cli/commands/serve.d.ts +64 -0
  178. package/dist/cli/commands/serve.d.ts.map +1 -0
  179. package/dist/cli/commands/session/connect.d.ts +9 -0
  180. package/dist/cli/commands/session/connect.d.ts.map +1 -0
  181. package/dist/cli/commands/session/cookie-import.d.ts +31 -0
  182. package/dist/cli/commands/session/cookie-import.d.ts.map +1 -0
  183. package/dist/cli/commands/session/cookie-list.d.ts +17 -0
  184. package/dist/cli/commands/session/cookie-list.d.ts.map +1 -0
  185. package/dist/cli/commands/session/disconnect.d.ts +6 -0
  186. package/dist/cli/commands/session/disconnect.d.ts.map +1 -0
  187. package/dist/cli/commands/session/launch.d.ts +29 -0
  188. package/dist/cli/commands/session/launch.d.ts.map +1 -0
  189. package/dist/cli/commands/session/status.d.ts +7 -0
  190. package/dist/cli/commands/session/status.d.ts.map +1 -0
  191. package/dist/cli/commands/shopping.d.ts +25 -0
  192. package/dist/cli/commands/shopping.d.ts.map +1 -0
  193. package/dist/cli/commands/status.d.ts +24 -0
  194. package/dist/cli/commands/status.d.ts.map +1 -0
  195. package/dist/cli/commands/targets/close.d.ts +6 -0
  196. package/dist/cli/commands/targets/close.d.ts.map +1 -0
  197. package/dist/cli/commands/targets/list.d.ts +7 -0
  198. package/dist/cli/commands/targets/list.d.ts.map +1 -0
  199. package/dist/cli/commands/targets/new.d.ts +7 -0
  200. package/dist/cli/commands/targets/new.d.ts.map +1 -0
  201. package/dist/cli/commands/targets/use.d.ts +7 -0
  202. package/dist/cli/commands/targets/use.d.ts.map +1 -0
  203. package/dist/cli/commands/types.d.ts +13 -0
  204. package/dist/cli/commands/types.d.ts.map +1 -0
  205. package/dist/cli/commands/uninstall.d.ts +14 -0
  206. package/dist/cli/commands/uninstall.d.ts.map +1 -0
  207. package/dist/cli/commands/update.d.ts +7 -0
  208. package/dist/cli/commands/update.d.ts.map +1 -0
  209. package/dist/cli/daemon-autostart.d.ts +46 -0
  210. package/dist/cli/daemon-autostart.d.ts.map +1 -0
  211. package/dist/cli/daemon-client.d.ts +33 -0
  212. package/dist/cli/daemon-client.d.ts.map +1 -0
  213. package/dist/cli/daemon-commands.d.ts +7 -0
  214. package/dist/cli/daemon-commands.d.ts.map +1 -0
  215. package/dist/cli/daemon-state.d.ts +56 -0
  216. package/dist/cli/daemon-state.d.ts.map +1 -0
  217. package/dist/cli/daemon-status.d.ts +19 -0
  218. package/dist/cli/daemon-status.d.ts.map +1 -0
  219. package/dist/cli/daemon.d.ts +29 -0
  220. package/dist/cli/daemon.d.ts.map +1 -0
  221. package/dist/cli/errors.d.ts +20 -0
  222. package/dist/cli/errors.d.ts.map +1 -0
  223. package/dist/cli/help.d.ts +33 -0
  224. package/dist/cli/help.d.ts.map +1 -0
  225. package/dist/cli/index.d.ts +2 -0
  226. package/dist/cli/index.d.ts.map +1 -0
  227. package/dist/cli/index.js +2825 -326
  228. package/dist/cli/index.js.map +1 -1
  229. package/dist/cli/installers/global.d.ts +9 -0
  230. package/dist/cli/installers/global.d.ts.map +1 -0
  231. package/dist/cli/installers/local.d.ts +9 -0
  232. package/dist/cli/installers/local.d.ts.map +1 -0
  233. package/dist/cli/installers/skills.d.ts +19 -0
  234. package/dist/cli/installers/skills.d.ts.map +1 -0
  235. package/dist/cli/output.d.ts +7 -0
  236. package/dist/cli/output.d.ts.map +1 -0
  237. package/dist/cli/remote-canvas-manager.d.ts +8 -0
  238. package/dist/cli/remote-canvas-manager.d.ts.map +1 -0
  239. package/dist/cli/remote-manager.d.ts +98 -0
  240. package/dist/cli/remote-manager.d.ts.map +1 -0
  241. package/dist/cli/remote-relay.d.ts +19 -0
  242. package/dist/cli/remote-relay.d.ts.map +1 -0
  243. package/dist/cli/templates/config.d.ts +7 -0
  244. package/dist/cli/templates/config.d.ts.map +1 -0
  245. package/dist/cli/utils/config.d.ts +20 -0
  246. package/dist/cli/utils/config.d.ts.map +1 -0
  247. package/dist/cli/utils/http.d.ts +5 -0
  248. package/dist/cli/utils/http.d.ts.map +1 -0
  249. package/dist/cli/utils/parse.d.ts +9 -0
  250. package/dist/cli/utils/parse.d.ts.map +1 -0
  251. package/dist/cli/utils/skills.d.ts +12 -0
  252. package/dist/cli/utils/skills.d.ts.map +1 -0
  253. package/dist/config.d.ts +208 -0
  254. package/dist/config.d.ts.map +1 -0
  255. package/dist/core/bootstrap.d.ts +3 -0
  256. package/dist/core/bootstrap.d.ts.map +1 -0
  257. package/dist/core/index.d.ts +3 -0
  258. package/dist/core/index.d.ts.map +1 -0
  259. package/dist/core/logging.d.ts +34 -0
  260. package/dist/core/logging.d.ts.map +1 -0
  261. package/dist/core/types.d.ts +36 -0
  262. package/dist/core/types.d.ts.map +1 -0
  263. package/dist/devtools/console-tracker.d.ts +44 -0
  264. package/dist/devtools/console-tracker.d.ts.map +1 -0
  265. package/dist/devtools/exception-tracker.d.ts +42 -0
  266. package/dist/devtools/exception-tracker.d.ts.map +1 -0
  267. package/dist/devtools/network-tracker.d.ts +34 -0
  268. package/dist/devtools/network-tracker.d.ts.map +1 -0
  269. package/dist/export/css-extract.d.ts +5 -0
  270. package/dist/export/css-extract.d.ts.map +1 -0
  271. package/dist/export/dom-capture.d.ts +15 -0
  272. package/dist/export/dom-capture.d.ts.map +1 -0
  273. package/dist/export/react-emitter.d.ts +11 -0
  274. package/dist/export/react-emitter.d.ts.map +1 -0
  275. package/dist/extension-extractor.d.ts +3 -0
  276. package/dist/extension-extractor.d.ts.map +1 -0
  277. package/dist/fs-UMRKOBNN.js +7 -0
  278. package/dist/fs-UMRKOBNN.js.map +1 -0
  279. package/dist/index.d.ts +3 -4
  280. package/dist/index.d.ts.map +1 -0
  281. package/dist/index.js +1028 -123
  282. package/dist/index.js.map +1 -1
  283. package/dist/macros/execute.d.ts +44 -0
  284. package/dist/macros/execute.d.ts.map +1 -0
  285. package/dist/macros/index.d.ts +9 -0
  286. package/dist/macros/index.d.ts.map +1 -0
  287. package/dist/macros/packs/core.d.ts +3 -0
  288. package/dist/macros/packs/core.d.ts.map +1 -0
  289. package/dist/macros/registry.d.ts +48 -0
  290. package/dist/macros/registry.d.ts.map +1 -0
  291. package/dist/macros-ND2M7LWU.js +399 -0
  292. package/dist/macros-ND2M7LWU.js.map +1 -0
  293. package/dist/opendevbrowser.d.ts +3 -4
  294. package/dist/opendevbrowser.d.ts.map +1 -0
  295. package/dist/opendevbrowser.js +1028 -123
  296. package/dist/opendevbrowser.js.map +1 -1
  297. package/dist/providers/adaptive-concurrency.d.ts +42 -0
  298. package/dist/providers/adaptive-concurrency.d.ts.map +1 -0
  299. package/dist/providers/artifacts.d.ts +34 -0
  300. package/dist/providers/artifacts.d.ts.map +1 -0
  301. package/dist/providers/blocker.d.ts +47 -0
  302. package/dist/providers/blocker.d.ts.map +1 -0
  303. package/dist/providers/community/index.d.ts +44 -0
  304. package/dist/providers/community/index.d.ts.map +1 -0
  305. package/dist/providers/enrichment.d.ts +33 -0
  306. package/dist/providers/enrichment.d.ts.map +1 -0
  307. package/dist/providers/errors.d.ts +41 -0
  308. package/dist/providers/errors.d.ts.map +1 -0
  309. package/dist/providers/index.d.ts +121 -0
  310. package/dist/providers/index.d.ts.map +1 -0
  311. package/dist/providers/normalize.d.ts +39 -0
  312. package/dist/providers/normalize.d.ts.map +1 -0
  313. package/dist/providers/policy.d.ts +5 -0
  314. package/dist/providers/policy.d.ts.map +1 -0
  315. package/dist/providers/registry.d.ts +22 -0
  316. package/dist/providers/registry.d.ts.map +1 -0
  317. package/dist/providers/renderer.d.ts +49 -0
  318. package/dist/providers/renderer.d.ts.map +1 -0
  319. package/dist/providers/runtime-factory.d.ts +20 -0
  320. package/dist/providers/runtime-factory.d.ts.map +1 -0
  321. package/dist/providers/safety/prompt-guard.d.ts +34 -0
  322. package/dist/providers/safety/prompt-guard.d.ts.map +1 -0
  323. package/dist/providers/shared/anti-bot-policy.d.ts +51 -0
  324. package/dist/providers/shared/anti-bot-policy.d.ts.map +1 -0
  325. package/dist/providers/shared/post-policy.d.ts +31 -0
  326. package/dist/providers/shared/post-policy.d.ts.map +1 -0
  327. package/dist/providers/shared/request-headers.d.ts +5 -0
  328. package/dist/providers/shared/request-headers.d.ts.map +1 -0
  329. package/dist/providers/shared/traversal-url.d.ts +2 -0
  330. package/dist/providers/shared/traversal-url.d.ts.map +1 -0
  331. package/dist/providers/shopping/index.d.ts +63 -0
  332. package/dist/providers/shopping/index.d.ts.map +1 -0
  333. package/dist/providers/social/bluesky.d.ts +3 -0
  334. package/dist/providers/social/bluesky.d.ts.map +1 -0
  335. package/dist/providers/social/facebook.d.ts +3 -0
  336. package/dist/providers/social/facebook.d.ts.map +1 -0
  337. package/dist/providers/social/index.d.ts +31 -0
  338. package/dist/providers/social/index.d.ts.map +1 -0
  339. package/dist/providers/social/instagram.d.ts +3 -0
  340. package/dist/providers/social/instagram.d.ts.map +1 -0
  341. package/dist/providers/social/linkedin.d.ts +3 -0
  342. package/dist/providers/social/linkedin.d.ts.map +1 -0
  343. package/dist/providers/social/platform.d.ts +40 -0
  344. package/dist/providers/social/platform.d.ts.map +1 -0
  345. package/dist/providers/social/reddit.d.ts +3 -0
  346. package/dist/providers/social/reddit.d.ts.map +1 -0
  347. package/dist/providers/social/threads.d.ts +3 -0
  348. package/dist/providers/social/threads.d.ts.map +1 -0
  349. package/dist/providers/social/tiktok.d.ts +3 -0
  350. package/dist/providers/social/tiktok.d.ts.map +1 -0
  351. package/dist/providers/social/x.d.ts +3 -0
  352. package/dist/providers/social/x.d.ts.map +1 -0
  353. package/dist/providers/social/youtube-resolver.d.ts +78 -0
  354. package/dist/providers/social/youtube-resolver.d.ts.map +1 -0
  355. package/dist/providers/social/youtube.d.ts +34 -0
  356. package/dist/providers/social/youtube.d.ts.map +1 -0
  357. package/dist/providers/tier-router.d.ts +30 -0
  358. package/dist/providers/tier-router.d.ts.map +1 -0
  359. package/dist/providers/timebox.d.ts +20 -0
  360. package/dist/providers/timebox.d.ts.map +1 -0
  361. package/dist/providers/types.d.ts +344 -0
  362. package/dist/providers/types.d.ts.map +1 -0
  363. package/dist/providers/web/crawl-worker.d.ts +36 -0
  364. package/dist/providers/web/crawl-worker.d.ts.map +1 -0
  365. package/dist/providers/web/crawler.d.ts +101 -0
  366. package/dist/providers/web/crawler.d.ts.map +1 -0
  367. package/dist/providers/web/extract.d.ts +11 -0
  368. package/dist/providers/web/extract.d.ts.map +1 -0
  369. package/dist/providers/web/index.d.ts +24 -0
  370. package/dist/providers/web/index.d.ts.map +1 -0
  371. package/dist/providers/web/policy.d.ts +14 -0
  372. package/dist/providers/web/policy.d.ts.map +1 -0
  373. package/dist/providers/workflows.d.ts +67 -0
  374. package/dist/providers/workflows.d.ts.map +1 -0
  375. package/dist/providers-G3LRHQXX.js +121 -0
  376. package/dist/providers-G3LRHQXX.js.map +1 -0
  377. package/dist/relay/protocol.d.ts +399 -0
  378. package/dist/relay/protocol.d.ts.map +1 -0
  379. package/dist/relay/relay-endpoints.d.ts +16 -0
  380. package/dist/relay/relay-endpoints.d.ts.map +1 -0
  381. package/dist/relay/relay-server.d.ts +124 -0
  382. package/dist/relay/relay-server.d.ts.map +1 -0
  383. package/dist/relay/relay-types.d.ts +12 -0
  384. package/dist/relay/relay-types.d.ts.map +1 -0
  385. package/dist/runtime-factory-BICHDPE7.js +13 -0
  386. package/dist/runtime-factory-BICHDPE7.js.map +1 -0
  387. package/dist/skills/continuity-nudge.d.ts +12 -0
  388. package/dist/skills/continuity-nudge.d.ts.map +1 -0
  389. package/dist/skills/skill-loader.d.ts +20 -0
  390. package/dist/skills/skill-loader.d.ts.map +1 -0
  391. package/dist/skills/skill-nudge.d.ts +18 -0
  392. package/dist/skills/skill-nudge.d.ts.map +1 -0
  393. package/dist/skills/types.d.ts +12 -0
  394. package/dist/skills/types.d.ts.map +1 -0
  395. package/dist/snapshot/ops-snapshot.d.ts +16 -0
  396. package/dist/snapshot/ops-snapshot.d.ts.map +1 -0
  397. package/dist/snapshot/refs.d.ts +23 -0
  398. package/dist/snapshot/refs.d.ts.map +1 -0
  399. package/dist/snapshot/snapshotter.d.ts +27 -0
  400. package/dist/snapshot/snapshotter.d.ts.map +1 -0
  401. package/dist/tools/annotate.d.ts +4 -0
  402. package/dist/tools/annotate.d.ts.map +1 -0
  403. package/dist/tools/canvas.d.ts +4 -0
  404. package/dist/tools/canvas.d.ts.map +1 -0
  405. package/dist/tools/check.d.ts +4 -0
  406. package/dist/tools/check.d.ts.map +1 -0
  407. package/dist/tools/click.d.ts +4 -0
  408. package/dist/tools/click.d.ts.map +1 -0
  409. package/dist/tools/clone_component.d.ts +4 -0
  410. package/dist/tools/clone_component.d.ts.map +1 -0
  411. package/dist/tools/clone_page.d.ts +4 -0
  412. package/dist/tools/clone_page.d.ts.map +1 -0
  413. package/dist/tools/close.d.ts +4 -0
  414. package/dist/tools/close.d.ts.map +1 -0
  415. package/dist/tools/connect.d.ts +4 -0
  416. package/dist/tools/connect.d.ts.map +1 -0
  417. package/dist/tools/console_poll.d.ts +4 -0
  418. package/dist/tools/console_poll.d.ts.map +1 -0
  419. package/dist/tools/cookie_import.d.ts +25 -0
  420. package/dist/tools/cookie_import.d.ts.map +1 -0
  421. package/dist/tools/cookie_list.d.ts +9 -0
  422. package/dist/tools/cookie_list.d.ts.map +1 -0
  423. package/dist/tools/debug_trace_snapshot.d.ts +4 -0
  424. package/dist/tools/debug_trace_snapshot.d.ts.map +1 -0
  425. package/dist/tools/deps.d.ts +28 -0
  426. package/dist/tools/deps.d.ts.map +1 -0
  427. package/dist/tools/disconnect.d.ts +4 -0
  428. package/dist/tools/disconnect.d.ts.map +1 -0
  429. package/dist/tools/dom_get_html.d.ts +4 -0
  430. package/dist/tools/dom_get_html.d.ts.map +1 -0
  431. package/dist/tools/dom_get_text.d.ts +4 -0
  432. package/dist/tools/dom_get_text.d.ts.map +1 -0
  433. package/dist/tools/get_attr.d.ts +4 -0
  434. package/dist/tools/get_attr.d.ts.map +1 -0
  435. package/dist/tools/get_value.d.ts +4 -0
  436. package/dist/tools/get_value.d.ts.map +1 -0
  437. package/dist/tools/goto.d.ts +4 -0
  438. package/dist/tools/goto.d.ts.map +1 -0
  439. package/dist/tools/hover.d.ts +4 -0
  440. package/dist/tools/hover.d.ts.map +1 -0
  441. package/dist/tools/index.d.ts +4 -0
  442. package/dist/tools/index.d.ts.map +1 -0
  443. package/dist/tools/is_checked.d.ts +4 -0
  444. package/dist/tools/is_checked.d.ts.map +1 -0
  445. package/dist/tools/is_enabled.d.ts +4 -0
  446. package/dist/tools/is_enabled.d.ts.map +1 -0
  447. package/dist/tools/is_visible.d.ts +4 -0
  448. package/dist/tools/is_visible.d.ts.map +1 -0
  449. package/dist/tools/launch.d.ts +4 -0
  450. package/dist/tools/launch.d.ts.map +1 -0
  451. package/dist/tools/list.d.ts +4 -0
  452. package/dist/tools/list.d.ts.map +1 -0
  453. package/dist/tools/macro_resolve.d.ts +25 -0
  454. package/dist/tools/macro_resolve.d.ts.map +1 -0
  455. package/dist/tools/network_poll.d.ts +4 -0
  456. package/dist/tools/network_poll.d.ts.map +1 -0
  457. package/dist/tools/page.d.ts +4 -0
  458. package/dist/tools/page.d.ts.map +1 -0
  459. package/dist/tools/perf.d.ts +4 -0
  460. package/dist/tools/perf.d.ts.map +1 -0
  461. package/dist/tools/press.d.ts +4 -0
  462. package/dist/tools/press.d.ts.map +1 -0
  463. package/dist/tools/product_video_run.d.ts +4 -0
  464. package/dist/tools/product_video_run.d.ts.map +1 -0
  465. package/dist/tools/prompting_guide.d.ts +4 -0
  466. package/dist/tools/prompting_guide.d.ts.map +1 -0
  467. package/dist/tools/research_run.d.ts +4 -0
  468. package/dist/tools/research_run.d.ts.map +1 -0
  469. package/dist/tools/response.d.ts +19 -0
  470. package/dist/tools/response.d.ts.map +1 -0
  471. package/dist/tools/run.d.ts +4 -0
  472. package/dist/tools/run.d.ts.map +1 -0
  473. package/dist/tools/screenshot.d.ts +4 -0
  474. package/dist/tools/screenshot.d.ts.map +1 -0
  475. package/dist/tools/scroll.d.ts +4 -0
  476. package/dist/tools/scroll.d.ts.map +1 -0
  477. package/dist/tools/scroll_into_view.d.ts +4 -0
  478. package/dist/tools/scroll_into_view.d.ts.map +1 -0
  479. package/dist/tools/select.d.ts +4 -0
  480. package/dist/tools/select.d.ts.map +1 -0
  481. package/dist/tools/shopping_run.d.ts +4 -0
  482. package/dist/tools/shopping_run.d.ts.map +1 -0
  483. package/dist/tools/skill_list.d.ts +4 -0
  484. package/dist/tools/skill_list.d.ts.map +1 -0
  485. package/dist/tools/skill_load.d.ts +4 -0
  486. package/dist/tools/skill_load.d.ts.map +1 -0
  487. package/dist/tools/snapshot.d.ts +4 -0
  488. package/dist/tools/snapshot.d.ts.map +1 -0
  489. package/dist/tools/status.d.ts +4 -0
  490. package/dist/tools/status.d.ts.map +1 -0
  491. package/dist/tools/target_close.d.ts +4 -0
  492. package/dist/tools/target_close.d.ts.map +1 -0
  493. package/dist/tools/target_new.d.ts +4 -0
  494. package/dist/tools/target_new.d.ts.map +1 -0
  495. package/dist/tools/target_use.d.ts +4 -0
  496. package/dist/tools/target_use.d.ts.map +1 -0
  497. package/dist/tools/targets_list.d.ts +4 -0
  498. package/dist/tools/targets_list.d.ts.map +1 -0
  499. package/dist/tools/type.d.ts +4 -0
  500. package/dist/tools/type.d.ts.map +1 -0
  501. package/dist/tools/uncheck.d.ts +4 -0
  502. package/dist/tools/uncheck.d.ts.map +1 -0
  503. package/dist/tools/wait.d.ts +4 -0
  504. package/dist/tools/wait.d.ts.map +1 -0
  505. package/dist/tools/workflow-runtime.d.ts +3 -0
  506. package/dist/tools/workflow-runtime.d.ts.map +1 -0
  507. package/dist/utils/crypto.d.ts +2 -0
  508. package/dist/utils/crypto.d.ts.map +1 -0
  509. package/dist/utils/endpoint-validation.d.ts +2 -0
  510. package/dist/utils/endpoint-validation.d.ts.map +1 -0
  511. package/dist/utils/fs.d.ts +5 -0
  512. package/dist/utils/fs.d.ts.map +1 -0
  513. package/dist/utils/hub-enabled.d.ts +3 -0
  514. package/dist/utils/hub-enabled.d.ts.map +1 -0
  515. package/extension/canvas.html +636 -0
  516. package/extension/dist/annotate-content.css +15 -6
  517. package/extension/dist/annotate-content.js +119 -9
  518. package/extension/dist/annotation-payload.js +163 -0
  519. package/extension/dist/background.js +158 -22
  520. package/extension/dist/canvas/canvas-runtime.js +1061 -0
  521. package/extension/dist/canvas/model.js +213 -0
  522. package/extension/dist/canvas/viewport-fit.js +67 -0
  523. package/extension/dist/canvas-page.js +1801 -0
  524. package/extension/dist/ops/dom-bridge.js +116 -3
  525. package/extension/dist/ops/ops-runtime.js +1014 -48
  526. package/extension/dist/ops/ops-session-store.js +37 -116
  527. package/extension/dist/ops/parallelism-governor.js +117 -0
  528. package/extension/dist/ops/snapshot-shared.js +21 -5
  529. package/extension/dist/ops/target-session-coordinator.js +157 -0
  530. package/extension/dist/popup.js +155 -31
  531. package/extension/dist/services/CDPRouter.js +70 -5
  532. package/extension/dist/services/ConnectionManager.js +22 -3
  533. package/extension/dist/services/RelayClient.js +9 -0
  534. package/extension/dist/services/TabManager.js +35 -12
  535. package/extension/dist/types.js +2 -0
  536. package/extension/icons/icon128.png +0 -0
  537. package/extension/icons/icon16.png +0 -0
  538. package/extension/icons/icon32.png +0 -0
  539. package/extension/icons/icon48.png +0 -0
  540. package/extension/manifest.json +1 -1
  541. package/extension/popup.html +52 -0
  542. package/package.json +30 -19
  543. package/scripts/native/host.cjs +230 -0
  544. package/scripts/native/install.ps1 +73 -0
  545. package/scripts/native/install.sh +66 -0
  546. package/scripts/native/uninstall.ps1 +25 -0
  547. package/scripts/native/uninstall.sh +26 -0
  548. package/skills/AGENTS.md +20 -8
  549. package/skills/opendevbrowser-best-practices/SKILL.md +248 -74
  550. package/skills/opendevbrowser-best-practices/artifacts/browser-agent-known-issues-matrix.md +44 -0
  551. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +141 -0
  552. package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +191 -0
  553. package/skills/opendevbrowser-best-practices/artifacts/debug-trace-playbook.md +36 -0
  554. package/skills/opendevbrowser-best-practices/artifacts/fingerprint-tiers.md +36 -0
  555. package/skills/opendevbrowser-best-practices/artifacts/macro-workflows.md +43 -0
  556. package/skills/opendevbrowser-best-practices/artifacts/parity-gates.md +36 -0
  557. package/skills/opendevbrowser-best-practices/artifacts/provider-workflows.md +89 -0
  558. package/skills/opendevbrowser-best-practices/assets/templates/canvas-blocker-checklist.json +70 -0
  559. package/skills/opendevbrowser-best-practices/assets/templates/canvas-feedback-eval.json +73 -0
  560. package/skills/opendevbrowser-best-practices/assets/templates/canvas-generation-plan.v1.json +67 -0
  561. package/skills/opendevbrowser-best-practices/assets/templates/canvas-handshake-example.json +126 -0
  562. package/skills/opendevbrowser-best-practices/assets/templates/cdp-forward-envelope.json +11 -0
  563. package/skills/opendevbrowser-best-practices/assets/templates/mode-flag-matrix.json +56 -0
  564. package/skills/opendevbrowser-best-practices/assets/templates/ops-request-envelope.json +9 -0
  565. package/skills/opendevbrowser-best-practices/assets/templates/robustness-checklist.json +136 -0
  566. package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +28 -0
  567. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +170 -0
  568. package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +164 -0
  569. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +234 -0
  570. package/skills/opendevbrowser-continuity-ledger/SKILL.md +10 -0
  571. package/skills/opendevbrowser-data-extraction/SKILL.md +126 -0
  572. package/skills/opendevbrowser-data-extraction/artifacts/extraction-workflows.md +31 -0
  573. package/skills/opendevbrowser-data-extraction/assets/templates/compliance-checklist.md +7 -0
  574. package/skills/opendevbrowser-data-extraction/assets/templates/extraction-schema.json +17 -0
  575. package/skills/opendevbrowser-data-extraction/assets/templates/pagination-state.json +11 -0
  576. package/skills/opendevbrowser-data-extraction/assets/templates/quality-gates.json +10 -0
  577. package/skills/opendevbrowser-data-extraction/examples/sample-schema.json +19 -0
  578. package/skills/opendevbrowser-data-extraction/scripts/run-extraction-workflow.sh +83 -0
  579. package/skills/opendevbrowser-data-extraction/scripts/validate-skill-assets.sh +49 -0
  580. package/skills/opendevbrowser-form-testing/SKILL.md +143 -0
  581. package/skills/opendevbrowser-form-testing/artifacts/form-workflows.md +37 -0
  582. package/skills/opendevbrowser-form-testing/assets/templates/a11y-assertions.md +7 -0
  583. package/skills/opendevbrowser-form-testing/assets/templates/challenge-decision-tree.json +16 -0
  584. package/skills/opendevbrowser-form-testing/assets/templates/multi-step-state.json +11 -0
  585. package/skills/opendevbrowser-form-testing/assets/templates/validation-matrix.json +24 -0
  586. package/skills/opendevbrowser-form-testing/examples/sample-validation-matrix.json +29 -0
  587. package/skills/opendevbrowser-form-testing/scripts/run-form-workflow.sh +82 -0
  588. package/skills/opendevbrowser-form-testing/scripts/validate-skill-assets.sh +49 -0
  589. package/skills/opendevbrowser-login-automation/SKILL.md +159 -0
  590. package/skills/opendevbrowser-login-automation/artifacts/login-workflows.md +39 -0
  591. package/skills/opendevbrowser-login-automation/assets/templates/auth-signals.json +21 -0
  592. package/skills/opendevbrowser-login-automation/assets/templates/challenge-checkpoint.md +10 -0
  593. package/skills/opendevbrowser-login-automation/assets/templates/login-scenario-matrix.json +26 -0
  594. package/skills/opendevbrowser-login-automation/examples/sample-auth-signals.json +14 -0
  595. package/skills/opendevbrowser-login-automation/scripts/record-auth-signals.sh +18 -0
  596. package/skills/opendevbrowser-login-automation/scripts/run-login-workflow.sh +99 -0
  597. package/skills/opendevbrowser-login-automation/scripts/validate-skill-assets.sh +50 -0
  598. package/skills/opendevbrowser-product-presentation-asset/SKILL.md +98 -0
  599. package/skills/opendevbrowser-product-presentation-asset/artifacts/asset-pack-assembly.md +23 -0
  600. package/skills/opendevbrowser-product-presentation-asset/artifacts/ugc-creative-guide.md +21 -0
  601. package/skills/opendevbrowser-product-presentation-asset/assets/templates/claims-evidence-map.md +5 -0
  602. package/skills/opendevbrowser-product-presentation-asset/assets/templates/copy.md +5 -0
  603. package/skills/opendevbrowser-product-presentation-asset/assets/templates/features.md +4 -0
  604. package/skills/opendevbrowser-product-presentation-asset/assets/templates/manifest.schema.json +14 -0
  605. package/skills/opendevbrowser-product-presentation-asset/assets/templates/shot-list.md +7 -0
  606. package/skills/opendevbrowser-product-presentation-asset/assets/templates/ugc-concepts.md +17 -0
  607. package/skills/opendevbrowser-product-presentation-asset/assets/templates/user-actions.md +7 -0
  608. package/skills/opendevbrowser-product-presentation-asset/assets/templates/video-assembly.md +18 -0
  609. package/skills/opendevbrowser-product-presentation-asset/examples/sample-input.json +6 -0
  610. package/skills/opendevbrowser-product-presentation-asset/examples/sample-manifest.json +18 -0
  611. package/skills/opendevbrowser-product-presentation-asset/scripts/capture-screenshots.sh +9 -0
  612. package/skills/opendevbrowser-product-presentation-asset/scripts/collect-product.sh +14 -0
  613. package/skills/opendevbrowser-product-presentation-asset/scripts/download-images.sh +9 -0
  614. package/skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh +96 -0
  615. package/skills/opendevbrowser-product-presentation-asset/scripts/validate-skill-assets.sh +56 -0
  616. package/skills/opendevbrowser-product-presentation-asset/scripts/write-manifest.sh +43 -0
  617. package/skills/opendevbrowser-research/SKILL.md +73 -0
  618. package/skills/opendevbrowser-research/artifacts/research-workflows.md +29 -0
  619. package/skills/opendevbrowser-research/assets/templates/compact.md +7 -0
  620. package/skills/opendevbrowser-research/assets/templates/context.json +18 -0
  621. package/skills/opendevbrowser-research/assets/templates/report.md +9 -0
  622. package/skills/opendevbrowser-research/examples/sample-input.json +6 -0
  623. package/skills/opendevbrowser-research/examples/sample-output.md +4 -0
  624. package/skills/opendevbrowser-research/scripts/render-output.sh +12 -0
  625. package/skills/opendevbrowser-research/scripts/run-research.sh +23 -0
  626. package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +48 -0
  627. package/skills/opendevbrowser-research/scripts/write-artifacts.sh +29 -0
  628. package/skills/opendevbrowser-shopping/SKILL.md +118 -0
  629. package/skills/opendevbrowser-shopping/artifacts/deal-hunting-workflows.md +37 -0
  630. package/skills/opendevbrowser-shopping/assets/templates/deal-thresholds.json +8 -0
  631. package/skills/opendevbrowser-shopping/assets/templates/deals-context.json +9 -0
  632. package/skills/opendevbrowser-shopping/assets/templates/deals-table.md +4 -0
  633. package/skills/opendevbrowser-shopping/assets/templates/market-analysis.json +30 -0
  634. package/skills/opendevbrowser-shopping/examples/sample-deals.md +4 -0
  635. package/skills/opendevbrowser-shopping/examples/sample-query.json +5 -0
  636. package/skills/opendevbrowser-shopping/scripts/analyze-market.sh +307 -0
  637. package/skills/opendevbrowser-shopping/scripts/normalize-offers.sh +28 -0
  638. package/skills/opendevbrowser-shopping/scripts/render-deals.sh +13 -0
  639. package/skills/opendevbrowser-shopping/scripts/run-deal-hunt.sh +32 -0
  640. package/skills/opendevbrowser-shopping/scripts/run-shopping.sh +19 -0
  641. package/skills/opendevbrowser-shopping/scripts/validate-skill-assets.sh +53 -0
  642. package/dist/chunk-JVBMT2O5.js +0 -7173
  643. package/dist/chunk-JVBMT2O5.js.map +0 -1
  644. package/skills/data-extraction/SKILL.md +0 -128
  645. package/skills/form-testing/SKILL.md +0 -106
  646. package/skills/login-automation/SKILL.md +0 -108
package/dist/cli/index.js CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  createOpenDevBrowserCore,
10
10
  createUsageError,
11
11
  extractExtension,
12
+ fetchDaemonStatus,
12
13
  fetchDaemonStatusFromMetadata,
13
14
  fetchWithTimeout,
14
15
  formatErrorPayload,
@@ -18,11 +19,78 @@ import {
18
19
  readDaemonMetadata,
19
20
  resolveExitCode,
20
21
  startDaemon,
21
- toCliError,
22
+ toCliError
23
+ } from "../chunk-5J3IFL3X.js";
24
+ import "../chunk-Y2KL55OG.js";
25
+ import {
22
26
  writeFileAtomic
23
- } from "../chunk-JVBMT2O5.js";
27
+ } from "../chunk-TBUCZX4A.js";
28
+ import "../chunk-V7KUDHDG.js";
29
+ import {
30
+ cleanupExpiredArtifacts
31
+ } from "../chunk-D633UO34.js";
32
+ import "../chunk-FUSXMW3G.js";
24
33
 
25
34
  // src/cli/args.ts
35
+ var CLI_COMMANDS = [
36
+ "install",
37
+ "update",
38
+ "uninstall",
39
+ "help",
40
+ "version",
41
+ "serve",
42
+ "daemon",
43
+ "native",
44
+ "run",
45
+ "launch",
46
+ "connect",
47
+ "disconnect",
48
+ "status",
49
+ "research",
50
+ "shopping",
51
+ "product-video",
52
+ "artifacts",
53
+ "goto",
54
+ "wait",
55
+ "snapshot",
56
+ "click",
57
+ "hover",
58
+ "press",
59
+ "check",
60
+ "uncheck",
61
+ "type",
62
+ "select",
63
+ "scroll",
64
+ "scroll-into-view",
65
+ "targets-list",
66
+ "target-use",
67
+ "target-new",
68
+ "target-close",
69
+ "page",
70
+ "pages",
71
+ "page-close",
72
+ "dom-html",
73
+ "dom-text",
74
+ "dom-attr",
75
+ "dom-value",
76
+ "dom-visible",
77
+ "dom-enabled",
78
+ "dom-checked",
79
+ "clone-page",
80
+ "clone-component",
81
+ "perf",
82
+ "screenshot",
83
+ "console-poll",
84
+ "network-poll",
85
+ "debug-trace-snapshot",
86
+ "cookie-import",
87
+ "cookie-list",
88
+ "macro-resolve",
89
+ "annotate",
90
+ "canvas",
91
+ "rpc"
92
+ ];
93
+ var CLI_COMMAND_SET = new Set(CLI_COMMANDS);
26
94
  var SHORT_FLAGS = {
27
95
  "-g": "--global",
28
96
  "-l": "--local",
@@ -85,12 +153,165 @@ function parseTransport(args) {
85
153
  }
86
154
  throw createUsageError(`Invalid --transport: ${value ?? "missing"}`);
87
155
  }
156
+ var VALID_FLAGS = [
157
+ "--global",
158
+ "--local",
159
+ "--update",
160
+ "--uninstall",
161
+ "--help",
162
+ "--version",
163
+ "--with-config",
164
+ "--no-prompt",
165
+ "--no-interactive",
166
+ "--quiet",
167
+ "--output-format",
168
+ "--full",
169
+ "--port",
170
+ "--token",
171
+ "--stop",
172
+ "--script",
173
+ "--headless",
174
+ "--profile",
175
+ "--persist-profile",
176
+ "--chrome-path",
177
+ "--start-url",
178
+ "--flag",
179
+ "--session-id",
180
+ "--close-browser",
181
+ "--ws-endpoint",
182
+ "--host",
183
+ "--cdp-port",
184
+ "--url",
185
+ "--wait-until",
186
+ "--timeout-ms",
187
+ "--ref",
188
+ "--state",
189
+ "--until",
190
+ "--mode",
191
+ "--max-chars",
192
+ "--cursor",
193
+ "--text",
194
+ "--clear",
195
+ "--submit",
196
+ "--values",
197
+ "--dy",
198
+ "--key",
199
+ "--attr",
200
+ "--name",
201
+ "--target-id",
202
+ "--tab-id",
203
+ "--include-urls",
204
+ "--path",
205
+ "--since-seq",
206
+ "--max",
207
+ "--since-console-seq",
208
+ "--since-network-seq",
209
+ "--since-exception-seq",
210
+ "--request-id",
211
+ "--cookies",
212
+ "--cookies-file",
213
+ "--strict",
214
+ "--expression",
215
+ "--default-provider",
216
+ "--include-catalog",
217
+ "--command",
218
+ "--execute",
219
+ "--params",
220
+ "--params-file",
221
+ "--unsafe-internal",
222
+ "--daemon",
223
+ "--transport",
224
+ "--no-extension",
225
+ "--extension-only",
226
+ "--extension-legacy",
227
+ "--wait-for-extension",
228
+ "--wait-timeout-ms",
229
+ "--skills-global",
230
+ "--skills-local",
231
+ "--no-skills",
232
+ "--screenshot-mode",
233
+ "--debug",
234
+ "--context",
235
+ "--stored",
236
+ "--topic",
237
+ "--days",
238
+ "--from",
239
+ "--to",
240
+ "--source-selection",
241
+ "--sources",
242
+ "--include-engagement",
243
+ "--limit-per-source",
244
+ "--query",
245
+ "--providers",
246
+ "--budget",
247
+ "--region",
248
+ "--sort",
249
+ "--product-url",
250
+ "--product-name",
251
+ "--provider-hint",
252
+ "--include-screenshots",
253
+ "--include-all-images",
254
+ "--include-copy",
255
+ "--output-dir",
256
+ "--ttl-hours",
257
+ "--expired-only"
258
+ ];
259
+ var VALID_FLAG_SET = new Set(VALID_FLAGS);
260
+ var VALID_EQUALS_FLAGS = [
261
+ "--output-format",
262
+ "--transport",
263
+ "--session-id",
264
+ "--url",
265
+ "--screenshot-mode",
266
+ "--context",
267
+ "--timeout-ms",
268
+ "--since-seq",
269
+ "--since-console-seq",
270
+ "--since-network-seq",
271
+ "--since-exception-seq",
272
+ "--max",
273
+ "--target-id",
274
+ "--tab-id",
275
+ "--name",
276
+ "--cookies",
277
+ "--cookies-file",
278
+ "--persist-profile",
279
+ "--expression",
280
+ "--default-provider",
281
+ "--command",
282
+ "--request-id",
283
+ "--strict",
284
+ "--params",
285
+ "--params-file",
286
+ "--topic",
287
+ "--days",
288
+ "--from",
289
+ "--to",
290
+ "--source-selection",
291
+ "--sources",
292
+ "--mode",
293
+ "--limit-per-source",
294
+ "--query",
295
+ "--providers",
296
+ "--budget",
297
+ "--region",
298
+ "--sort",
299
+ "--product-url",
300
+ "--product-name",
301
+ "--provider-hint",
302
+ "--include-screenshots",
303
+ "--include-all-images",
304
+ "--include-copy",
305
+ "--output-dir",
306
+ "--ttl-hours"
307
+ ];
308
+ var VALID_EQUALS_FLAG_SET = new Set(VALID_EQUALS_FLAGS);
88
309
  function parseArgs(argv) {
89
310
  let args = expandShortFlags(argv.slice(2));
90
311
  let commandOverride = null;
91
312
  if (args[0] && !args[0].startsWith("-")) {
92
313
  const candidate = args[0];
93
- if (candidate === "install" || candidate === "update" || candidate === "uninstall" || candidate === "help" || candidate === "version" || candidate === "serve" || candidate === "daemon" || candidate === "native" || candidate === "run" || candidate === "launch" || candidate === "connect" || candidate === "disconnect" || candidate === "status" || candidate === "goto" || candidate === "wait" || candidate === "snapshot" || candidate === "click" || candidate === "hover" || candidate === "press" || candidate === "check" || candidate === "uncheck" || candidate === "type" || candidate === "select" || candidate === "scroll" || candidate === "scroll-into-view" || candidate === "targets-list" || candidate === "target-use" || candidate === "target-new" || candidate === "target-close" || candidate === "page" || candidate === "pages" || candidate === "page-close" || candidate === "dom-html" || candidate === "dom-text" || candidate === "dom-attr" || candidate === "dom-value" || candidate === "dom-visible" || candidate === "dom-enabled" || candidate === "dom-checked" || candidate === "clone-page" || candidate === "clone-component" || candidate === "perf" || candidate === "screenshot" || candidate === "console-poll" || candidate === "network-poll" || candidate === "annotate") {
314
+ if (CLI_COMMAND_SET.has(candidate)) {
94
315
  commandOverride = candidate;
95
316
  args = args.slice(1);
96
317
  } else {
@@ -179,87 +400,11 @@ function parseArgs(argv) {
179
400
  } else if (noPrompt) {
180
401
  mode = "global";
181
402
  }
182
- const validFlags = /* @__PURE__ */ new Set([
183
- "--global",
184
- "--local",
185
- "--update",
186
- "--uninstall",
187
- "--help",
188
- "--version",
189
- "--with-config",
190
- "--no-prompt",
191
- "--no-interactive",
192
- "--quiet",
193
- "--output-format",
194
- "--full",
195
- "--port",
196
- "--token",
197
- "--stop",
198
- "--script",
199
- "--headless",
200
- "--profile",
201
- "--persist-profile",
202
- "--chrome-path",
203
- "--start-url",
204
- "--flag",
205
- "--session-id",
206
- "--close-browser",
207
- "--ws-endpoint",
208
- "--host",
209
- "--cdp-port",
210
- "--url",
211
- "--wait-until",
212
- "--timeout-ms",
213
- "--ref",
214
- "--state",
215
- "--until",
216
- "--mode",
217
- "--max-chars",
218
- "--cursor",
219
- "--text",
220
- "--clear",
221
- "--submit",
222
- "--values",
223
- "--dy",
224
- "--key",
225
- "--attr",
226
- "--name",
227
- "--target-id",
228
- "--tab-id",
229
- "--include-urls",
230
- "--path",
231
- "--since-seq",
232
- "--max",
233
- "--daemon",
234
- "--transport",
235
- "--no-extension",
236
- "--extension-only",
237
- "--extension-legacy",
238
- "--wait-for-extension",
239
- "--wait-timeout-ms",
240
- "--skills-global",
241
- "--skills-local",
242
- "--no-skills",
243
- "--screenshot-mode",
244
- "--debug",
245
- "--context"
246
- ]);
247
- const validEqualsFlags = /* @__PURE__ */ new Set([
248
- "--output-format",
249
- "--transport",
250
- "--session-id",
251
- "--url",
252
- "--screenshot-mode",
253
- "--context",
254
- "--timeout-ms",
255
- "--target-id",
256
- "--tab-id"
257
- ]);
258
403
  for (const arg of args) {
259
- if (arg.startsWith("--") && !validFlags.has(arg)) {
404
+ if (arg.startsWith("--") && !VALID_FLAG_SET.has(arg)) {
260
405
  if (arg.includes("=")) {
261
406
  const baseFlag = arg.split("=", 2)[0] ?? "";
262
- if (validEqualsFlags.has(baseFlag)) {
407
+ if (VALID_EQUALS_FLAG_SET.has(baseFlag)) {
263
408
  continue;
264
409
  }
265
410
  }
@@ -283,94 +428,6 @@ function parseArgs(argv) {
283
428
  rawArgs: args
284
429
  };
285
430
  }
286
- function getHelpText() {
287
- return `
288
- OpenDevBrowser CLI - Install and manage the OpenDevBrowser plugin
289
-
290
- USAGE:
291
- npx opendevbrowser [command] [options]
292
-
293
- COMMANDS:
294
- install Install the plugin (default if no command specified)
295
- update Clear cached plugin to trigger reinstall
296
- uninstall Remove plugin from config
297
- serve Start or stop the local daemon
298
- daemon Install/uninstall/status daemon auto-start
299
- native Install/uninstall/status native messaging host
300
- run Execute a JSON script in a single process
301
- launch Launch a managed browser session via daemon
302
- connect Connect to an existing browser via daemon
303
- disconnect Disconnect a daemon session
304
- status Get daemon status (or session status with --session-id)
305
- goto Navigate current session to a URL
306
- wait Wait for load or a ref to appear
307
- snapshot Capture a snapshot of the active page
308
- click Click an element by ref
309
- hover Hover an element by ref
310
- press Press a keyboard key
311
- check Check a checkbox by ref
312
- uncheck Uncheck a checkbox by ref
313
- type Type into an element by ref
314
- select Select values in a select by ref
315
- scroll Scroll the page or element by ref
316
- scroll-into-view Scroll an element into view by ref
317
- targets-list List page targets
318
- target-use Focus a target by id
319
- target-new Open a new target
320
- target-close Close a target by id
321
- page Open or focus a named page
322
- pages List named pages
323
- page-close Close a named page
324
- dom-html Capture HTML for a ref
325
- dom-text Capture text for a ref
326
- dom-attr Capture attribute value for a ref
327
- dom-value Capture input value for a ref
328
- dom-visible Check visibility for a ref
329
- dom-enabled Check enabled state for a ref
330
- dom-checked Check checked state for a ref
331
- clone-page Clone the active page to React
332
- clone-component Clone a component by ref
333
- perf Capture performance metrics
334
- screenshot Capture a screenshot
335
- console-poll Poll console events
336
- network-poll Poll network events
337
- annotate Request interactive annotations (direct or relay)
338
- help Show this help message
339
- version Show version
340
-
341
- ALIASES:
342
- --update, -u Same as update
343
- --uninstall Same as uninstall
344
- --help, -h Same as help
345
- --version, -v Same as version
346
-
347
- INSTALL OPTIONS:
348
- --global, -g Install to ~/.config/opencode/opencode.json
349
- --local, -l Install to ./opencode.json (project-local)
350
- --with-config Also create opendevbrowser.jsonc with defaults
351
- --full, -f Create config and pre-extract extension assets
352
- --no-prompt Skip prompts, use defaults (global install)
353
- --no-interactive Alias of --no-prompt
354
- --quiet Suppress non-error output
355
- --output-format Output format: text (default), json, stream-json
356
- --transport Transport: relay (default) or native
357
- --skills-global Install bundled skills to ~/.config/opencode/skill (default)
358
- --skills-local Install bundled skills to ./.opencode/skill
359
- --no-skills Skip installing bundled skills
360
-
361
- EXAMPLES:
362
- npx opendevbrowser # Interactive install
363
- npx opendevbrowser --global # Global install
364
- npx opendevbrowser --local # Project install
365
- npx opendevbrowser --full # Install + config + extension assets
366
- npx opendevbrowser -g --with-config # Global + config file
367
- npx opendevbrowser --skills-local # Install skills locally
368
- npx opendevbrowser --no-skills # Skip skill installation
369
- npx opendevbrowser --update # Update plugin
370
- npx opendevbrowser --uninstall --global # Remove from global config
371
- npx opendevbrowser native install <extension-id> # Install native host
372
- `.trim();
373
- }
374
431
  function detectOutputFormat(argv) {
375
432
  const args = expandShortFlags(argv.slice(2));
376
433
  try {
@@ -388,6 +445,383 @@ function registerCommand(definition) {
388
445
  function getCommand(name) {
389
446
  return registry.get(name);
390
447
  }
448
+ function listCommands() {
449
+ return Array.from(registry.values());
450
+ }
451
+
452
+ // src/cli/help.ts
453
+ var LABEL_WIDTH = 42;
454
+ var EXPECTED_TOOL_COUNT = 49;
455
+ var COMMAND_SET = new Set(CLI_COMMANDS);
456
+ var FLAG_SET = new Set(VALID_FLAGS);
457
+ var HELP_COMMAND_GROUPS = [
458
+ {
459
+ title: "Install & Lifecycle",
460
+ summary: "Install, remove, and inspect CLI basics.",
461
+ commands: ["install", "update", "uninstall", "help", "version"]
462
+ },
463
+ {
464
+ title: "Daemon & Runtime",
465
+ summary: "Run daemon services and single-process scripts.",
466
+ commands: ["serve", "daemon", "native", "run"]
467
+ },
468
+ {
469
+ title: "Session Lifecycle",
470
+ summary: "Launch/connect sessions and manage browser state.",
471
+ commands: ["launch", "connect", "disconnect", "status", "cookie-import", "cookie-list"]
472
+ },
473
+ {
474
+ title: "Provider Workflows",
475
+ summary: "Run research/shopping/media workflows and macro plans.",
476
+ commands: ["research", "shopping", "product-video", "artifacts", "macro-resolve"]
477
+ },
478
+ {
479
+ title: "Design Canvas",
480
+ summary: "Execute design-canvas session, document, overlay, and preview commands.",
481
+ commands: ["canvas"]
482
+ },
483
+ {
484
+ title: "Navigation",
485
+ summary: "Move through pages and capture fresh refs.",
486
+ commands: ["goto", "wait", "snapshot"]
487
+ },
488
+ {
489
+ title: "Interaction",
490
+ summary: "Perform ref-based interactions in the active page.",
491
+ commands: ["click", "hover", "press", "check", "uncheck", "type", "select", "scroll", "scroll-into-view"]
492
+ },
493
+ {
494
+ title: "Targets & Pages",
495
+ summary: "Manage tabs/targets and named pages.",
496
+ commands: ["targets-list", "target-use", "target-new", "target-close", "page", "pages", "page-close"]
497
+ },
498
+ {
499
+ title: "DOM & Export",
500
+ summary: "Read DOM state and export page/component code.",
501
+ commands: ["dom-html", "dom-text", "dom-attr", "dom-value", "dom-visible", "dom-enabled", "dom-checked", "clone-page", "clone-component"]
502
+ },
503
+ {
504
+ title: "Diagnostics & Annotation",
505
+ summary: "Collect runtime diagnostics and annotation payloads.",
506
+ commands: ["perf", "screenshot", "console-poll", "network-poll", "debug-trace-snapshot", "annotate"]
507
+ },
508
+ {
509
+ title: "Power",
510
+ summary: "Unsafe internal command passthrough.",
511
+ commands: ["rpc"]
512
+ }
513
+ ];
514
+ var HELP_FLAG_GROUPS = [
515
+ {
516
+ title: "Install/Global Flags",
517
+ summary: "Control installation scope and setup behavior.",
518
+ flags: [
519
+ { flag: "--global", alias: "-g", description: "Install into ~/.config/opencode/opencode.json." },
520
+ { flag: "--local", alias: "-l", description: "Install into ./opencode.json for this project." },
521
+ { flag: "--update", alias: "-u", description: "Alias for the update command." },
522
+ { flag: "--uninstall", description: "Alias for the uninstall command." },
523
+ { flag: "--with-config", description: "Also create opendevbrowser.jsonc defaults." },
524
+ { flag: "--full", alias: "-f", description: "Install config and pre-extract extension assets." },
525
+ { flag: "--no-prompt", description: "Run non-interactively using defaults." },
526
+ { flag: "--no-interactive", description: "Alias of --no-prompt." },
527
+ { flag: "--quiet", description: "Suppress non-error text output." },
528
+ { flag: "--skills-global", description: "Install bundled skills into global agent directories." },
529
+ { flag: "--skills-local", description: "Install bundled skills into local project agent directories." },
530
+ { flag: "--no-skills", description: "Skip bundled skill installation." }
531
+ ]
532
+ },
533
+ {
534
+ title: "Help/Output Flags",
535
+ summary: "Inspect help/version and control output transport.",
536
+ flags: [
537
+ { flag: "--help", alias: "-h", description: "Show CLI help output." },
538
+ { flag: "--version", alias: "-v", description: "Show CLI version." },
539
+ { flag: "--output-format", description: "Output mode: text, json, stream-json." },
540
+ { flag: "--transport", description: "Transport selector for transport-aware commands. `status` uses relay/native; `annotate` uses auto/direct/relay." }
541
+ ]
542
+ },
543
+ {
544
+ title: "Daemon/Session/Launch Flags",
545
+ summary: "Control daemon binding, connect, and launch behavior.",
546
+ flags: [
547
+ { flag: "--port", description: "Daemon or relay port override." },
548
+ { flag: "--token", description: "Relay/daemon auth token override." },
549
+ { flag: "--stop", description: "Stop a running daemon." },
550
+ { flag: "--daemon", description: "Target daemon status mode where supported." },
551
+ { flag: "--script", description: "Path to a run-script JSON file." },
552
+ { flag: "--session-id", description: "Target an existing daemon session." },
553
+ { flag: "--close-browser", description: "Close managed browser on disconnect." },
554
+ { flag: "--ws-endpoint", description: "Connect using explicit CDP WebSocket endpoint." },
555
+ { flag: "--host", description: "CDP host for host/port connect mode." },
556
+ { flag: "--cdp-port", description: "CDP port for host/port connect mode." },
557
+ { flag: "--headless", description: "Launch managed browser in headless mode." },
558
+ { flag: "--profile", description: "Use a named browser profile directory." },
559
+ { flag: "--persist-profile", description: "Keep generated profile directory after exit." },
560
+ { flag: "--chrome-path", description: "Use a specific Chrome/Chromium binary." },
561
+ { flag: "--start-url", description: "Open this URL immediately after launch or connect." },
562
+ { flag: "--flag", description: "Pass one or more extra Chrome CLI flags." },
563
+ { flag: "--no-extension", description: "Force managed mode without extension relay." },
564
+ { flag: "--extension-only", description: "Fail unless extension relay is connected." },
565
+ { flag: "--extension-legacy", description: "Use legacy /cdp relay mode instead of /ops." },
566
+ { flag: "--wait-for-extension", description: "Wait for extension handshake before returning." },
567
+ { flag: "--wait-timeout-ms", description: "Handshake wait timeout in milliseconds." }
568
+ ]
569
+ },
570
+ {
571
+ title: "Navigation/Interaction/Diagnostics Flags",
572
+ summary: "Command-specific flags for page actions and diagnostics.",
573
+ flags: [
574
+ { flag: "--url", description: "Target URL for navigation, connect, or workflow commands." },
575
+ { flag: "--wait-until", description: "Navigation wait strategy (load, domcontentloaded, etc.)." },
576
+ { flag: "--timeout-ms", description: "Operation timeout in milliseconds (for example goto, wait, screenshot, annotate, canvas, rpc, and macro-resolve)." },
577
+ { flag: "--ref", description: "Snapshot ref id for element-targeted commands." },
578
+ { flag: "--state", description: "Wait state selector for wait-style commands." },
579
+ { flag: "--until", description: "Wait condition selector for wait-style commands." },
580
+ { flag: "--mode", description: "Mode selector for commands that accept variants." },
581
+ { flag: "--max-chars", description: "Maximum text characters to return for DOM reads." },
582
+ { flag: "--cursor", description: "Cursor token for paginated list commands." },
583
+ { flag: "--text", description: "Text payload for type and related commands." },
584
+ { flag: "--clear", description: "Clear existing input value before typing." },
585
+ { flag: "--submit", description: "Submit form/input after typing." },
586
+ { flag: "--values", description: "CSV values for select commands." },
587
+ { flag: "--dy", description: "Vertical scroll delta for scroll commands." },
588
+ { flag: "--key", description: "Keyboard key for press command." },
589
+ { flag: "--attr", description: "DOM attribute name for dom-attr command." },
590
+ { flag: "--name", description: "Named page identifier for page commands." },
591
+ { flag: "--target-id", description: "Browser target id for target commands." },
592
+ { flag: "--tab-id", description: "Browser tab id override for extension/annotation commands." },
593
+ { flag: "--include-urls", description: "Include page URLs in list output where supported." },
594
+ { flag: "--path", description: "Filesystem path for command output/artifacts." },
595
+ { flag: "--since-seq", description: "Poll from sequence id across diagnostics streams." },
596
+ { flag: "--max", description: "Maximum number of records/items to return." },
597
+ { flag: "--since-console-seq", description: "Console sequence cursor for debug trace snapshots." },
598
+ { flag: "--since-network-seq", description: "Network sequence cursor for debug trace snapshots." },
599
+ { flag: "--since-exception-seq", description: "Exception sequence cursor for debug trace snapshots." },
600
+ { flag: "--request-id", description: "Attach/lookup request id for correlateable output." },
601
+ { flag: "--cookies", description: "Inline cookie payload for cookie-import command." },
602
+ { flag: "--cookies-file", description: "File path containing cookies for cookie-import." },
603
+ { flag: "--strict", description: "Fail cookie import on invalid entries." },
604
+ { flag: "--screenshot-mode", description: "Annotation screenshot mode: visible, full, or none." },
605
+ { flag: "--debug", description: "Enable debug-level annotation capture extras." },
606
+ { flag: "--context", description: "Free-form annotation context for reviewers/agents." },
607
+ { flag: "--stored", description: "Return the last stored annotation payload instead of starting a new capture." }
608
+ ]
609
+ },
610
+ {
611
+ title: "Macro/Provider/Power Flags",
612
+ summary: "Workflow filters, provider selectors, and unsafe RPC options.",
613
+ flags: [
614
+ { flag: "--expression", description: "Macro expression to resolve/execute." },
615
+ { flag: "--default-provider", description: "Provider fallback for shorthand macro expressions." },
616
+ { flag: "--include-catalog", description: "Include macro catalog metadata in response." },
617
+ { flag: "--execute", description: "Execute resolved macro action after planning (pair with --timeout-ms on slow runs)." },
618
+ { flag: "--command", description: "Canvas command name for the canvas CLI command." },
619
+ { flag: "--params", description: "Inline JSON params for canvas or rpc commands." },
620
+ { flag: "--params-file", description: "Path to JSON params file for canvas or rpc commands." },
621
+ { flag: "--unsafe-internal", description: "Required safety gate for rpc command." },
622
+ { flag: "--topic", description: "Research topic input." },
623
+ { flag: "--days", description: "Lookback window in days for research commands." },
624
+ { flag: "--from", description: "Start date boundary for research commands." },
625
+ { flag: "--to", description: "End date boundary for research commands." },
626
+ { flag: "--source-selection", description: "Research source-family selector." },
627
+ { flag: "--sources", description: "Explicit source selectors within a source family." },
628
+ { flag: "--include-engagement", description: "Include engagement metrics in research output." },
629
+ { flag: "--limit-per-source", description: "Per-source result cap for research runs." },
630
+ { flag: "--query", description: "Shopping query input." },
631
+ { flag: "--providers", description: "Comma-separated provider ids for shopping/artifacts." },
632
+ { flag: "--budget", description: "Budget filter for shopping workflows." },
633
+ { flag: "--region", description: "Region/country hint for provider selection." },
634
+ { flag: "--sort", description: "Sort mode for shopping results." },
635
+ { flag: "--product-url", description: "Target product URL for product-video/artifacts workflows." },
636
+ { flag: "--product-name", description: "Product name override for media workflows." },
637
+ { flag: "--provider-hint", description: "Provider hint override for product workflows." },
638
+ { flag: "--include-screenshots", description: "Include screenshots in product presentation output, or prefer screenshots when fetching stored annotations." },
639
+ { flag: "--include-all-images", description: "Include all discovered product images." },
640
+ { flag: "--include-copy", description: "Include product marketing copy metadata." },
641
+ { flag: "--output-dir", description: "Directory where generated artifacts are written." },
642
+ { flag: "--ttl-hours", description: "Artifact cache time-to-live in hours." },
643
+ { flag: "--expired-only", description: "List only expired artifacts in artifacts commands." }
644
+ ]
645
+ }
646
+ ];
647
+ var HELP_TOOL_ENTRIES = [
648
+ { name: "opendevbrowser_launch", description: "Launch a managed browser session." },
649
+ { name: "opendevbrowser_connect", description: "Connect to an existing browser session." },
650
+ { name: "opendevbrowser_disconnect", description: "Disconnect a managed or connected session." },
651
+ { name: "opendevbrowser_status", description: "Inspect session and relay status." },
652
+ { name: "opendevbrowser_targets_list", description: "List available page targets/tabs." },
653
+ { name: "opendevbrowser_target_use", description: "Switch active target by id." },
654
+ { name: "opendevbrowser_target_new", description: "Create a new target/tab." },
655
+ { name: "opendevbrowser_target_close", description: "Close target/tab by id." },
656
+ { name: "opendevbrowser_page", description: "Open or focus a named page." },
657
+ { name: "opendevbrowser_list", description: "List named pages in the session." },
658
+ { name: "opendevbrowser_close", description: "Close a named page." },
659
+ { name: "opendevbrowser_goto", description: "Navigate to a URL." },
660
+ { name: "opendevbrowser_wait", description: "Wait for load/ref/state conditions." },
661
+ { name: "opendevbrowser_snapshot", description: "Capture AX-tree refs for actions." },
662
+ { name: "opendevbrowser_click", description: "Click an element by ref." },
663
+ { name: "opendevbrowser_hover", description: "Hover an element by ref." },
664
+ { name: "opendevbrowser_press", description: "Send a keyboard key." },
665
+ { name: "opendevbrowser_check", description: "Check checkbox/radio by ref." },
666
+ { name: "opendevbrowser_uncheck", description: "Uncheck checkbox/radio by ref." },
667
+ { name: "opendevbrowser_type", description: "Type text into an input by ref." },
668
+ { name: "opendevbrowser_select", description: "Set select values by ref." },
669
+ { name: "opendevbrowser_scroll", description: "Scroll page or element." },
670
+ { name: "opendevbrowser_scroll_into_view", description: "Scroll target element into view." },
671
+ { name: "opendevbrowser_dom_get_html", description: "Get HTML for page or ref." },
672
+ { name: "opendevbrowser_dom_get_text", description: "Get text for page or ref." },
673
+ { name: "opendevbrowser_get_attr", description: "Read a DOM attribute by ref." },
674
+ { name: "opendevbrowser_get_value", description: "Read form/control value by ref." },
675
+ { name: "opendevbrowser_is_visible", description: "Check ref visibility." },
676
+ { name: "opendevbrowser_is_enabled", description: "Check ref enabled state." },
677
+ { name: "opendevbrowser_is_checked", description: "Check ref checked state." },
678
+ { name: "opendevbrowser_run", description: "Execute multi-action automation scripts." },
679
+ { name: "opendevbrowser_prompting_guide", description: "Return best-practice prompting guidance." },
680
+ { name: "opendevbrowser_console_poll", description: "Poll redacted console events." },
681
+ { name: "opendevbrowser_network_poll", description: "Poll redacted network events." },
682
+ { name: "opendevbrowser_debug_trace_snapshot", description: "Capture page + console + network diagnostics." },
683
+ { name: "opendevbrowser_cookie_import", description: "Import validated cookies into session." },
684
+ { name: "opendevbrowser_cookie_list", description: "List cookies in session with optional URL filters." },
685
+ { name: "opendevbrowser_macro_resolve", description: "Resolve/execute provider macro expressions." },
686
+ { name: "opendevbrowser_research_run", description: "Run research workflow directly." },
687
+ { name: "opendevbrowser_shopping_run", description: "Run shopping workflow directly." },
688
+ { name: "opendevbrowser_product_video_run", description: "Run product-video asset workflow directly." },
689
+ { name: "opendevbrowser_canvas", description: "Execute a design-canvas command surface call." },
690
+ { name: "opendevbrowser_clone_page", description: "Export active page into React code." },
691
+ { name: "opendevbrowser_clone_component", description: "Export component by ref into React code." },
692
+ { name: "opendevbrowser_perf", description: "Collect browser performance metrics." },
693
+ { name: "opendevbrowser_screenshot", description: "Capture page screenshot." },
694
+ { name: "opendevbrowser_annotate", description: "Capture interactive annotations." },
695
+ { name: "opendevbrowser_skill_list", description: "List available skill packs." },
696
+ { name: "opendevbrowser_skill_load", description: "Load a specific skill pack." }
697
+ ];
698
+ var HELP_REFERENCE_ENTRIES = [
699
+ { label: "docs/CLI.md", description: "Full command docs, flag matrix, and examples." },
700
+ { label: "docs/SURFACE_REFERENCE.md", description: "Canonical CLI/tool/channel inventory matrix." },
701
+ { label: "src/tools/index.ts", description: "Code-level tool registry (source of truth)." },
702
+ { label: "opendevbrowser --help", description: "Primary full help invocation for quick discovery." },
703
+ { label: "opendevbrowser help", description: "Alias that prints the same full help inventory." }
704
+ ];
705
+ function formatRows(rows) {
706
+ return rows.map((row) => ` ${row.label.padEnd(LABEL_WIDTH)} ${row.description}`).join("\n");
707
+ }
708
+ function getCommandDescriptions() {
709
+ const descriptions = /* @__PURE__ */ new Map();
710
+ for (const definition of listCommands()) {
711
+ descriptions.set(definition.name, definition.description);
712
+ }
713
+ return descriptions;
714
+ }
715
+ function assertCommandCoverage(commandDescriptions) {
716
+ const seen = /* @__PURE__ */ new Set();
717
+ for (const group of HELP_COMMAND_GROUPS) {
718
+ for (const command of group.commands) {
719
+ if (!COMMAND_SET.has(command)) {
720
+ throw new Error(`Help references unknown CLI command: ${command}`);
721
+ }
722
+ if (!commandDescriptions.has(command)) {
723
+ throw new Error(`Help references unregistered CLI command: ${command}`);
724
+ }
725
+ if (seen.has(command)) {
726
+ throw new Error(`Help command appears multiple times: ${command}`);
727
+ }
728
+ seen.add(command);
729
+ }
730
+ }
731
+ if (seen.size !== CLI_COMMANDS.length) {
732
+ const missing = CLI_COMMANDS.filter((command) => !seen.has(command));
733
+ throw new Error(`Help command coverage mismatch; missing: ${missing.join(", ")}`);
734
+ }
735
+ }
736
+ function assertFlagCoverage() {
737
+ const seen = /* @__PURE__ */ new Set();
738
+ for (const group of HELP_FLAG_GROUPS) {
739
+ for (const entry of group.flags) {
740
+ if (!FLAG_SET.has(entry.flag)) {
741
+ throw new Error(`Help references unknown CLI flag: ${entry.flag}`);
742
+ }
743
+ if (seen.has(entry.flag)) {
744
+ throw new Error(`Help flag appears multiple times: ${entry.flag}`);
745
+ }
746
+ seen.add(entry.flag);
747
+ }
748
+ }
749
+ if (seen.size !== VALID_FLAGS.length) {
750
+ const missing = VALID_FLAGS.filter((flag) => !seen.has(flag));
751
+ throw new Error(`Help flag coverage mismatch; missing: ${missing.join(", ")}`);
752
+ }
753
+ }
754
+ function assertToolCoverage() {
755
+ if (HELP_TOOL_ENTRIES.length !== EXPECTED_TOOL_COUNT) {
756
+ throw new Error(`Help tool inventory must list ${EXPECTED_TOOL_COUNT} tools; got ${HELP_TOOL_ENTRIES.length}`);
757
+ }
758
+ const seen = /* @__PURE__ */ new Set();
759
+ for (const entry of HELP_TOOL_ENTRIES) {
760
+ if (seen.has(entry.name)) {
761
+ throw new Error(`Help tool appears multiple times: ${entry.name}`);
762
+ }
763
+ if (!entry.name.startsWith("opendevbrowser_")) {
764
+ throw new Error(`Invalid tool name in help inventory: ${entry.name}`);
765
+ }
766
+ seen.add(entry.name);
767
+ }
768
+ }
769
+ function formatCommandGroups(commandDescriptions) {
770
+ return HELP_COMMAND_GROUPS.map((group) => {
771
+ const rows = group.commands.map((command) => ({
772
+ label: command,
773
+ description: commandDescriptions.get(command) ?? "Missing command description."
774
+ }));
775
+ return `${group.title}: ${group.summary}
776
+ ${formatRows(rows)}`;
777
+ }).join("\n\n");
778
+ }
779
+ function formatFlagGroups() {
780
+ return HELP_FLAG_GROUPS.map((group) => {
781
+ const rows = group.flags.map((entry) => ({
782
+ label: entry.alias ? `${entry.flag} (${entry.alias})` : entry.flag,
783
+ description: entry.description
784
+ }));
785
+ return `${group.title}: ${group.summary}
786
+ ${formatRows(rows)}`;
787
+ }).join("\n\n");
788
+ }
789
+ function formatToolEntries() {
790
+ return formatRows(HELP_TOOL_ENTRIES.map((entry) => ({
791
+ label: entry.name,
792
+ description: entry.description
793
+ })));
794
+ }
795
+ function formatReferenceEntries() {
796
+ return formatRows(HELP_REFERENCE_ENTRIES.map((entry) => ({
797
+ label: entry.label,
798
+ description: entry.description
799
+ })));
800
+ }
801
+ function getHelpText() {
802
+ const commandDescriptions = getCommandDescriptions();
803
+ assertCommandCoverage(commandDescriptions);
804
+ assertFlagCoverage();
805
+ assertToolCoverage();
806
+ return [
807
+ "OpenDevBrowser CLI",
808
+ "",
809
+ "Usage:",
810
+ " npx opendevbrowser <command> [options]",
811
+ "",
812
+ `Command Inventory (all ${CLI_COMMANDS.length} commands):`,
813
+ formatCommandGroups(commandDescriptions),
814
+ "",
815
+ "Flag Inventory (all supported flags):",
816
+ formatFlagGroups(),
817
+ "",
818
+ `Tool Inventory (all ${EXPECTED_TOOL_COUNT} opendevbrowser_* tools):`,
819
+ formatToolEntries(),
820
+ "",
821
+ "Reference Pointers:",
822
+ formatReferenceEntries()
823
+ ].join("\n");
824
+ }
391
825
 
392
826
  // src/cli/installers/global.ts
393
827
  import * as fs3 from "fs";
@@ -504,7 +938,7 @@ function buildConfigTemplate(relayToken, daemonToken) {
504
938
  "skills": {
505
939
  "nudge": {
506
940
  "enabled": true,
507
- "keywords": ["login", "form", "extract"],
941
+ "keywords": ["quick start", "getting started", "launch", "connect", "setup"],
508
942
  "maxAgeMs": 60000
509
943
  }
510
944
  },
@@ -655,6 +1089,7 @@ import * as os3 from "os";
655
1089
  import { fileURLToPath } from "url";
656
1090
  var PACKAGE_NAME = "opendevbrowser";
657
1091
  var SKILL_DIR_NAME = "skill";
1092
+ var SKILLS_DIR_NAME = "skills";
658
1093
  var cachedPackageRoot = null;
659
1094
  function findPackageRoot(startDir) {
660
1095
  let current = startDir;
@@ -697,33 +1132,108 @@ function getGlobalSkillDir() {
697
1132
  function getLocalSkillDir() {
698
1133
  return path3.join(process.cwd(), ".opencode", SKILL_DIR_NAME);
699
1134
  }
1135
+ function getCodexHomeDir() {
1136
+ return process.env.CODEX_HOME || path3.join(os3.homedir(), ".codex");
1137
+ }
1138
+ function getClaudeCodeHomeDir() {
1139
+ return process.env.CLAUDECODE_HOME || process.env.CLAUDE_HOME || path3.join(os3.homedir(), ".claude");
1140
+ }
1141
+ function getAmpHomeDir() {
1142
+ return process.env.AMPCLI_HOME || process.env.AMP_CLI_HOME || process.env.AMP_HOME || path3.join(os3.homedir(), ".amp");
1143
+ }
1144
+ function dedupeTargets(targets) {
1145
+ const deduped = /* @__PURE__ */ new Map();
1146
+ for (const target of targets) {
1147
+ const key = path3.resolve(target.dir);
1148
+ const existing = deduped.get(key);
1149
+ if (existing) {
1150
+ if (!existing.agents.includes(target.agent)) {
1151
+ existing.agents.push(target.agent);
1152
+ }
1153
+ continue;
1154
+ }
1155
+ deduped.set(key, { agents: [target.agent], dir: target.dir });
1156
+ }
1157
+ return Array.from(deduped.values());
1158
+ }
1159
+ function getGlobalSkillTargets() {
1160
+ const claudeSkillsDir = path3.join(getClaudeCodeHomeDir(), SKILLS_DIR_NAME);
1161
+ const ampSkillsDir = path3.join(getAmpHomeDir(), SKILLS_DIR_NAME);
1162
+ return dedupeTargets([
1163
+ { agent: "opencode", dir: getGlobalSkillDir() },
1164
+ { agent: "codex", dir: path3.join(getCodexHomeDir(), SKILLS_DIR_NAME) },
1165
+ { agent: "claudecode", dir: claudeSkillsDir },
1166
+ { agent: "claude", dir: claudeSkillsDir },
1167
+ { agent: "ampcli", dir: ampSkillsDir },
1168
+ { agent: "amp", dir: ampSkillsDir }
1169
+ ]);
1170
+ }
1171
+ function getLocalSkillTargets() {
1172
+ const localClaudeSkillsDir = path3.join(process.cwd(), ".claude", SKILLS_DIR_NAME);
1173
+ const localAmpSkillsDir = path3.join(process.cwd(), ".amp", SKILLS_DIR_NAME);
1174
+ return dedupeTargets([
1175
+ { agent: "opencode", dir: getLocalSkillDir() },
1176
+ { agent: "codex", dir: path3.join(process.cwd(), ".codex", SKILLS_DIR_NAME) },
1177
+ { agent: "claudecode", dir: localClaudeSkillsDir },
1178
+ { agent: "claude", dir: localClaudeSkillsDir },
1179
+ { agent: "ampcli", dir: localAmpSkillsDir },
1180
+ { agent: "amp", dir: localAmpSkillsDir }
1181
+ ]);
1182
+ }
700
1183
 
701
1184
  // src/cli/installers/skills.ts
702
1185
  function installSkills(mode) {
703
- const targetDir = mode === "global" ? getGlobalSkillDir() : getLocalSkillDir();
704
- const installed = [];
705
- const skipped = [];
1186
+ const targets = mode === "global" ? getGlobalSkillTargets() : getLocalSkillTargets();
1187
+ const targetResults = [];
706
1188
  try {
707
1189
  const sourceDir = getBundledSkillsDir();
708
1190
  const entries = fs6.readdirSync(sourceDir, { withFileTypes: true });
709
- ensureDir(targetDir);
710
- for (const entry of entries) {
711
- if (!entry.isDirectory()) continue;
712
- const skillName = entry.name;
713
- const sourcePath = path4.join(sourceDir, skillName);
714
- const targetPath = path4.join(targetDir, skillName);
715
- if (fs6.existsSync(targetPath)) {
716
- skipped.push(skillName);
717
- continue;
1191
+ for (const target of targets) {
1192
+ const installed2 = [];
1193
+ const skipped2 = [];
1194
+ try {
1195
+ ensureDir(target.dir);
1196
+ for (const entry of entries) {
1197
+ if (!entry.isDirectory()) continue;
1198
+ const skillName = entry.name;
1199
+ const sourcePath = path4.join(sourceDir, skillName);
1200
+ const targetPath = path4.join(target.dir, skillName);
1201
+ if (fs6.existsSync(targetPath)) {
1202
+ skipped2.push(skillName);
1203
+ continue;
1204
+ }
1205
+ fs6.cpSync(sourcePath, targetPath, { recursive: true });
1206
+ installed2.push(skillName);
1207
+ }
1208
+ targetResults.push({
1209
+ agents: target.agents,
1210
+ targetDir: target.dir,
1211
+ installed: installed2,
1212
+ skipped: skipped2,
1213
+ success: true
1214
+ });
1215
+ } catch (error) {
1216
+ const message = error instanceof Error ? error.message : String(error);
1217
+ targetResults.push({
1218
+ agents: target.agents,
1219
+ targetDir: target.dir,
1220
+ installed: installed2,
1221
+ skipped: skipped2,
1222
+ success: false,
1223
+ error: message
1224
+ });
718
1225
  }
719
- fs6.cpSync(sourcePath, targetPath, { recursive: true });
720
- installed.push(skillName);
721
1226
  }
722
- const summary = `Skills ${mode} install: ${installed.length} installed${skipped.length ? `, ${skipped.length} skipped` : ""} (${targetDir})`;
1227
+ const installed = targetResults.flatMap((result) => result.installed);
1228
+ const skipped = targetResults.flatMap((result) => result.skipped);
1229
+ const failures = targetResults.filter((result) => !result.success);
1230
+ const failedSummary = failures.length > 0 ? `, ${failures.length} failed` : "";
1231
+ const summary = `Skills ${mode} install: ${installed.length} installed${skipped.length ? `, ${skipped.length} skipped` : ""}${failedSummary} across ${targetResults.length} targets`;
723
1232
  return {
724
- success: true,
1233
+ success: failures.length === 0,
725
1234
  message: summary,
726
- targetDir,
1235
+ mode,
1236
+ targets: targetResults,
727
1237
  installed,
728
1238
  skipped
729
1239
  };
@@ -732,9 +1242,10 @@ function installSkills(mode) {
732
1242
  return {
733
1243
  success: false,
734
1244
  message: `Failed to install skills (${mode}): ${message}`,
735
- targetDir,
736
- installed,
737
- skipped
1245
+ mode,
1246
+ targets: targetResults,
1247
+ installed: targetResults.flatMap((result) => result.installed),
1248
+ skipped: targetResults.flatMap((result) => result.skipped)
738
1249
  };
739
1250
  }
740
1251
  }
@@ -866,6 +1377,9 @@ function findInstalledConfigs() {
866
1377
  return { global, local };
867
1378
  }
868
1379
 
1380
+ // src/cli/commands/serve.ts
1381
+ import { spawnSync } from "child_process";
1382
+
869
1383
  // src/cli/utils/parse.ts
870
1384
  function parseNumberFlag(value, flag, options = {}) {
871
1385
  const parsed = Number(value);
@@ -884,6 +1398,26 @@ function parseNumberFlag(value, flag, options = {}) {
884
1398
  }
885
1399
  return parsed;
886
1400
  }
1401
+ function parseOptionalStringFlag(rawArgs, flag) {
1402
+ for (let i = 0; i < rawArgs.length; i += 1) {
1403
+ const arg = rawArgs[i];
1404
+ if (arg === flag) {
1405
+ const value = rawArgs[i + 1];
1406
+ if (!value) {
1407
+ throw createUsageError(`Missing value for ${flag}`);
1408
+ }
1409
+ return value;
1410
+ }
1411
+ if (arg?.startsWith(`${flag}=`)) {
1412
+ const value = arg.split("=", 2)[1];
1413
+ if (!value) {
1414
+ throw createUsageError(`Missing value for ${flag}`);
1415
+ }
1416
+ return value;
1417
+ }
1418
+ }
1419
+ return void 0;
1420
+ }
887
1421
 
888
1422
  // src/cli/commands/native.ts
889
1423
  import * as fs9 from "fs";
@@ -1125,39 +1659,6 @@ var getExtensionPathCandidates = () => {
1125
1659
  }
1126
1660
  return [...candidates];
1127
1661
  };
1128
- var getNativeStatusSnapshot = () => {
1129
- const hostScript = getHostScriptPath();
1130
- const manifestPath = getManifestPath();
1131
- const wrapperPath = getWrapperPath();
1132
- const registryPath = readRegistryPath();
1133
- let installed = false;
1134
- let manifestExists = false;
1135
- let wrapperExists = false;
1136
- let extensionIdValue = null;
1137
- if (fs9.existsSync(manifestPath)) {
1138
- manifestExists = true;
1139
- installed = true;
1140
- const manifest = readManifest(manifestPath);
1141
- extensionIdValue = manifest.extensionId;
1142
- }
1143
- if (fs9.existsSync(wrapperPath)) {
1144
- wrapperExists = true;
1145
- }
1146
- if (!manifestExists || !wrapperExists) {
1147
- installed = false;
1148
- }
1149
- if (process.platform === "win32" && !registryPath) {
1150
- installed = false;
1151
- }
1152
- return {
1153
- installed,
1154
- manifestPath: manifestExists ? manifestPath : null,
1155
- wrapperPath: wrapperExists ? wrapperPath : null,
1156
- hostScriptPath: hostScript,
1157
- extensionId: extensionIdValue,
1158
- registryPath
1159
- };
1160
- };
1161
1662
  function discoverExtensionId() {
1162
1663
  const extensionPaths = getExtensionPathCandidates();
1163
1664
  const roots = getChromeUserDataRoots();
@@ -1175,7 +1676,7 @@ function discoverExtensionId() {
1175
1676
  return { extensionId: match.id, matchedBy: match.matchedBy };
1176
1677
  }
1177
1678
  if (!nameFallback) {
1178
- nameFallback = match;
1679
+ nameFallback = { id: match.id, matchedBy: "name" };
1179
1680
  }
1180
1681
  }
1181
1682
  if (!commandFallback) {
@@ -1192,6 +1693,81 @@ function discoverExtensionId() {
1192
1693
  }
1193
1694
  return { extensionId: null };
1194
1695
  }
1696
+ var resolveExpectedExtension = () => {
1697
+ let configuredExtensionId = null;
1698
+ try {
1699
+ configuredExtensionId = normalizeExtensionId(loadGlobalConfig().nativeExtensionId);
1700
+ } catch {
1701
+ configuredExtensionId = null;
1702
+ }
1703
+ const discovered = discoverExtensionId();
1704
+ const discoveredExtensionId = discovered.extensionId ?? null;
1705
+ const discoveredMatchedBy = discovered.matchedBy ?? null;
1706
+ if (discoveredExtensionId) {
1707
+ return {
1708
+ discoveredExtensionId,
1709
+ discoveredMatchedBy,
1710
+ expectedExtensionId: discoveredExtensionId,
1711
+ expectedExtensionSource: discoveredMatchedBy
1712
+ };
1713
+ }
1714
+ if (configuredExtensionId) {
1715
+ return {
1716
+ discoveredExtensionId,
1717
+ discoveredMatchedBy,
1718
+ expectedExtensionId: configuredExtensionId,
1719
+ expectedExtensionSource: "config"
1720
+ };
1721
+ }
1722
+ return {
1723
+ discoveredExtensionId,
1724
+ discoveredMatchedBy,
1725
+ expectedExtensionId: null,
1726
+ expectedExtensionSource: null
1727
+ };
1728
+ };
1729
+ var getNativeStatusSnapshot = () => {
1730
+ const expectation = resolveExpectedExtension();
1731
+ const hostScript = getHostScriptPath();
1732
+ const manifestPath = getManifestPath();
1733
+ const wrapperPath = getWrapperPath();
1734
+ const registryPath = readRegistryPath();
1735
+ let installed = false;
1736
+ let manifestExists = false;
1737
+ let wrapperExists = false;
1738
+ let extensionIdValue = null;
1739
+ if (fs9.existsSync(manifestPath)) {
1740
+ manifestExists = true;
1741
+ installed = true;
1742
+ const manifest = readManifest(manifestPath);
1743
+ extensionIdValue = manifest.extensionId;
1744
+ }
1745
+ if (fs9.existsSync(wrapperPath)) {
1746
+ wrapperExists = true;
1747
+ }
1748
+ if (!manifestExists || !wrapperExists) {
1749
+ installed = false;
1750
+ }
1751
+ if (process.platform === "win32" && !registryPath) {
1752
+ installed = false;
1753
+ }
1754
+ const mismatch = Boolean(
1755
+ installed && extensionIdValue && expectation.expectedExtensionId && extensionIdValue !== expectation.expectedExtensionId
1756
+ );
1757
+ return {
1758
+ installed,
1759
+ manifestPath: manifestExists ? manifestPath : null,
1760
+ wrapperPath: wrapperExists ? wrapperPath : null,
1761
+ hostScriptPath: hostScript,
1762
+ extensionId: extensionIdValue,
1763
+ registryPath,
1764
+ discoveredExtensionId: expectation.discoveredExtensionId,
1765
+ discoveredMatchedBy: expectation.discoveredMatchedBy,
1766
+ expectedExtensionId: expectation.expectedExtensionId,
1767
+ expectedExtensionSource: expectation.expectedExtensionSource,
1768
+ mismatch
1769
+ };
1770
+ };
1195
1771
  function installNativeHost(extensionId) {
1196
1772
  const normalized = normalizeExtensionId(extensionId);
1197
1773
  if (!normalized) {
@@ -1253,12 +1829,33 @@ async function runNativeCommand(args) {
1253
1829
  exitCode: EXIT_DISCONNECTED
1254
1830
  };
1255
1831
  }
1832
+ if (data.mismatch && data.extensionId && data.expectedExtensionId) {
1833
+ return {
1834
+ success: false,
1835
+ message: `Native host targets ${data.extensionId}, but the current extension is ${data.expectedExtensionId}. Reinstall with \`opendevbrowser native install ${data.expectedExtensionId}\` or rerun \`opendevbrowser serve\`.`,
1836
+ data,
1837
+ exitCode: EXIT_DISCONNECTED
1838
+ };
1839
+ }
1256
1840
  const message = data.extensionId ? `Native host installed for extension ${data.extensionId}.` : "Native host installed (extension id missing).";
1257
1841
  return { success: true, message, data };
1258
1842
  }
1259
1843
 
1260
1844
  // src/cli/commands/serve.ts
1261
1845
  var daemonHandle = null;
1846
+ var PS_MAX_BUFFER = 8 * 1024 * 1024;
1847
+ function resolveTokenCandidates(requestedToken, metadataToken, configToken) {
1848
+ return Array.from(new Set([requestedToken, metadataToken, configToken].filter((token) => typeof token === "string" && token.trim().length > 0)));
1849
+ }
1850
+ async function resolveExistingDaemon(port, tokens) {
1851
+ for (const token of tokens) {
1852
+ const status = await fetchDaemonStatus(port, token);
1853
+ if (status?.ok) {
1854
+ return { token, status };
1855
+ }
1856
+ }
1857
+ return null;
1858
+ }
1262
1859
  function parseServeArgs(rawArgs) {
1263
1860
  const parsed = { stop: false };
1264
1861
  for (let i = 0; i < rawArgs.length; i += 1) {
@@ -1304,11 +1901,64 @@ function parseServeArgs(rawArgs) {
1304
1901
  }
1305
1902
  return parsed;
1306
1903
  }
1904
+ function listServeProcessPids() {
1905
+ const result = spawnSync("ps", ["-ax", "-o", "pid=,command="], {
1906
+ encoding: "utf-8",
1907
+ maxBuffer: PS_MAX_BUFFER
1908
+ });
1909
+ if ((result.status ?? 1) !== 0) {
1910
+ return [];
1911
+ }
1912
+ const servePattern = /\b(opendevbrowser|dist\/cli\/index\.js)\b.*\bserve\b/;
1913
+ const lines = String(result.stdout ?? "").split(/\r?\n/);
1914
+ const pids = /* @__PURE__ */ new Set();
1915
+ for (const line of lines) {
1916
+ const trimmed = line.trim();
1917
+ if (!trimmed) continue;
1918
+ const match = trimmed.match(/^(\d+)\s+(.+)$/);
1919
+ if (!match) continue;
1920
+ const pidText = match[1];
1921
+ if (!pidText) continue;
1922
+ const pid = Number.parseInt(pidText, 10);
1923
+ const command = match[2] ?? "";
1924
+ if (!Number.isInteger(pid) || pid <= 0) continue;
1925
+ if (pid === process.pid || pid === process.ppid) continue;
1926
+ if (!servePattern.test(command)) continue;
1927
+ pids.add(pid);
1928
+ }
1929
+ return [...pids];
1930
+ }
1931
+ function terminateProcess(pid) {
1932
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid || pid === process.ppid) {
1933
+ return false;
1934
+ }
1935
+ try {
1936
+ process.kill(pid, "SIGTERM");
1937
+ } catch {
1938
+ return false;
1939
+ }
1940
+ try {
1941
+ process.kill(pid, "SIGKILL");
1942
+ } catch {
1943
+ }
1944
+ return true;
1945
+ }
1946
+ function cleanupStaleServeProcesses(keepPid) {
1947
+ const candidates = listServeProcessPids();
1948
+ let cleaned = 0;
1949
+ for (const pid of candidates) {
1950
+ if (Number.isInteger(keepPid) && pid === keepPid) continue;
1951
+ if (terminateProcess(pid)) {
1952
+ cleaned += 1;
1953
+ }
1954
+ }
1955
+ return cleaned;
1956
+ }
1307
1957
  async function runServe(args) {
1308
1958
  const serveArgs = parseServeArgs(args.rawArgs);
1309
1959
  if (serveArgs.stop) {
1310
- const metadata = readDaemonMetadata();
1311
- if (!metadata) {
1960
+ const metadata2 = readDaemonMetadata();
1961
+ if (!metadata2) {
1312
1962
  if (daemonHandle) {
1313
1963
  await daemonHandle.stop();
1314
1964
  daemonHandle = null;
@@ -1317,9 +1967,9 @@ async function runServe(args) {
1317
1967
  return { success: false, message: "Daemon not running.", exitCode: EXIT_DISCONNECTED };
1318
1968
  }
1319
1969
  try {
1320
- const response = await fetchWithTimeout(`http://127.0.0.1:${metadata.port}/stop`, {
1970
+ const response = await fetchWithTimeout(`http://127.0.0.1:${metadata2.port}/stop`, {
1321
1971
  method: "POST",
1322
- headers: { Authorization: `Bearer ${metadata.token}` }
1972
+ headers: { Authorization: `Bearer ${metadata2.token}` }
1323
1973
  });
1324
1974
  if (!response.ok) {
1325
1975
  throw new Error(`Stop failed (${response.status})`);
@@ -1331,39 +1981,100 @@ async function runServe(args) {
1331
1981
  }
1332
1982
  }
1333
1983
  const config = loadGlobalConfig();
1984
+ const requestedPort = serveArgs.port ?? config.daemonPort;
1985
+ const metadata = readDaemonMetadata();
1986
+ const metadataToken = metadata?.port === requestedPort ? metadata.token : void 0;
1987
+ const tokenCandidates = resolveTokenCandidates(serveArgs.token, metadataToken, config.daemonToken);
1988
+ const existingDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
1989
+ const staleCleared = cleanupStaleServeProcesses(existingDaemon?.status.pid);
1990
+ if (existingDaemon) {
1991
+ const relayPort = existingDaemon.status.relay.port ?? config.relayPort;
1992
+ const staleNote2 = staleCleared > 0 ? ` Cleared ${staleCleared} stale daemon process${staleCleared === 1 ? "" : "es"}.` : "";
1993
+ return {
1994
+ success: true,
1995
+ message: `Daemon already running on 127.0.0.1:${requestedPort} (pid=${existingDaemon.status.pid}, relay ${relayPort}).${staleNote2}`,
1996
+ data: {
1997
+ port: requestedPort,
1998
+ pid: existingDaemon.status.pid,
1999
+ relayPort,
2000
+ alreadyRunning: true,
2001
+ staleDaemonsCleared: staleCleared,
2002
+ relay: existingDaemon.status.relay
2003
+ },
2004
+ exitCode: null
2005
+ };
2006
+ }
1334
2007
  let nativeStatus = getNativeStatusSnapshot();
1335
2008
  let nativeMessage = null;
1336
- if (!nativeStatus.installed) {
2009
+ if (!nativeStatus.installed || nativeStatus.mismatch) {
1337
2010
  const discovered = discoverExtensionId();
1338
- const extensionId = config.nativeExtensionId ?? discovered.extensionId ?? null;
1339
- const usedDiscovery = !config.nativeExtensionId && Boolean(discovered.extensionId);
2011
+ const extensionId = nativeStatus.expectedExtensionId ?? config.nativeExtensionId ?? discovered.extensionId ?? null;
2012
+ const usedDiscovery = nativeStatus.expectedExtensionSource !== "config" && Boolean(extensionId);
2013
+ const previousExtensionId = nativeStatus.extensionId;
1340
2014
  if (extensionId) {
1341
2015
  const installResult = installNativeHost(extensionId);
1342
2016
  if (installResult.success) {
1343
2017
  const suffix = usedDiscovery && discovered.matchedBy ? ` (auto-detected by ${discovered.matchedBy})` : "";
1344
- nativeMessage = `${installResult.message ?? "Native host installed."}${suffix}`;
2018
+ nativeMessage = nativeStatus.mismatch && previousExtensionId ? `Native host reinstalled for extension ${extensionId} (replacing stale ${previousExtensionId}).${suffix}` : `${installResult.message ?? "Native host installed."}${suffix}`;
1345
2019
  nativeStatus = getNativeStatusSnapshot();
1346
2020
  } else {
1347
- nativeMessage = `Native host install skipped: ${installResult.message ?? "unknown error"}`;
2021
+ nativeMessage = nativeStatus.mismatch ? `Native host reinstall skipped: ${installResult.message ?? "unknown error"}` : `Native host install skipped: ${installResult.message ?? "unknown error"}`;
1348
2022
  }
2023
+ } else if (nativeStatus.mismatch && previousExtensionId) {
2024
+ nativeMessage = `Native host targets stale extension ${previousExtensionId}, but no current extension id could be resolved for reinstall.`;
1349
2025
  } else {
1350
2026
  nativeMessage = "Native host not installed. Set nativeExtensionId in opendevbrowser.jsonc to auto-install.";
1351
2027
  }
1352
2028
  }
1353
- const handle = await startDaemon({
1354
- port: serveArgs.port,
1355
- token: serveArgs.token,
1356
- config
1357
- });
2029
+ let handle;
2030
+ try {
2031
+ handle = await startDaemon({
2032
+ port: serveArgs.port,
2033
+ token: serveArgs.token,
2034
+ config
2035
+ });
2036
+ } catch (error) {
2037
+ const message2 = error instanceof Error ? error.message : String(error);
2038
+ if (message2.includes("EADDRINUSE") || message2.includes("in use")) {
2039
+ const runningDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
2040
+ if (runningDaemon) {
2041
+ const relayPort = runningDaemon.status.relay.port ?? config.relayPort;
2042
+ return {
2043
+ success: true,
2044
+ message: `Daemon already running on 127.0.0.1:${requestedPort} (pid=${runningDaemon.status.pid}, relay ${relayPort}).`,
2045
+ data: {
2046
+ port: requestedPort,
2047
+ pid: runningDaemon.status.pid,
2048
+ relayPort,
2049
+ alreadyRunning: true,
2050
+ relay: runningDaemon.status.relay
2051
+ },
2052
+ exitCode: null
2053
+ };
2054
+ }
2055
+ return {
2056
+ success: false,
2057
+ message: `Daemon port ${requestedPort} is already in use by another process. If this is an existing daemon, run \`opendevbrowser status --daemon\` or \`opendevbrowser serve --stop\`.`,
2058
+ exitCode: EXIT_EXECUTION
2059
+ };
2060
+ }
2061
+ return {
2062
+ success: false,
2063
+ message: `Failed to start daemon: ${message2}`,
2064
+ exitCode: EXIT_EXECUTION
2065
+ };
2066
+ }
1358
2067
  daemonHandle = handle;
1359
2068
  const { state } = handle;
1360
2069
  const baseMessage = `Daemon running on 127.0.0.1:${state.port} (relay ${state.relayPort})`;
2070
+ const staleNote = staleCleared > 0 ? `
2071
+ Cleared ${staleCleared} stale daemon process${staleCleared === 1 ? "" : "es"}.` : "";
1361
2072
  const message = nativeMessage ? `${baseMessage}
1362
- ${nativeMessage}` : baseMessage;
2073
+ ${nativeMessage}${staleNote}` : `${baseMessage}${staleNote}`;
1363
2074
  return {
1364
2075
  success: true,
1365
2076
  message,
1366
- data: { port: state.port, pid: state.pid, relayPort: state.relayPort, native: nativeStatus },
2077
+ data: { port: state.port, pid: state.pid, relayPort: state.relayPort, native: nativeStatus, staleDaemonsCleared: staleCleared },
1367
2078
  exitCode: null
1368
2079
  };
1369
2080
  }
@@ -1372,7 +2083,7 @@ ${nativeMessage}` : baseMessage;
1372
2083
  import { execFileSync as execFileSync2 } from "child_process";
1373
2084
  import { existsSync as existsSync8, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
1374
2085
  import { homedir as homedir7 } from "os";
1375
- import { dirname as dirname5, join as join8, resolve as resolve3 } from "path";
2086
+ import { dirname as dirname5, join as join8, resolve as resolve4 } from "path";
1376
2087
  import { fileURLToPath as fileURLToPath3 } from "url";
1377
2088
  var MAC_LABEL = "com.opendevbrowser.daemon";
1378
2089
  var WIN_TASK_NAME = "OpenDevBrowser Daemon";
@@ -1390,7 +2101,7 @@ var defaultDeps = () => ({
1390
2101
  });
1391
2102
  var resolveCliPathFromModule = (moduleUrl, exists) => {
1392
2103
  const modulePath = fileURLToPath3(moduleUrl);
1393
- const candidate = resolve3(dirname5(modulePath), "..", "index.js");
2104
+ const candidate = resolve4(dirname5(modulePath), "..", "index.js");
1394
2105
  if (!exists(candidate)) {
1395
2106
  throw new Error(`CLI entrypoint not found at ${candidate}`);
1396
2107
  }
@@ -1401,7 +2112,7 @@ var resolveCliEntrypoint = (deps = {}) => {
1401
2112
  const exists = resolved.existsSync;
1402
2113
  let cliPath = null;
1403
2114
  if (resolved.argv1) {
1404
- const candidate = resolve3(resolved.argv1);
2115
+ const candidate = resolve4(resolved.argv1);
1405
2116
  if (exists(candidate)) {
1406
2117
  cliPath = candidate;
1407
2118
  }
@@ -1687,6 +2398,75 @@ async function runDaemonCommand(args) {
1687
2398
  };
1688
2399
  }
1689
2400
 
2401
+ // src/cli/commands/artifacts.ts
2402
+ import { join as join9, resolve as resolve5 } from "path";
2403
+ import { tmpdir } from "os";
2404
+ var usageError = () => {
2405
+ throw createUsageError("Usage: opendevbrowser artifacts cleanup --expired-only [--output-dir <path>]");
2406
+ };
2407
+ var requireValue = (rawArgs, index, flag) => {
2408
+ const value = rawArgs[index + 1];
2409
+ if (!value) {
2410
+ throw createUsageError(`Missing value for ${flag}`);
2411
+ }
2412
+ return value;
2413
+ };
2414
+ var parseArtifactsArgs = (rawArgs) => {
2415
+ const [candidate, ...rest] = rawArgs;
2416
+ if (candidate !== "cleanup") {
2417
+ usageError();
2418
+ }
2419
+ const subcommand = "cleanup";
2420
+ let expiredOnly = false;
2421
+ let outputDir;
2422
+ for (let index = 0; index < rest.length; index += 1) {
2423
+ const arg = rest[index];
2424
+ if (arg === "--expired-only") {
2425
+ expiredOnly = true;
2426
+ continue;
2427
+ }
2428
+ if (arg === "--output-dir") {
2429
+ outputDir = requireValue(rest, index, "--output-dir");
2430
+ index += 1;
2431
+ continue;
2432
+ }
2433
+ if (arg?.startsWith("--output-dir=")) {
2434
+ const value = arg.split("=", 2)[1];
2435
+ if (!value) {
2436
+ throw createUsageError("Missing value for --output-dir");
2437
+ }
2438
+ outputDir = value;
2439
+ continue;
2440
+ }
2441
+ throw createUsageError(`Unknown artifacts flag: ${arg}`);
2442
+ }
2443
+ if (!expiredOnly) {
2444
+ usageError();
2445
+ }
2446
+ return {
2447
+ subcommand,
2448
+ expiredOnly,
2449
+ outputDir
2450
+ };
2451
+ };
2452
+ async function runArtifactsCommand(args) {
2453
+ const parsed = parseArtifactsArgs(args.rawArgs);
2454
+ const rootDir = parsed.outputDir ? resolve5(parsed.outputDir) : join9(tmpdir(), "opendevbrowser");
2455
+ const cleaned = await cleanupExpiredArtifacts(rootDir);
2456
+ return {
2457
+ success: true,
2458
+ message: `Artifact cleanup completed. Removed ${cleaned.removed.length} expired run(s).`,
2459
+ data: {
2460
+ rootDir,
2461
+ expiredOnly: parsed.expiredOnly,
2462
+ removed: cleaned.removed,
2463
+ skipped: cleaned.skipped,
2464
+ removedCount: cleaned.removed.length,
2465
+ skippedCount: cleaned.skipped.length
2466
+ }
2467
+ };
2468
+ }
2469
+
1690
2470
  // src/cli/commands/run.ts
1691
2471
  import { readFileSync as readFileSync4 } from "fs";
1692
2472
 
@@ -1790,13 +2570,13 @@ function parseRunArgs(rawArgs) {
1790
2570
  return parsed;
1791
2571
  }
1792
2572
  function readScriptFromStdin() {
1793
- return new Promise((resolve4, reject) => {
2573
+ return new Promise((resolve6, reject) => {
1794
2574
  let data = "";
1795
2575
  process.stdin.setEncoding("utf8");
1796
2576
  process.stdin.on("data", (chunk) => {
1797
2577
  data += chunk;
1798
2578
  });
1799
- process.stdin.on("end", () => resolve4(data));
2579
+ process.stdin.on("end", () => resolve6(data));
1800
2580
  process.stdin.on("error", reject);
1801
2581
  });
1802
2582
  }
@@ -1851,6 +2631,14 @@ async function runScriptCommand(args) {
1851
2631
  }
1852
2632
 
1853
2633
  // src/cli/commands/session/launch.ts
2634
+ var MIN_LAUNCH_CALL_TIMEOUT_MS = 3e4;
2635
+ var LAUNCH_CALL_TIMEOUT_BUFFER_MS = 5e3;
2636
+ var parseBooleanFlag = (value, flag) => {
2637
+ const normalized = value.trim().toLowerCase();
2638
+ if (normalized === "true" || normalized === "1") return true;
2639
+ if (normalized === "false" || normalized === "0") return false;
2640
+ throw createUsageError(`Invalid ${flag}: ${value}`);
2641
+ };
1854
2642
  function parseLaunchArgs(rawArgs) {
1855
2643
  const parsed = { flags: [] };
1856
2644
  for (let i = 0; i < rawArgs.length; i += 1) {
@@ -1893,7 +2681,19 @@ function parseLaunchArgs(rawArgs) {
1893
2681
  continue;
1894
2682
  }
1895
2683
  if (arg === "--persist-profile") {
1896
- parsed.persistProfile = true;
2684
+ const value = rawArgs[i + 1];
2685
+ if (value && !value.startsWith("--")) {
2686
+ parsed.persistProfile = parseBooleanFlag(value, "--persist-profile");
2687
+ i += 1;
2688
+ } else {
2689
+ parsed.persistProfile = true;
2690
+ }
2691
+ continue;
2692
+ }
2693
+ if (arg?.startsWith("--persist-profile=")) {
2694
+ const value = arg.split("=", 2)[1];
2695
+ if (!value) throw createUsageError("Missing value for --persist-profile");
2696
+ parsed.persistProfile = parseBooleanFlag(value, "--persist-profile");
1897
2697
  continue;
1898
2698
  }
1899
2699
  if (arg === "--no-extension") {
@@ -1941,10 +2741,15 @@ function parseLaunchArgs(rawArgs) {
1941
2741
  }
1942
2742
  return parsed;
1943
2743
  }
2744
+ function deriveLaunchCallTimeoutMs(launchArgs) {
2745
+ const waitHintMs = typeof launchArgs.waitTimeoutMs === "number" ? launchArgs.waitTimeoutMs + LAUNCH_CALL_TIMEOUT_BUFFER_MS : 0;
2746
+ return Math.max(MIN_LAUNCH_CALL_TIMEOUT_MS, waitHintMs);
2747
+ }
1944
2748
  async function runSessionLaunch(args) {
1945
2749
  const launchArgs = parseLaunchArgs(args.rawArgs);
2750
+ const launchCallTimeoutMs = deriveLaunchCallTimeoutMs(launchArgs);
1946
2751
  try {
1947
- const result = await callDaemon("session.launch", launchArgs);
2752
+ const result = await callDaemon("session.launch", launchArgs, { timeoutMs: launchCallTimeoutMs });
1948
2753
  return {
1949
2754
  success: true,
1950
2755
  message: `Session launched: ${result.sessionId}`,
@@ -1966,7 +2771,8 @@ async function runSessionLaunch(args) {
1966
2771
  );
1967
2772
  if (retry) {
1968
2773
  try {
1969
- const result = await callDaemon("session.launch", { ...launchArgs, waitForExtension: true });
2774
+ const retryArgs = { ...launchArgs, waitForExtension: true };
2775
+ const result = await callDaemon("session.launch", retryArgs, { timeoutMs: deriveLaunchCallTimeoutMs(retryArgs) });
1970
2776
  return {
1971
2777
  success: true,
1972
2778
  message: `Session launched: ${result.sessionId}`,
@@ -1979,11 +2785,12 @@ async function runSessionLaunch(args) {
1979
2785
  const proceedManaged = await promptYesNo("Proceed with a managed session (headed)?", false);
1980
2786
  if (proceedManaged) {
1981
2787
  const useHeadless = await promptYesNo("Run headless instead?", false);
1982
- const result = await callDaemon("session.launch", {
2788
+ const managedArgs = {
1983
2789
  ...launchArgs,
1984
2790
  noExtension: true,
1985
2791
  headless: useHeadless ? true : false
1986
- });
2792
+ };
2793
+ const result = await callDaemon("session.launch", managedArgs, { timeoutMs: deriveLaunchCallTimeoutMs(managedArgs) });
1987
2794
  return {
1988
2795
  success: true,
1989
2796
  message: `Session launched: ${result.sessionId}`,
@@ -2007,16 +2814,16 @@ function promptYesNo(question, defaultYes) {
2007
2814
  return Promise.resolve(false);
2008
2815
  }
2009
2816
  const suffix = defaultYes ? " [Y/n] " : " [y/N] ";
2010
- return new Promise((resolve4) => {
2817
+ return new Promise((resolve6) => {
2011
2818
  process.stdout.write(`${question}${suffix}`);
2012
2819
  process.stdin.setEncoding("utf8");
2013
2820
  process.stdin.once("data", (data) => {
2014
2821
  const input = data.toString().trim().toLowerCase();
2015
2822
  if (!input) {
2016
- resolve4(defaultYes);
2823
+ resolve6(defaultYes);
2017
2824
  return;
2018
2825
  }
2019
- resolve4(input === "y" || input === "yes");
2826
+ resolve6(input === "y" || input === "yes");
2020
2827
  });
2021
2828
  });
2022
2829
  }
@@ -2063,8 +2870,25 @@ function parseConnectArgs(rawArgs) {
2063
2870
  parsed.port = parseNumberFlag(value, "--cdp-port", { min: 1, max: 65535 });
2064
2871
  continue;
2065
2872
  }
2066
- if (arg === "--extension-legacy") {
2067
- parsed.extensionLegacy = true;
2873
+ if (arg === "--start-url") {
2874
+ const value = rawArgs[i + 1];
2875
+ if (!value) throw createUsageError("Missing value for --start-url");
2876
+ parsed.startUrl = value;
2877
+ i += 1;
2878
+ continue;
2879
+ }
2880
+ if (arg?.startsWith("--start-url=")) {
2881
+ const value = arg.split("=", 2)[1];
2882
+ if (!value) throw createUsageError("Missing value for --start-url");
2883
+ parsed.startUrl = value;
2884
+ continue;
2885
+ }
2886
+ if (arg === "--extension-legacy") {
2887
+ parsed.extensionLegacy = true;
2888
+ continue;
2889
+ }
2890
+ if (arg === "--headless") {
2891
+ parsed.headless = true;
2068
2892
  continue;
2069
2893
  }
2070
2894
  }
@@ -2181,6 +3005,14 @@ async function runStatus(args) {
2181
3005
  exitCode: EXIT_DISCONNECTED
2182
3006
  };
2183
3007
  }
3008
+ if (nativeStatus2.mismatch && nativeStatus2.extensionId && nativeStatus2.expectedExtensionId) {
3009
+ return {
3010
+ success: false,
3011
+ message: `Native host targets ${nativeStatus2.extensionId}, but the current extension is ${nativeStatus2.expectedExtensionId}.`,
3012
+ data: nativeStatus2,
3013
+ exitCode: EXIT_DISCONNECTED
3014
+ };
3015
+ }
2184
3016
  return {
2185
3017
  success: true,
2186
3018
  message: nativeStatus2.extensionId ? `Native host installed for extension ${nativeStatus2.extensionId}.` : "Native host installed.",
@@ -2192,12 +3024,13 @@ async function runStatus(args) {
2192
3024
  throw createUsageError("Daemon not running. Start with `opendevbrowser serve`.");
2193
3025
  }
2194
3026
  const nativeStatus = getNativeStatusSnapshot();
3027
+ const nativeSummary = !nativeStatus.installed ? "not installed" : nativeStatus.mismatch && nativeStatus.extensionId && nativeStatus.expectedExtensionId ? `mismatch (${nativeStatus.extensionId} != ${nativeStatus.expectedExtensionId})` : `installed${nativeStatus.extensionId ? ` (${nativeStatus.extensionId})` : ""}`;
2195
3028
  const baseMessage = [
2196
3029
  `Daemon OK (pid=${daemonStatus.pid})`,
2197
- `Relay: port=${daemonStatus.relay.port ?? "n/a"} ext=${daemonStatus.relay.extensionConnected ? "on" : "off"} handshake=${daemonStatus.relay.extensionHandshakeComplete ? "on" : "off"} cdp=${daemonStatus.relay.cdpConnected ? "on" : "off"} annotate=${daemonStatus.relay.annotationConnected ? "on" : "off"} ops=${daemonStatus.relay.opsConnected ? "on" : "off"} pairing=${daemonStatus.relay.pairingRequired ? "on" : "off"} health=${daemonStatus.relay.health?.reason ?? "n/a"}`,
2198
- `Native: ${nativeStatus.installed ? "installed" : "not installed"}${nativeStatus.extensionId ? ` (${nativeStatus.extensionId})` : ""}`,
3030
+ `Relay: port=${daemonStatus.relay.port ?? "n/a"} ext=${daemonStatus.relay.extensionConnected ? "on" : "off"} handshake=${daemonStatus.relay.extensionHandshakeComplete ? "on" : "off"} cdp=${daemonStatus.relay.cdpConnected ? "on" : "off"} annotate=${daemonStatus.relay.annotationConnected ? "on" : "off"} ops=${daemonStatus.relay.opsConnected ? "on" : "off"} canvas=${daemonStatus.relay.canvasConnected ? "on" : "off"} pairing=${daemonStatus.relay.pairingRequired ? "on" : "off"} health=${daemonStatus.relay.health?.reason ?? "n/a"}`,
3031
+ `Native: ${nativeSummary}`,
2199
3032
  daemonStatus.relay.lastHandshakeError ? `Relay last handshake error: ${daemonStatus.relay.lastHandshakeError.code} (${daemonStatus.relay.lastHandshakeError.message})` : "Relay last handshake error: none",
2200
- "Legend: ext=extension websocket, handshake=extension handshake, cdp=active /cdp client, annotate=annotation channel, ops=ops clients, pairing=token required, health=relay status"
3033
+ "Legend: ext=extension websocket, handshake=extension handshake, cdp=active /cdp client, annotate=annotation channel, ops=ops clients, canvas=canvas clients, pairing=token required, health=relay status"
2201
3034
  ].join("\n");
2202
3035
  const message = daemon || args.outputFormat !== "text" ? baseMessage : [
2203
3036
  "Warning: `status` defaults to daemon status. Use --daemon explicitly or --session-id for session status.",
@@ -2266,9 +3099,16 @@ function parseGotoArgs(rawArgs) {
2266
3099
  }
2267
3100
  async function runGoto(args) {
2268
3101
  const { sessionId, url, waitUntil, timeoutMs } = parseGotoArgs(args.rawArgs);
3102
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2269
3103
  if (!sessionId) throw createUsageError("Missing --session-id");
2270
3104
  if (!url) throw createUsageError("Missing --url");
2271
- const result = await callDaemon("nav.goto", { sessionId, url, waitUntil, timeoutMs });
3105
+ const result = await callDaemon("nav.goto", {
3106
+ sessionId,
3107
+ url,
3108
+ waitUntil,
3109
+ timeoutMs,
3110
+ ...typeof targetId === "string" ? { targetId } : {}
3111
+ });
2272
3112
  return { success: true, message: `Navigated: ${url}`, data: result };
2273
3113
  }
2274
3114
 
@@ -2339,8 +3179,16 @@ function parseWaitArgs(rawArgs) {
2339
3179
  }
2340
3180
  async function runWait(args) {
2341
3181
  const { sessionId, ref, state, until, timeoutMs } = parseWaitArgs(args.rawArgs);
3182
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2342
3183
  if (!sessionId) throw createUsageError("Missing --session-id");
2343
- const result = await callDaemon("nav.wait", { sessionId, ref, state, until, timeoutMs });
3184
+ const result = await callDaemon("nav.wait", {
3185
+ sessionId,
3186
+ ref,
3187
+ state,
3188
+ until,
3189
+ timeoutMs,
3190
+ ...typeof targetId === "string" ? { targetId } : {}
3191
+ });
2344
3192
  return { success: true, message: "Wait complete.", data: result };
2345
3193
  }
2346
3194
 
@@ -2398,13 +3246,20 @@ function parseSnapshotArgs(rawArgs) {
2398
3246
  }
2399
3247
  async function runSnapshot(args) {
2400
3248
  const { sessionId, mode, maxChars, cursor } = parseSnapshotArgs(args.rawArgs);
3249
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2401
3250
  if (!sessionId) throw createUsageError("Missing --session-id");
2402
- const result = await callDaemon("nav.snapshot", { sessionId, mode, maxChars, cursor });
3251
+ const result = await callDaemon("nav.snapshot", {
3252
+ sessionId,
3253
+ mode,
3254
+ maxChars,
3255
+ cursor,
3256
+ ...typeof targetId === "string" ? { targetId } : {}
3257
+ });
2403
3258
  return { success: true, message: "Snapshot captured.", data: result };
2404
3259
  }
2405
3260
 
2406
3261
  // src/cli/commands/annotate.ts
2407
- var requireValue = (value, flag) => {
3262
+ var requireValue2 = (value, flag) => {
2408
3263
  if (!value) throw createUsageError(`Missing value for ${flag}`);
2409
3264
  return value;
2410
3265
  };
@@ -2425,68 +3280,76 @@ var parseAnnotateArgs = (rawArgs) => {
2425
3280
  for (let i = 0; i < rawArgs.length; i += 1) {
2426
3281
  const arg = rawArgs[i];
2427
3282
  if (arg === "--session-id") {
2428
- const value = requireValue(rawArgs[i + 1], "--session-id");
3283
+ const value = requireValue2(rawArgs[i + 1], "--session-id");
2429
3284
  parsed.sessionId = value;
2430
3285
  i += 1;
2431
3286
  continue;
2432
3287
  }
2433
3288
  if (arg?.startsWith("--session-id=")) {
2434
- const value = requireValue(arg.split("=", 2)[1], "--session-id");
3289
+ const value = requireValue2(arg.split("=", 2)[1], "--session-id");
2435
3290
  parsed.sessionId = value;
2436
3291
  continue;
2437
3292
  }
3293
+ if (arg === "--stored") {
3294
+ parsed.stored = true;
3295
+ continue;
3296
+ }
3297
+ if (arg === "--include-screenshots") {
3298
+ parsed.includeScreenshots = true;
3299
+ continue;
3300
+ }
2438
3301
  if (arg === "--url") {
2439
- const value = requireValue(rawArgs[i + 1], "--url");
3302
+ const value = requireValue2(rawArgs[i + 1], "--url");
2440
3303
  parsed.url = value;
2441
3304
  i += 1;
2442
3305
  continue;
2443
3306
  }
2444
3307
  if (arg?.startsWith("--url=")) {
2445
- const value = requireValue(arg.split("=", 2)[1], "--url");
3308
+ const value = requireValue2(arg.split("=", 2)[1], "--url");
2446
3309
  parsed.url = value;
2447
3310
  continue;
2448
3311
  }
2449
3312
  if (arg === "--screenshot-mode") {
2450
- const value = requireValue(rawArgs[i + 1], "--screenshot-mode");
3313
+ const value = requireValue2(rawArgs[i + 1], "--screenshot-mode");
2451
3314
  parsed.screenshotMode = requireScreenshotMode(value);
2452
3315
  i += 1;
2453
3316
  continue;
2454
3317
  }
2455
3318
  if (arg?.startsWith("--screenshot-mode=")) {
2456
- const value = requireValue(arg.split("=", 2)[1], "--screenshot-mode");
3319
+ const value = requireValue2(arg.split("=", 2)[1], "--screenshot-mode");
2457
3320
  parsed.screenshotMode = requireScreenshotMode(value);
2458
3321
  continue;
2459
3322
  }
2460
3323
  if (arg === "--transport") {
2461
- const value = requireValue(rawArgs[i + 1], "--transport");
3324
+ const value = requireValue2(rawArgs[i + 1], "--transport");
2462
3325
  parsed.transport = requireTransport(value);
2463
3326
  i += 1;
2464
3327
  continue;
2465
3328
  }
2466
3329
  if (arg?.startsWith("--transport=")) {
2467
- const value = requireValue(arg.split("=", 2)[1], "--transport");
3330
+ const value = requireValue2(arg.split("=", 2)[1], "--transport");
2468
3331
  parsed.transport = requireTransport(value);
2469
3332
  continue;
2470
3333
  }
2471
3334
  if (arg === "--target-id") {
2472
- const value = requireValue(rawArgs[i + 1], "--target-id");
3335
+ const value = requireValue2(rawArgs[i + 1], "--target-id");
2473
3336
  parsed.targetId = value;
2474
3337
  i += 1;
2475
3338
  continue;
2476
3339
  }
2477
3340
  if (arg?.startsWith("--target-id=")) {
2478
- const value = requireValue(arg.split("=", 2)[1], "--target-id");
3341
+ const value = requireValue2(arg.split("=", 2)[1], "--target-id");
2479
3342
  parsed.targetId = value;
2480
3343
  continue;
2481
3344
  }
2482
3345
  if (arg === "--tab-id") {
2483
- const value = requireValue(rawArgs[i + 1], "--tab-id");
3346
+ const value = requireValue2(rawArgs[i + 1], "--tab-id");
2484
3347
  parsed.tabId = parseNumberFlag(value, "--tab-id", { min: 1 });
2485
3348
  i += 1;
2486
3349
  continue;
2487
3350
  }
2488
3351
  if (arg?.startsWith("--tab-id=")) {
2489
- const value = requireValue(arg.split("=", 2)[1], "--tab-id");
3352
+ const value = requireValue2(arg.split("=", 2)[1], "--tab-id");
2490
3353
  parsed.tabId = parseNumberFlag(value, "--tab-id", { min: 1 });
2491
3354
  continue;
2492
3355
  }
@@ -2495,24 +3358,24 @@ var parseAnnotateArgs = (rawArgs) => {
2495
3358
  continue;
2496
3359
  }
2497
3360
  if (arg === "--context") {
2498
- const value = requireValue(rawArgs[i + 1], "--context");
3361
+ const value = requireValue2(rawArgs[i + 1], "--context");
2499
3362
  parsed.context = value;
2500
3363
  i += 1;
2501
3364
  continue;
2502
3365
  }
2503
3366
  if (arg?.startsWith("--context=")) {
2504
- const value = requireValue(arg.split("=", 2)[1], "--context");
3367
+ const value = requireValue2(arg.split("=", 2)[1], "--context");
2505
3368
  parsed.context = value;
2506
3369
  continue;
2507
3370
  }
2508
3371
  if (arg === "--timeout-ms") {
2509
- const value = requireValue(rawArgs[i + 1], "--timeout-ms");
3372
+ const value = requireValue2(rawArgs[i + 1], "--timeout-ms");
2510
3373
  parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
2511
3374
  i += 1;
2512
3375
  continue;
2513
3376
  }
2514
3377
  if (arg?.startsWith("--timeout-ms=")) {
2515
- const value = requireValue(arg.split("=", 2)[1], "--timeout-ms");
3378
+ const value = requireValue2(arg.split("=", 2)[1], "--timeout-ms");
2516
3379
  parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
2517
3380
  continue;
2518
3381
  }
@@ -2520,13 +3383,27 @@ var parseAnnotateArgs = (rawArgs) => {
2520
3383
  return parsed;
2521
3384
  };
2522
3385
  async function runAnnotate(args) {
2523
- const { sessionId, url, screenshotMode, debug, context, timeoutMs, transport, targetId, tabId } = parseAnnotateArgs(args.rawArgs);
3386
+ const {
3387
+ sessionId,
3388
+ stored,
3389
+ includeScreenshots,
3390
+ url,
3391
+ screenshotMode,
3392
+ debug,
3393
+ context,
3394
+ timeoutMs,
3395
+ transport,
3396
+ targetId,
3397
+ tabId
3398
+ } = parseAnnotateArgs(args.rawArgs);
2524
3399
  if (!sessionId) throw createUsageError("Missing --session-id");
2525
3400
  const client = new DaemonClient({ autoRenew: true });
2526
3401
  const callTimeoutMs = typeof timeoutMs === "number" ? timeoutMs + 1e4 : void 0;
2527
3402
  try {
2528
3403
  const response = await client.call("annotate", {
2529
3404
  sessionId,
3405
+ stored,
3406
+ includeScreenshots,
2530
3407
  transport,
2531
3408
  targetId,
2532
3409
  tabId,
@@ -2536,6 +3413,13 @@ async function runAnnotate(args) {
2536
3413
  context,
2537
3414
  timeoutMs
2538
3415
  }, { timeoutMs: callTimeoutMs });
3416
+ if (response.status === "cancelled") {
3417
+ return {
3418
+ success: true,
3419
+ message: response.error?.message ?? "Annotation cancelled.",
3420
+ data: { cancelled: true }
3421
+ };
3422
+ }
2539
3423
  if (response.status !== "ok" || !response.payload) {
2540
3424
  const message2 = response.error?.message ?? "Annotation failed.";
2541
3425
  throw new Error(message2);
@@ -2548,6 +3432,385 @@ async function runAnnotate(args) {
2548
3432
  }
2549
3433
  }
2550
3434
 
3435
+ // src/cli/commands/canvas.ts
3436
+ import { readFileSync as readFileSync5 } from "fs";
3437
+ var DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS = 3e4;
3438
+ var MIN_FEEDBACK_STREAM_POLL_MS = 250;
3439
+ var MAX_FEEDBACK_STREAM_POLL_MS = 1e3;
3440
+ var isRecord = (value) => {
3441
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3442
+ };
3443
+ var asString = (value) => {
3444
+ return typeof value === "string" && value.length > 0 ? value : null;
3445
+ };
3446
+ var asNumber = (value) => {
3447
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
3448
+ };
3449
+ var asRecordArray = (value) => {
3450
+ return Array.isArray(value) ? value.filter(isRecord) : [];
3451
+ };
3452
+ var sleep = async (ms) => {
3453
+ await new Promise((resolve6) => setTimeout(resolve6, ms));
3454
+ };
3455
+ var toFeedbackPollResult = (value) => {
3456
+ if (!isRecord(value)) {
3457
+ return { items: [], nextCursor: null };
3458
+ }
3459
+ const retention = isRecord(value.retention) ? {
3460
+ activeTargetIds: Array.isArray(value.retention.activeTargetIds) ? value.retention.activeTargetIds.filter((entry) => typeof entry === "string") : void 0
3461
+ } : void 0;
3462
+ return {
3463
+ items: asRecordArray(value.items),
3464
+ nextCursor: asString(value.nextCursor),
3465
+ retention
3466
+ };
3467
+ };
3468
+ async function streamFeedbackViaPolling(client, args, canvasArgs, params, initial) {
3469
+ const outputOptions = { format: args.outputFormat, quiet: args.quiet };
3470
+ writeOutput({
3471
+ success: true,
3472
+ message: `Canvas executed: ${canvasArgs.command}`,
3473
+ data: {
3474
+ command: canvasArgs.command,
3475
+ result: initial
3476
+ }
3477
+ }, outputOptions);
3478
+ const heartbeatMs = Math.max(asNumber(initial.heartbeatMs) ?? 15e3, 1e3);
3479
+ const pollIntervalMs = Math.min(
3480
+ MAX_FEEDBACK_STREAM_POLL_MS,
3481
+ Math.max(MIN_FEEDBACK_STREAM_POLL_MS, Math.floor(heartbeatMs / 3))
3482
+ );
3483
+ const streamTimeoutMs = canvasArgs.timeoutMs ?? DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS;
3484
+ const deadline = Date.now() + streamTimeoutMs;
3485
+ let cursor = asString(initial.cursor);
3486
+ let lastHeartbeatAt = Date.now();
3487
+ while (Date.now() < deadline) {
3488
+ await sleep(pollIntervalMs);
3489
+ const remainingMs = deadline - Date.now();
3490
+ if (remainingMs <= 0) {
3491
+ break;
3492
+ }
3493
+ const polled = toFeedbackPollResult(await client.call(
3494
+ "canvas.execute",
3495
+ {
3496
+ command: "canvas.feedback.poll",
3497
+ params: {
3498
+ ...params,
3499
+ afterCursor: cursor
3500
+ }
3501
+ },
3502
+ { timeoutMs: remainingMs }
3503
+ ));
3504
+ if (polled.items.length > 0) {
3505
+ for (const item of polled.items) {
3506
+ const itemCursor = asString(item.cursor);
3507
+ if (itemCursor) {
3508
+ cursor = itemCursor;
3509
+ }
3510
+ writeOutput({
3511
+ success: true,
3512
+ message: `Canvas feedback: ${canvasArgs.command}`,
3513
+ data: {
3514
+ command: canvasArgs.command,
3515
+ streamEvent: {
3516
+ eventType: "feedback.item",
3517
+ item,
3518
+ cursor: cursor ?? null
3519
+ }
3520
+ }
3521
+ }, outputOptions);
3522
+ }
3523
+ lastHeartbeatAt = Date.now();
3524
+ continue;
3525
+ }
3526
+ if (polled.nextCursor) {
3527
+ cursor = polled.nextCursor;
3528
+ }
3529
+ if (Date.now() - lastHeartbeatAt >= heartbeatMs) {
3530
+ writeOutput({
3531
+ success: true,
3532
+ message: `Canvas feedback: ${canvasArgs.command}`,
3533
+ data: {
3534
+ command: canvasArgs.command,
3535
+ streamEvent: {
3536
+ eventType: "feedback.heartbeat",
3537
+ cursor: cursor ?? null,
3538
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
3539
+ activeTargetIds: polled.retention?.activeTargetIds ?? []
3540
+ }
3541
+ }
3542
+ }, outputOptions);
3543
+ lastHeartbeatAt = Date.now();
3544
+ }
3545
+ }
3546
+ writeOutput({
3547
+ success: true,
3548
+ message: `Canvas feedback: ${canvasArgs.command}`,
3549
+ data: {
3550
+ command: canvasArgs.command,
3551
+ streamEvent: {
3552
+ eventType: "feedback.complete",
3553
+ cursor: cursor ?? null,
3554
+ completeReason: "timeout"
3555
+ }
3556
+ }
3557
+ }, outputOptions);
3558
+ }
3559
+ var requireValue3 = (value, flag) => {
3560
+ if (!value) throw createUsageError(`Missing value for ${flag}`);
3561
+ return value;
3562
+ };
3563
+ var parseJsonObject = (raw, source) => {
3564
+ let parsed;
3565
+ try {
3566
+ parsed = JSON.parse(raw);
3567
+ } catch (error) {
3568
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3569
+ throw createUsageError(`Invalid JSON from ${source}: ${message}`);
3570
+ }
3571
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3572
+ throw createUsageError(`Invalid JSON from ${source}: expected object`);
3573
+ }
3574
+ return parsed;
3575
+ };
3576
+ var parseCanvasArgs = (rawArgs) => {
3577
+ const parsed = {};
3578
+ for (let i = 0; i < rawArgs.length; i += 1) {
3579
+ const arg = rawArgs[i];
3580
+ if (arg === "--command") {
3581
+ parsed.command = requireValue3(rawArgs[i + 1], "--command");
3582
+ i += 1;
3583
+ continue;
3584
+ }
3585
+ if (arg?.startsWith("--command=")) {
3586
+ parsed.command = requireValue3(arg.split("=", 2)[1], "--command");
3587
+ continue;
3588
+ }
3589
+ if (arg === "--params") {
3590
+ parsed.params = requireValue3(rawArgs[i + 1], "--params");
3591
+ i += 1;
3592
+ continue;
3593
+ }
3594
+ if (arg?.startsWith("--params=")) {
3595
+ parsed.params = requireValue3(arg.split("=", 2)[1], "--params");
3596
+ continue;
3597
+ }
3598
+ if (arg === "--params-file") {
3599
+ parsed.paramsFile = requireValue3(rawArgs[i + 1], "--params-file");
3600
+ i += 1;
3601
+ continue;
3602
+ }
3603
+ if (arg?.startsWith("--params-file=")) {
3604
+ parsed.paramsFile = requireValue3(arg.split("=", 2)[1], "--params-file");
3605
+ continue;
3606
+ }
3607
+ if (arg === "--timeout-ms") {
3608
+ parsed.timeoutMs = parseNumberFlag(requireValue3(rawArgs[i + 1], "--timeout-ms"), "--timeout-ms", { min: 1 });
3609
+ i += 1;
3610
+ continue;
3611
+ }
3612
+ if (arg?.startsWith("--timeout-ms=")) {
3613
+ parsed.timeoutMs = parseNumberFlag(requireValue3(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
3614
+ }
3615
+ }
3616
+ return parsed;
3617
+ };
3618
+ var resolveCanvasParams = (canvasArgs) => {
3619
+ const hasParams = typeof canvasArgs.params === "string";
3620
+ const hasParamsFile = typeof canvasArgs.paramsFile === "string";
3621
+ if (Number(hasParams) + Number(hasParamsFile) > 1) {
3622
+ throw createUsageError("Provide only one params source: --params or --params-file.");
3623
+ }
3624
+ if (hasParams) {
3625
+ return parseJsonObject(canvasArgs.params ?? "", "--params");
3626
+ }
3627
+ if (hasParamsFile) {
3628
+ let raw = "";
3629
+ try {
3630
+ raw = readFileSync5(canvasArgs.paramsFile ?? "", "utf8");
3631
+ } catch (error) {
3632
+ const message = error instanceof Error ? error.message : "Unable to read file";
3633
+ throw createUsageError(`Invalid --params-file: ${message}`);
3634
+ }
3635
+ if (!raw.trim()) {
3636
+ throw createUsageError("Invalid JSON from --params-file: empty input");
3637
+ }
3638
+ return parseJsonObject(raw, "--params-file");
3639
+ }
3640
+ return {};
3641
+ };
3642
+ async function runCanvas(args) {
3643
+ const canvasArgs = parseCanvasArgs(args.rawArgs);
3644
+ if (!canvasArgs.command) {
3645
+ throw createUsageError("Usage: opendevbrowser canvas --command <canvas.command> [--params <json> | --params-file <path>]");
3646
+ }
3647
+ if (!canvasArgs.command.startsWith("canvas.")) {
3648
+ throw createUsageError("Canvas command names must start with 'canvas.'.");
3649
+ }
3650
+ const client = new DaemonClient({ autoRenew: true });
3651
+ try {
3652
+ const params = resolveCanvasParams(canvasArgs);
3653
+ const result = await client.call(
3654
+ "canvas.execute",
3655
+ {
3656
+ command: canvasArgs.command,
3657
+ params
3658
+ },
3659
+ { timeoutMs: canvasArgs.timeoutMs }
3660
+ );
3661
+ if (canvasArgs.command === "canvas.feedback.subscribe" && args.outputFormat === "stream-json" && isRecord(result)) {
3662
+ await streamFeedbackViaPolling(client, args, canvasArgs, params, result);
3663
+ return {
3664
+ success: true,
3665
+ message: `Canvas executed: ${canvasArgs.command}`,
3666
+ data: {
3667
+ suppressOutput: true
3668
+ }
3669
+ };
3670
+ }
3671
+ if (args.outputFormat === "text") {
3672
+ const output = typeof result === "string" ? result : JSON.stringify(result, null, 2);
3673
+ return { success: true, message: output };
3674
+ }
3675
+ return {
3676
+ success: true,
3677
+ message: `Canvas executed: ${canvasArgs.command}`,
3678
+ data: {
3679
+ command: canvasArgs.command,
3680
+ result
3681
+ }
3682
+ };
3683
+ } finally {
3684
+ await client.releaseBinding().catch(() => {
3685
+ });
3686
+ }
3687
+ }
3688
+
3689
+ // src/cli/commands/rpc.ts
3690
+ import { readFileSync as readFileSync6 } from "fs";
3691
+ var requireValue4 = (value, flag) => {
3692
+ if (!value) throw createUsageError(`Missing value for ${flag}`);
3693
+ return value;
3694
+ };
3695
+ var parseJsonObject2 = (raw, source) => {
3696
+ let parsed;
3697
+ try {
3698
+ parsed = JSON.parse(raw);
3699
+ } catch (error) {
3700
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3701
+ throw createUsageError(`Invalid JSON from ${source}: ${message}`);
3702
+ }
3703
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3704
+ throw createUsageError(`Invalid JSON from ${source}: expected object`);
3705
+ }
3706
+ return parsed;
3707
+ };
3708
+ var parseRpcArgs = (rawArgs) => {
3709
+ const parsed = {};
3710
+ for (let i = 0; i < rawArgs.length; i += 1) {
3711
+ const arg = rawArgs[i];
3712
+ if (arg === "--unsafe-internal") {
3713
+ parsed.unsafeInternal = true;
3714
+ continue;
3715
+ }
3716
+ if (arg === "--name") {
3717
+ parsed.name = requireValue4(rawArgs[i + 1], "--name");
3718
+ i += 1;
3719
+ continue;
3720
+ }
3721
+ if (arg?.startsWith("--name=")) {
3722
+ parsed.name = requireValue4(arg.split("=", 2)[1], "--name");
3723
+ continue;
3724
+ }
3725
+ if (arg === "--params") {
3726
+ parsed.params = requireValue4(rawArgs[i + 1], "--params");
3727
+ i += 1;
3728
+ continue;
3729
+ }
3730
+ if (arg?.startsWith("--params=")) {
3731
+ parsed.params = requireValue4(arg.split("=", 2)[1], "--params");
3732
+ continue;
3733
+ }
3734
+ if (arg === "--params-file") {
3735
+ parsed.paramsFile = requireValue4(rawArgs[i + 1], "--params-file");
3736
+ i += 1;
3737
+ continue;
3738
+ }
3739
+ if (arg?.startsWith("--params-file=")) {
3740
+ parsed.paramsFile = requireValue4(arg.split("=", 2)[1], "--params-file");
3741
+ continue;
3742
+ }
3743
+ if (arg === "--timeout-ms") {
3744
+ const value = requireValue4(rawArgs[i + 1], "--timeout-ms");
3745
+ parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
3746
+ i += 1;
3747
+ continue;
3748
+ }
3749
+ if (arg?.startsWith("--timeout-ms=")) {
3750
+ const value = requireValue4(arg.split("=", 2)[1], "--timeout-ms");
3751
+ parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
3752
+ continue;
3753
+ }
3754
+ }
3755
+ return parsed;
3756
+ };
3757
+ var resolveRpcParams = (rpcArgs) => {
3758
+ const hasParamsArg = typeof rpcArgs.params === "string";
3759
+ const hasParamsFile = typeof rpcArgs.paramsFile === "string";
3760
+ const inputCount = Number(hasParamsArg) + Number(hasParamsFile);
3761
+ if (inputCount > 1) {
3762
+ throw createUsageError("Provide only one params source: --params or --params-file.");
3763
+ }
3764
+ if (hasParamsArg) {
3765
+ return parseJsonObject2(rpcArgs.params ?? "", "--params");
3766
+ }
3767
+ if (hasParamsFile) {
3768
+ let raw = "";
3769
+ try {
3770
+ raw = readFileSync6(rpcArgs.paramsFile ?? "", "utf8");
3771
+ } catch (error) {
3772
+ const message = error instanceof Error ? error.message : "Unable to read file";
3773
+ throw createUsageError(`Invalid --params-file: ${message}`);
3774
+ }
3775
+ if (!raw.trim()) {
3776
+ throw createUsageError("Invalid JSON from --params-file: empty input");
3777
+ }
3778
+ return parseJsonObject2(raw, "--params-file");
3779
+ }
3780
+ return {};
3781
+ };
3782
+ async function runRpc(args) {
3783
+ const rpcArgs = parseRpcArgs(args.rawArgs);
3784
+ if (!rpcArgs.unsafeInternal) {
3785
+ throw createUsageError(
3786
+ "Missing --unsafe-internal. rpc is a power-user command that executes internal daemon commands and can mutate session state."
3787
+ );
3788
+ }
3789
+ if (!rpcArgs.name) {
3790
+ throw createUsageError("Missing --name");
3791
+ }
3792
+ const params = resolveRpcParams(rpcArgs);
3793
+ const client = new DaemonClient({ autoRenew: true });
3794
+ try {
3795
+ const result = await client.call(rpcArgs.name, params, { timeoutMs: rpcArgs.timeoutMs });
3796
+ if (args.outputFormat === "text") {
3797
+ const output = typeof result === "string" ? result : JSON.stringify(result, null, 2);
3798
+ return { success: true, message: output };
3799
+ }
3800
+ return {
3801
+ success: true,
3802
+ message: `RPC executed: ${rpcArgs.name}`,
3803
+ data: {
3804
+ name: rpcArgs.name,
3805
+ result
3806
+ }
3807
+ };
3808
+ } finally {
3809
+ await client.releaseBinding().catch(() => {
3810
+ });
3811
+ }
3812
+ }
3813
+
2551
3814
  // src/cli/commands/interact/click.ts
2552
3815
  function parseClickArgs(rawArgs) {
2553
3816
  const parsed = {};
@@ -2580,9 +3843,14 @@ function parseClickArgs(rawArgs) {
2580
3843
  }
2581
3844
  async function runClick(args) {
2582
3845
  const { sessionId, ref } = parseClickArgs(args.rawArgs);
3846
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2583
3847
  if (!sessionId) throw createUsageError("Missing --session-id");
2584
3848
  if (!ref) throw createUsageError("Missing --ref");
2585
- const result = await callDaemon("interact.click", { sessionId, ref });
3849
+ const result = await callDaemon("interact.click", {
3850
+ sessionId,
3851
+ ref,
3852
+ ...typeof targetId === "string" ? { targetId } : {}
3853
+ });
2586
3854
  return { success: true, message: "Click complete.", data: result };
2587
3855
  }
2588
3856
 
@@ -2618,9 +3886,14 @@ function parseHoverArgs(rawArgs) {
2618
3886
  }
2619
3887
  async function runHover(args) {
2620
3888
  const { sessionId, ref } = parseHoverArgs(args.rawArgs);
3889
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2621
3890
  if (!sessionId) throw createUsageError("Missing --session-id");
2622
3891
  if (!ref) throw createUsageError("Missing --ref");
2623
- const result = await callDaemon("interact.hover", { sessionId, ref });
3892
+ const result = await callDaemon("interact.hover", {
3893
+ sessionId,
3894
+ ref,
3895
+ ...typeof targetId === "string" ? { targetId } : {}
3896
+ });
2624
3897
  return { success: true, message: "Hover complete.", data: result };
2625
3898
  }
2626
3899
 
@@ -2667,9 +3940,15 @@ function parsePressArgs(rawArgs) {
2667
3940
  }
2668
3941
  async function runPress(args) {
2669
3942
  const { sessionId, key, ref } = parsePressArgs(args.rawArgs);
3943
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2670
3944
  if (!sessionId) throw createUsageError("Missing --session-id");
2671
3945
  if (!key) throw createUsageError("Missing --key");
2672
- const result = await callDaemon("interact.press", { sessionId, key, ref });
3946
+ const result = await callDaemon("interact.press", {
3947
+ sessionId,
3948
+ key,
3949
+ ref,
3950
+ ...typeof targetId === "string" ? { targetId } : {}
3951
+ });
2673
3952
  return { success: true, message: "Key press complete.", data: result };
2674
3953
  }
2675
3954
 
@@ -2705,9 +3984,14 @@ function parseCheckArgs(rawArgs) {
2705
3984
  }
2706
3985
  async function runCheck(args) {
2707
3986
  const { sessionId, ref } = parseCheckArgs(args.rawArgs);
3987
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2708
3988
  if (!sessionId) throw createUsageError("Missing --session-id");
2709
3989
  if (!ref) throw createUsageError("Missing --ref");
2710
- const result = await callDaemon("interact.check", { sessionId, ref });
3990
+ const result = await callDaemon("interact.check", {
3991
+ sessionId,
3992
+ ref,
3993
+ ...typeof targetId === "string" ? { targetId } : {}
3994
+ });
2711
3995
  return { success: true, message: "Check complete.", data: result };
2712
3996
  }
2713
3997
 
@@ -2743,9 +4027,14 @@ function parseUncheckArgs(rawArgs) {
2743
4027
  }
2744
4028
  async function runUncheck(args) {
2745
4029
  const { sessionId, ref } = parseUncheckArgs(args.rawArgs);
4030
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2746
4031
  if (!sessionId) throw createUsageError("Missing --session-id");
2747
4032
  if (!ref) throw createUsageError("Missing --ref");
2748
- const result = await callDaemon("interact.uncheck", { sessionId, ref });
4033
+ const result = await callDaemon("interact.uncheck", {
4034
+ sessionId,
4035
+ ref,
4036
+ ...typeof targetId === "string" ? { targetId } : {}
4037
+ });
2749
4038
  return { success: true, message: "Uncheck complete.", data: result };
2750
4039
  }
2751
4040
 
@@ -2800,10 +4089,18 @@ function parseTypeArgs(rawArgs) {
2800
4089
  }
2801
4090
  async function runType(args) {
2802
4091
  const { sessionId, ref, text, clear, submit } = parseTypeArgs(args.rawArgs);
4092
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2803
4093
  if (!sessionId) throw createUsageError("Missing --session-id");
2804
4094
  if (!ref) throw createUsageError("Missing --ref");
2805
4095
  if (!text) throw createUsageError("Missing --text");
2806
- const result = await callDaemon("interact.type", { sessionId, ref, text, clear, submit });
4096
+ const result = await callDaemon("interact.type", {
4097
+ sessionId,
4098
+ ref,
4099
+ text,
4100
+ clear,
4101
+ submit,
4102
+ ...typeof targetId === "string" ? { targetId } : {}
4103
+ });
2807
4104
  return { success: true, message: "Type complete.", data: result };
2808
4105
  }
2809
4106
 
@@ -2852,10 +4149,16 @@ function parseSelectArgs(rawArgs) {
2852
4149
  }
2853
4150
  async function runSelect(args) {
2854
4151
  const { sessionId, ref, values } = parseSelectArgs(args.rawArgs);
4152
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2855
4153
  if (!sessionId) throw createUsageError("Missing --session-id");
2856
4154
  if (!ref) throw createUsageError("Missing --ref");
2857
4155
  if (!values || values.length === 0) throw createUsageError("Missing --values");
2858
- const result = await callDaemon("interact.select", { sessionId, ref, values });
4156
+ const result = await callDaemon("interact.select", {
4157
+ sessionId,
4158
+ ref,
4159
+ values,
4160
+ ...typeof targetId === "string" ? { targetId } : {}
4161
+ });
2859
4162
  return { success: true, message: "Select complete.", data: result };
2860
4163
  }
2861
4164
 
@@ -2902,9 +4205,15 @@ function parseScrollArgs(rawArgs) {
2902
4205
  }
2903
4206
  async function runScroll(args) {
2904
4207
  const { sessionId, ref, dy } = parseScrollArgs(args.rawArgs);
4208
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2905
4209
  if (!sessionId) throw createUsageError("Missing --session-id");
2906
4210
  if (typeof dy !== "number" || Number.isNaN(dy)) throw createUsageError("Missing --dy");
2907
- const result = await callDaemon("interact.scroll", { sessionId, ref, dy });
4211
+ const result = await callDaemon("interact.scroll", {
4212
+ sessionId,
4213
+ ref,
4214
+ dy,
4215
+ ...typeof targetId === "string" ? { targetId } : {}
4216
+ });
2908
4217
  return { success: true, message: "Scroll complete.", data: result };
2909
4218
  }
2910
4219
 
@@ -2940,9 +4249,14 @@ function parseScrollIntoViewArgs(rawArgs) {
2940
4249
  }
2941
4250
  async function runScrollIntoView(args) {
2942
4251
  const { sessionId, ref } = parseScrollIntoViewArgs(args.rawArgs);
4252
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2943
4253
  if (!sessionId) throw createUsageError("Missing --session-id");
2944
4254
  if (!ref) throw createUsageError("Missing --ref");
2945
- const result = await callDaemon("interact.scrollIntoView", { sessionId, ref });
4255
+ const result = await callDaemon("interact.scrollIntoView", {
4256
+ sessionId,
4257
+ ref,
4258
+ ...typeof targetId === "string" ? { targetId } : {}
4259
+ });
2946
4260
  return { success: true, message: "Scroll into view complete.", data: result };
2947
4261
  }
2948
4262
 
@@ -3244,9 +4558,15 @@ function parseDomHtmlArgs(rawArgs) {
3244
4558
  }
3245
4559
  async function runDomHtml(args) {
3246
4560
  const { sessionId, ref, maxChars } = parseDomHtmlArgs(args.rawArgs);
4561
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3247
4562
  if (!sessionId) throw createUsageError("Missing --session-id");
3248
4563
  if (!ref) throw createUsageError("Missing --ref");
3249
- const result = await callDaemon("dom.getHtml", { sessionId, ref, maxChars });
4564
+ const result = await callDaemon("dom.getHtml", {
4565
+ sessionId,
4566
+ ref,
4567
+ maxChars,
4568
+ ...typeof targetId === "string" ? { targetId } : {}
4569
+ });
3250
4570
  return { success: true, message: "DOM HTML captured.", data: result };
3251
4571
  }
3252
4572
 
@@ -3293,9 +4613,15 @@ function parseDomTextArgs(rawArgs) {
3293
4613
  }
3294
4614
  async function runDomText(args) {
3295
4615
  const { sessionId, ref, maxChars } = parseDomTextArgs(args.rawArgs);
4616
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3296
4617
  if (!sessionId) throw createUsageError("Missing --session-id");
3297
4618
  if (!ref) throw createUsageError("Missing --ref");
3298
- const result = await callDaemon("dom.getText", { sessionId, ref, maxChars });
4619
+ const result = await callDaemon("dom.getText", {
4620
+ sessionId,
4621
+ ref,
4622
+ maxChars,
4623
+ ...typeof targetId === "string" ? { targetId } : {}
4624
+ });
3299
4625
  return { success: true, message: "DOM text captured.", data: result };
3300
4626
  }
3301
4627
 
@@ -3342,10 +4668,16 @@ function parseDomAttrArgs(rawArgs) {
3342
4668
  }
3343
4669
  async function runDomAttr(args) {
3344
4670
  const { sessionId, ref, attr } = parseDomAttrArgs(args.rawArgs);
4671
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3345
4672
  if (!sessionId) throw createUsageError("Missing --session-id");
3346
4673
  if (!ref) throw createUsageError("Missing --ref");
3347
4674
  if (!attr) throw createUsageError("Missing --attr");
3348
- const result = await callDaemon("dom.getAttr", { sessionId, ref, name: attr });
4675
+ const result = await callDaemon("dom.getAttr", {
4676
+ sessionId,
4677
+ ref,
4678
+ name: attr,
4679
+ ...typeof targetId === "string" ? { targetId } : {}
4680
+ });
3349
4681
  return { success: true, message: "DOM attribute captured.", data: result };
3350
4682
  }
3351
4683
 
@@ -3381,9 +4713,14 @@ function parseDomValueArgs(rawArgs) {
3381
4713
  }
3382
4714
  async function runDomValue(args) {
3383
4715
  const { sessionId, ref } = parseDomValueArgs(args.rawArgs);
4716
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3384
4717
  if (!sessionId) throw createUsageError("Missing --session-id");
3385
4718
  if (!ref) throw createUsageError("Missing --ref");
3386
- const result = await callDaemon("dom.getValue", { sessionId, ref });
4719
+ const result = await callDaemon("dom.getValue", {
4720
+ sessionId,
4721
+ ref,
4722
+ ...typeof targetId === "string" ? { targetId } : {}
4723
+ });
3387
4724
  return { success: true, message: "DOM value captured.", data: result };
3388
4725
  }
3389
4726
 
@@ -3419,9 +4756,14 @@ function parseDomVisibleArgs(rawArgs) {
3419
4756
  }
3420
4757
  async function runDomVisible(args) {
3421
4758
  const { sessionId, ref } = parseDomVisibleArgs(args.rawArgs);
4759
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3422
4760
  if (!sessionId) throw createUsageError("Missing --session-id");
3423
4761
  if (!ref) throw createUsageError("Missing --ref");
3424
- const result = await callDaemon("dom.isVisible", { sessionId, ref });
4762
+ const result = await callDaemon("dom.isVisible", {
4763
+ sessionId,
4764
+ ref,
4765
+ ...typeof targetId === "string" ? { targetId } : {}
4766
+ });
3425
4767
  return { success: true, message: "Visibility checked.", data: result };
3426
4768
  }
3427
4769
 
@@ -3457,9 +4799,14 @@ function parseDomEnabledArgs(rawArgs) {
3457
4799
  }
3458
4800
  async function runDomEnabled(args) {
3459
4801
  const { sessionId, ref } = parseDomEnabledArgs(args.rawArgs);
4802
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3460
4803
  if (!sessionId) throw createUsageError("Missing --session-id");
3461
4804
  if (!ref) throw createUsageError("Missing --ref");
3462
- const result = await callDaemon("dom.isEnabled", { sessionId, ref });
4805
+ const result = await callDaemon("dom.isEnabled", {
4806
+ sessionId,
4807
+ ref,
4808
+ ...typeof targetId === "string" ? { targetId } : {}
4809
+ });
3463
4810
  return { success: true, message: "Enabled state checked.", data: result };
3464
4811
  }
3465
4812
 
@@ -3495,9 +4842,14 @@ function parseDomCheckedArgs(rawArgs) {
3495
4842
  }
3496
4843
  async function runDomChecked(args) {
3497
4844
  const { sessionId, ref } = parseDomCheckedArgs(args.rawArgs);
4845
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3498
4846
  if (!sessionId) throw createUsageError("Missing --session-id");
3499
4847
  if (!ref) throw createUsageError("Missing --ref");
3500
- const result = await callDaemon("dom.isChecked", { sessionId, ref });
4848
+ const result = await callDaemon("dom.isChecked", {
4849
+ sessionId,
4850
+ ref,
4851
+ ...typeof targetId === "string" ? { targetId } : {}
4852
+ });
3501
4853
  return { success: true, message: "Checked state reported.", data: result };
3502
4854
  }
3503
4855
 
@@ -3517,13 +4869,27 @@ function parseClonePageArgs(rawArgs) {
3517
4869
  parsed.sessionId = arg.split("=", 2)[1];
3518
4870
  continue;
3519
4871
  }
4872
+ if (arg === "--target-id") {
4873
+ const value = rawArgs[i + 1];
4874
+ if (!value) throw createUsageError("Missing value for --target-id");
4875
+ parsed.targetId = value;
4876
+ i += 1;
4877
+ continue;
4878
+ }
4879
+ if (arg?.startsWith("--target-id=")) {
4880
+ parsed.targetId = arg.split("=", 2)[1];
4881
+ continue;
4882
+ }
3520
4883
  }
3521
4884
  return parsed;
3522
4885
  }
3523
4886
  async function runClonePage(args) {
3524
- const { sessionId } = parseClonePageArgs(args.rawArgs);
4887
+ const { sessionId, targetId } = parseClonePageArgs(args.rawArgs);
3525
4888
  if (!sessionId) throw createUsageError("Missing --session-id");
3526
- const result = await callDaemon("export.clonePage", { sessionId });
4889
+ const result = await callDaemon("export.clonePage", {
4890
+ sessionId,
4891
+ ...typeof targetId === "string" ? { targetId } : {}
4892
+ });
3527
4893
  return { success: true, message: "Page cloned.", data: result };
3528
4894
  }
3529
4895
 
@@ -3554,14 +4920,29 @@ function parseCloneComponentArgs(rawArgs) {
3554
4920
  parsed.ref = arg.split("=", 2)[1];
3555
4921
  continue;
3556
4922
  }
4923
+ if (arg === "--target-id") {
4924
+ const value = rawArgs[i + 1];
4925
+ if (!value) throw createUsageError("Missing value for --target-id");
4926
+ parsed.targetId = value;
4927
+ i += 1;
4928
+ continue;
4929
+ }
4930
+ if (arg?.startsWith("--target-id=")) {
4931
+ parsed.targetId = arg.split("=", 2)[1];
4932
+ continue;
4933
+ }
3557
4934
  }
3558
4935
  return parsed;
3559
4936
  }
3560
4937
  async function runCloneComponent(args) {
3561
- const { sessionId, ref } = parseCloneComponentArgs(args.rawArgs);
4938
+ const { sessionId, ref, targetId } = parseCloneComponentArgs(args.rawArgs);
3562
4939
  if (!sessionId) throw createUsageError("Missing --session-id");
3563
4940
  if (!ref) throw createUsageError("Missing --ref");
3564
- const result = await callDaemon("export.cloneComponent", { sessionId, ref });
4941
+ const result = await callDaemon("export.cloneComponent", {
4942
+ sessionId,
4943
+ ref,
4944
+ ...typeof targetId === "string" ? { targetId } : {}
4945
+ });
3565
4946
  return { success: true, message: "Component cloned.", data: result };
3566
4947
  }
3567
4948
 
@@ -3586,45 +4967,72 @@ function parsePerfArgs(rawArgs) {
3586
4967
  }
3587
4968
  async function runPerf(args) {
3588
4969
  const { sessionId } = parsePerfArgs(args.rawArgs);
4970
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3589
4971
  if (!sessionId) throw createUsageError("Missing --session-id");
3590
- const result = await callDaemon("devtools.perf", { sessionId });
4972
+ const result = await callDaemon("devtools.perf", {
4973
+ sessionId,
4974
+ ...typeof targetId === "string" ? { targetId } : {}
4975
+ });
3591
4976
  return { success: true, message: "Performance metrics captured.", data: result };
3592
4977
  }
3593
4978
 
3594
4979
  // src/cli/commands/devtools/screenshot.ts
4980
+ var requireValue5 = (value, flag) => {
4981
+ if (!value) throw createUsageError(`Missing value for ${flag}`);
4982
+ return value;
4983
+ };
3595
4984
  function parseScreenshotArgs(rawArgs) {
3596
4985
  const parsed = {};
3597
4986
  for (let i = 0; i < rawArgs.length; i += 1) {
3598
4987
  const arg = rawArgs[i];
3599
4988
  if (arg === "--session-id") {
3600
- const value = rawArgs[i + 1];
3601
- if (!value) throw createUsageError("Missing value for --session-id");
3602
- parsed.sessionId = value;
4989
+ parsed.sessionId = requireValue5(rawArgs[i + 1], "--session-id");
3603
4990
  i += 1;
3604
4991
  continue;
3605
4992
  }
3606
4993
  if (arg?.startsWith("--session-id=")) {
3607
- parsed.sessionId = arg.split("=", 2)[1];
4994
+ parsed.sessionId = requireValue5(arg.split("=", 2)[1], "--session-id");
3608
4995
  continue;
3609
4996
  }
3610
- if (arg === "--path") {
3611
- const value = rawArgs[i + 1];
3612
- if (!value) throw createUsageError("Missing value for --path");
3613
- parsed.path = value;
4997
+ if (arg === "--target-id") {
4998
+ parsed.targetId = requireValue5(rawArgs[i + 1], "--target-id");
3614
4999
  i += 1;
3615
5000
  continue;
3616
5001
  }
3617
- if (arg?.startsWith("--path=")) {
3618
- parsed.path = arg.split("=", 2)[1];
5002
+ if (arg?.startsWith("--target-id=")) {
5003
+ parsed.targetId = requireValue5(arg.split("=", 2)[1], "--target-id");
3619
5004
  continue;
3620
5005
  }
3621
- }
3622
- return parsed;
5006
+ if (arg === "--path") {
5007
+ parsed.path = requireValue5(rawArgs[i + 1], "--path");
5008
+ i += 1;
5009
+ continue;
5010
+ }
5011
+ if (arg?.startsWith("--path=")) {
5012
+ parsed.path = requireValue5(arg.split("=", 2)[1], "--path");
5013
+ continue;
5014
+ }
5015
+ if (arg === "--timeout-ms") {
5016
+ parsed.timeoutMs = parseNumberFlag(requireValue5(rawArgs[i + 1], "--timeout-ms"), "--timeout-ms", { min: 1 });
5017
+ i += 1;
5018
+ continue;
5019
+ }
5020
+ if (arg?.startsWith("--timeout-ms=")) {
5021
+ parsed.timeoutMs = parseNumberFlag(requireValue5(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
5022
+ continue;
5023
+ }
5024
+ }
5025
+ return parsed;
3623
5026
  }
3624
5027
  async function runScreenshot(args) {
3625
- const { sessionId, path: path8 } = parseScreenshotArgs(args.rawArgs);
5028
+ const { sessionId, targetId, path: path8, timeoutMs } = parseScreenshotArgs(args.rawArgs);
3626
5029
  if (!sessionId) throw createUsageError("Missing --session-id");
3627
- const result = await callDaemon("page.screenshot", { sessionId, path: path8 });
5030
+ const params = {
5031
+ sessionId,
5032
+ path: path8,
5033
+ ...typeof targetId === "string" ? { targetId } : {}
5034
+ };
5035
+ const result = typeof timeoutMs === "number" ? await callDaemon("page.screenshot", params, { timeoutMs }) : await callDaemon("page.screenshot", params);
3628
5036
  return { success: true, message: "Screenshot captured.", data: result };
3629
5037
  }
3630
5038
 
@@ -3724,14 +5132,1055 @@ async function runNetworkPoll(args) {
3724
5132
  return { success: true, message: "Network events polled.", data: result };
3725
5133
  }
3726
5134
 
5135
+ // src/cli/commands/devtools/debug-trace-snapshot.ts
5136
+ function parseDebugTraceSnapshotArgs(rawArgs) {
5137
+ const parsed = {};
5138
+ for (let index = 0; index < rawArgs.length; index += 1) {
5139
+ const arg = rawArgs[index];
5140
+ if (arg === "--session-id") {
5141
+ const value = rawArgs[index + 1];
5142
+ if (!value) throw createUsageError("Missing value for --session-id");
5143
+ parsed.sessionId = value;
5144
+ index += 1;
5145
+ continue;
5146
+ }
5147
+ if (arg?.startsWith("--session-id=")) {
5148
+ parsed.sessionId = arg.split("=", 2)[1];
5149
+ continue;
5150
+ }
5151
+ if (arg === "--since-console-seq") {
5152
+ const value = rawArgs[index + 1];
5153
+ if (!value) throw createUsageError("Missing value for --since-console-seq");
5154
+ parsed.sinceConsoleSeq = parseNumberFlag(value, "--since-console-seq", { min: 0 });
5155
+ index += 1;
5156
+ continue;
5157
+ }
5158
+ if (arg?.startsWith("--since-console-seq=")) {
5159
+ const value = arg.split("=", 2)[1];
5160
+ if (!value) throw createUsageError("Missing value for --since-console-seq");
5161
+ parsed.sinceConsoleSeq = parseNumberFlag(value, "--since-console-seq", { min: 0 });
5162
+ continue;
5163
+ }
5164
+ if (arg === "--since-network-seq") {
5165
+ const value = rawArgs[index + 1];
5166
+ if (!value) throw createUsageError("Missing value for --since-network-seq");
5167
+ parsed.sinceNetworkSeq = parseNumberFlag(value, "--since-network-seq", { min: 0 });
5168
+ index += 1;
5169
+ continue;
5170
+ }
5171
+ if (arg?.startsWith("--since-network-seq=")) {
5172
+ const value = arg.split("=", 2)[1];
5173
+ if (!value) throw createUsageError("Missing value for --since-network-seq");
5174
+ parsed.sinceNetworkSeq = parseNumberFlag(value, "--since-network-seq", { min: 0 });
5175
+ continue;
5176
+ }
5177
+ if (arg === "--since-exception-seq") {
5178
+ const value = rawArgs[index + 1];
5179
+ if (!value) throw createUsageError("Missing value for --since-exception-seq");
5180
+ parsed.sinceExceptionSeq = parseNumberFlag(value, "--since-exception-seq", { min: 0 });
5181
+ index += 1;
5182
+ continue;
5183
+ }
5184
+ if (arg?.startsWith("--since-exception-seq=")) {
5185
+ const value = arg.split("=", 2)[1];
5186
+ if (!value) throw createUsageError("Missing value for --since-exception-seq");
5187
+ parsed.sinceExceptionSeq = parseNumberFlag(value, "--since-exception-seq", { min: 0 });
5188
+ continue;
5189
+ }
5190
+ if (arg === "--max") {
5191
+ const value = rawArgs[index + 1];
5192
+ if (!value) throw createUsageError("Missing value for --max");
5193
+ parsed.max = parseNumberFlag(value, "--max", { min: 1 });
5194
+ index += 1;
5195
+ continue;
5196
+ }
5197
+ if (arg?.startsWith("--max=")) {
5198
+ const value = arg.split("=", 2)[1];
5199
+ if (!value) throw createUsageError("Missing value for --max");
5200
+ parsed.max = parseNumberFlag(value, "--max", { min: 1 });
5201
+ continue;
5202
+ }
5203
+ if (arg === "--request-id") {
5204
+ const value = rawArgs[index + 1];
5205
+ if (!value) throw createUsageError("Missing value for --request-id");
5206
+ parsed.requestId = value;
5207
+ index += 1;
5208
+ continue;
5209
+ }
5210
+ if (arg?.startsWith("--request-id=")) {
5211
+ const value = arg.split("=", 2)[1];
5212
+ if (!value) throw createUsageError("Missing value for --request-id");
5213
+ parsed.requestId = value;
5214
+ continue;
5215
+ }
5216
+ }
5217
+ return parsed;
5218
+ }
5219
+ async function runDebugTraceSnapshot(args) {
5220
+ const parsed = parseDebugTraceSnapshotArgs(args.rawArgs);
5221
+ if (!parsed.sessionId) {
5222
+ throw createUsageError("Missing --session-id");
5223
+ }
5224
+ const result = await callDaemon("devtools.debugTraceSnapshot", {
5225
+ sessionId: parsed.sessionId,
5226
+ sinceConsoleSeq: parsed.sinceConsoleSeq,
5227
+ sinceNetworkSeq: parsed.sinceNetworkSeq,
5228
+ sinceExceptionSeq: parsed.sinceExceptionSeq,
5229
+ max: parsed.max,
5230
+ requestId: parsed.requestId
5231
+ });
5232
+ return {
5233
+ success: true,
5234
+ message: "Debug trace snapshot captured.",
5235
+ data: result
5236
+ };
5237
+ }
5238
+
5239
+ // src/cli/commands/session/cookie-import.ts
5240
+ import { readFileSync as readFileSync7 } from "fs";
5241
+ var requireValue6 = (value, flag) => {
5242
+ if (!value) {
5243
+ throw createUsageError(`Missing value for ${flag}`);
5244
+ }
5245
+ return value;
5246
+ };
5247
+ var parseStrictValue = (value, flag) => {
5248
+ const normalized = value.trim().toLowerCase();
5249
+ if (normalized === "true") return true;
5250
+ if (normalized === "false") return false;
5251
+ throw createUsageError(`Invalid ${flag}: ${value}`);
5252
+ };
5253
+ var parseCookieImportArgs = (rawArgs) => {
5254
+ const parsed = {};
5255
+ for (let index = 0; index < rawArgs.length; index += 1) {
5256
+ const arg = rawArgs[index];
5257
+ if (arg === "--session-id") {
5258
+ parsed.sessionId = requireValue6(rawArgs[index + 1], "--session-id");
5259
+ index += 1;
5260
+ continue;
5261
+ }
5262
+ if (arg?.startsWith("--session-id=")) {
5263
+ parsed.sessionId = requireValue6(arg.split("=", 2)[1], "--session-id");
5264
+ continue;
5265
+ }
5266
+ if (arg === "--cookies") {
5267
+ parsed.cookies = requireValue6(rawArgs[index + 1], "--cookies");
5268
+ index += 1;
5269
+ continue;
5270
+ }
5271
+ if (arg?.startsWith("--cookies=")) {
5272
+ parsed.cookies = requireValue6(arg.split("=", 2)[1], "--cookies");
5273
+ continue;
5274
+ }
5275
+ if (arg === "--cookies-file") {
5276
+ parsed.cookiesFile = requireValue6(rawArgs[index + 1], "--cookies-file");
5277
+ index += 1;
5278
+ continue;
5279
+ }
5280
+ if (arg?.startsWith("--cookies-file=")) {
5281
+ parsed.cookiesFile = requireValue6(arg.split("=", 2)[1], "--cookies-file");
5282
+ continue;
5283
+ }
5284
+ if (arg === "--strict") {
5285
+ parsed.strict = true;
5286
+ continue;
5287
+ }
5288
+ if (arg?.startsWith("--strict=")) {
5289
+ parsed.strict = parseStrictValue(requireValue6(arg.split("=", 2)[1], "--strict"), "--strict");
5290
+ continue;
5291
+ }
5292
+ if (arg === "--request-id") {
5293
+ parsed.requestId = requireValue6(rawArgs[index + 1], "--request-id");
5294
+ index += 1;
5295
+ continue;
5296
+ }
5297
+ if (arg?.startsWith("--request-id=")) {
5298
+ parsed.requestId = requireValue6(arg.split("=", 2)[1], "--request-id");
5299
+ continue;
5300
+ }
5301
+ }
5302
+ return parsed;
5303
+ };
5304
+ var parseCookiesJson = (raw, source) => {
5305
+ let parsed;
5306
+ try {
5307
+ parsed = JSON.parse(raw);
5308
+ } catch (error) {
5309
+ const message = error instanceof Error ? error.message : "Invalid JSON";
5310
+ throw createUsageError(`Invalid JSON from ${source}: ${message}`);
5311
+ }
5312
+ if (!Array.isArray(parsed)) {
5313
+ throw createUsageError(`Invalid JSON from ${source}: expected array`);
5314
+ }
5315
+ const cookies = [];
5316
+ for (const entry of parsed) {
5317
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
5318
+ throw createUsageError(`Invalid JSON from ${source}: expected cookie object entries`);
5319
+ }
5320
+ const cookie = entry;
5321
+ if (typeof cookie.name !== "string" || typeof cookie.value !== "string") {
5322
+ throw createUsageError(`Invalid JSON from ${source}: each cookie requires string name and value`);
5323
+ }
5324
+ if (typeof cookie.sameSite !== "undefined" && cookie.sameSite !== "Strict" && cookie.sameSite !== "Lax" && cookie.sameSite !== "None") {
5325
+ throw createUsageError(`Invalid JSON from ${source}: sameSite must be Strict, Lax, or None`);
5326
+ }
5327
+ cookies.push({
5328
+ name: cookie.name,
5329
+ value: cookie.value,
5330
+ ...typeof cookie.url === "string" ? { url: cookie.url } : {},
5331
+ ...typeof cookie.domain === "string" ? { domain: cookie.domain } : {},
5332
+ ...typeof cookie.path === "string" ? { path: cookie.path } : {},
5333
+ ...typeof cookie.expires === "number" ? { expires: cookie.expires } : {},
5334
+ ...typeof cookie.httpOnly === "boolean" ? { httpOnly: cookie.httpOnly } : {},
5335
+ ...typeof cookie.secure === "boolean" ? { secure: cookie.secure } : {},
5336
+ ...cookie.sameSite ? { sameSite: cookie.sameSite } : {}
5337
+ });
5338
+ }
5339
+ return cookies;
5340
+ };
5341
+ var resolveCookies = (parsed) => {
5342
+ const hasInline = typeof parsed.cookies === "string";
5343
+ const hasFile = typeof parsed.cookiesFile === "string";
5344
+ if (!hasInline && !hasFile) {
5345
+ throw createUsageError("Missing --cookies or --cookies-file");
5346
+ }
5347
+ if (hasInline && hasFile) {
5348
+ throw createUsageError("Provide only one cookies source: --cookies or --cookies-file.");
5349
+ }
5350
+ if (hasInline) {
5351
+ return parseCookiesJson(parsed.cookies ?? "", "--cookies");
5352
+ }
5353
+ let raw = "";
5354
+ try {
5355
+ raw = readFileSync7(parsed.cookiesFile ?? "", "utf8");
5356
+ } catch (error) {
5357
+ const message = error instanceof Error ? error.message : "Unable to read file";
5358
+ throw createUsageError(`Invalid --cookies-file: ${message}`);
5359
+ }
5360
+ if (!raw.trim()) {
5361
+ throw createUsageError("Invalid JSON from --cookies-file: empty input");
5362
+ }
5363
+ return parseCookiesJson(raw, "--cookies-file");
5364
+ };
5365
+ async function runCookieImport(args) {
5366
+ const parsed = parseCookieImportArgs(args.rawArgs);
5367
+ if (!parsed.sessionId) {
5368
+ throw createUsageError("Missing --session-id");
5369
+ }
5370
+ const cookies = resolveCookies(parsed);
5371
+ const result = await callDaemon("session.cookieImport", {
5372
+ sessionId: parsed.sessionId,
5373
+ cookies,
5374
+ strict: parsed.strict ?? true,
5375
+ requestId: parsed.requestId
5376
+ });
5377
+ const imported = typeof result.imported === "number" ? result.imported : cookies.length;
5378
+ return {
5379
+ success: true,
5380
+ message: `Cookies imported: ${imported}`,
5381
+ data: result
5382
+ };
5383
+ }
5384
+
5385
+ // src/cli/commands/session/cookie-list.ts
5386
+ var requireValue7 = (value, flag) => {
5387
+ if (!value) {
5388
+ throw createUsageError(`Missing value for ${flag}`);
5389
+ }
5390
+ return value;
5391
+ };
5392
+ var normalizeCookieUrls = (values) => {
5393
+ const normalized = [];
5394
+ const seen = /* @__PURE__ */ new Set();
5395
+ for (const value of values) {
5396
+ const trimmed = value.trim();
5397
+ if (!trimmed) {
5398
+ continue;
5399
+ }
5400
+ let parsedUrl;
5401
+ try {
5402
+ parsedUrl = new URL(trimmed);
5403
+ } catch {
5404
+ throw createUsageError(`Invalid --url value: ${trimmed}`);
5405
+ }
5406
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
5407
+ throw createUsageError(`Invalid --url protocol: ${trimmed}`);
5408
+ }
5409
+ const normalizedUrl = parsedUrl.toString();
5410
+ if (seen.has(normalizedUrl)) {
5411
+ continue;
5412
+ }
5413
+ seen.add(normalizedUrl);
5414
+ normalized.push(normalizedUrl);
5415
+ }
5416
+ return normalized;
5417
+ };
5418
+ var parseCookieListArgs = (rawArgs) => {
5419
+ const parsed = { urls: [] };
5420
+ for (let index = 0; index < rawArgs.length; index += 1) {
5421
+ const arg = rawArgs[index];
5422
+ if (arg === "--session-id") {
5423
+ parsed.sessionId = requireValue7(rawArgs[index + 1], "--session-id");
5424
+ index += 1;
5425
+ continue;
5426
+ }
5427
+ if (arg?.startsWith("--session-id=")) {
5428
+ parsed.sessionId = requireValue7(arg.split("=", 2)[1], "--session-id");
5429
+ continue;
5430
+ }
5431
+ if (arg === "--url") {
5432
+ const rawValue = requireValue7(rawArgs[index + 1], "--url");
5433
+ parsed.urls.push(...rawValue.split(","));
5434
+ index += 1;
5435
+ continue;
5436
+ }
5437
+ if (arg?.startsWith("--url=")) {
5438
+ parsed.urls.push(...requireValue7(arg.split("=", 2)[1], "--url").split(","));
5439
+ continue;
5440
+ }
5441
+ if (arg === "--request-id") {
5442
+ parsed.requestId = requireValue7(rawArgs[index + 1], "--request-id");
5443
+ index += 1;
5444
+ continue;
5445
+ }
5446
+ if (arg?.startsWith("--request-id=")) {
5447
+ parsed.requestId = requireValue7(arg.split("=", 2)[1], "--request-id");
5448
+ continue;
5449
+ }
5450
+ }
5451
+ parsed.urls = normalizeCookieUrls(parsed.urls);
5452
+ return parsed;
5453
+ };
5454
+ async function runCookieList(args) {
5455
+ const parsed = parseCookieListArgs(args.rawArgs);
5456
+ if (!parsed.sessionId) {
5457
+ throw createUsageError("Missing --session-id");
5458
+ }
5459
+ const result = await callDaemon("session.cookieList", {
5460
+ sessionId: parsed.sessionId,
5461
+ ...parsed.urls.length > 0 ? { urls: parsed.urls } : {},
5462
+ requestId: parsed.requestId
5463
+ });
5464
+ const count = typeof result.count === "number" ? result.count : Array.isArray(result.cookies) ? result.cookies.length : 0;
5465
+ return {
5466
+ success: true,
5467
+ message: `Cookies listed: ${count}`,
5468
+ data: result
5469
+ };
5470
+ }
5471
+
5472
+ // src/cli/commands/macro-resolve.ts
5473
+ var requireValue8 = (value, flag) => {
5474
+ if (!value) {
5475
+ throw createUsageError(`Missing value for ${flag}`);
5476
+ }
5477
+ return value;
5478
+ };
5479
+ var parseMacroResolveArgs = (rawArgs) => {
5480
+ const parsed = {};
5481
+ for (let index = 0; index < rawArgs.length; index += 1) {
5482
+ const arg = rawArgs[index];
5483
+ if (arg === "--expression") {
5484
+ parsed.expression = requireValue8(rawArgs[index + 1], "--expression");
5485
+ index += 1;
5486
+ continue;
5487
+ }
5488
+ if (arg?.startsWith("--expression=")) {
5489
+ parsed.expression = requireValue8(arg.split("=", 2)[1], "--expression");
5490
+ continue;
5491
+ }
5492
+ if (arg === "--default-provider") {
5493
+ parsed.defaultProvider = requireValue8(rawArgs[index + 1], "--default-provider");
5494
+ index += 1;
5495
+ continue;
5496
+ }
5497
+ if (arg?.startsWith("--default-provider=")) {
5498
+ parsed.defaultProvider = requireValue8(arg.split("=", 2)[1], "--default-provider");
5499
+ continue;
5500
+ }
5501
+ if (arg === "--include-catalog") {
5502
+ parsed.includeCatalog = true;
5503
+ continue;
5504
+ }
5505
+ if (arg === "--execute") {
5506
+ parsed.execute = true;
5507
+ continue;
5508
+ }
5509
+ if (arg === "--timeout-ms") {
5510
+ const value = requireValue8(rawArgs[index + 1], "--timeout-ms");
5511
+ parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
5512
+ index += 1;
5513
+ continue;
5514
+ }
5515
+ if (arg?.startsWith("--timeout-ms=")) {
5516
+ parsed.timeoutMs = parseNumberFlag(requireValue8(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
5517
+ continue;
5518
+ }
5519
+ }
5520
+ return parsed;
5521
+ };
5522
+ async function runMacroResolve(args) {
5523
+ const parsed = parseMacroResolveArgs(args.rawArgs);
5524
+ if (!parsed.expression) {
5525
+ throw createUsageError("Missing --expression");
5526
+ }
5527
+ const params = {
5528
+ expression: parsed.expression,
5529
+ defaultProvider: parsed.defaultProvider,
5530
+ includeCatalog: parsed.includeCatalog ?? false,
5531
+ execute: parsed.execute ?? false
5532
+ };
5533
+ const result = typeof parsed.timeoutMs === "number" ? await callDaemon("macro.resolve", params, { timeoutMs: parsed.timeoutMs }) : await callDaemon("macro.resolve", params);
5534
+ return {
5535
+ success: true,
5536
+ message: parsed.execute ? "Macro resolved and executed." : "Macro resolved.",
5537
+ data: result
5538
+ };
5539
+ }
5540
+
5541
+ // src/cli/commands/research.ts
5542
+ var SOURCE_VALUES = /* @__PURE__ */ new Set(["web", "community", "social", "shopping"]);
5543
+ var SOURCE_SELECTION_VALUES = /* @__PURE__ */ new Set(["auto", "web", "community", "social", "shopping", "all"]);
5544
+ var MODE_VALUES = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
5545
+ var COOKIE_POLICY_VALUES = /* @__PURE__ */ new Set(["off", "auto", "required"]);
5546
+ var requireValue9 = (rawArgs, index, flag) => {
5547
+ const value = rawArgs[index + 1];
5548
+ if (!value) {
5549
+ throw createUsageError(`Missing value for ${flag}`);
5550
+ }
5551
+ return value;
5552
+ };
5553
+ var parseBoolean = (value, flag) => {
5554
+ if (value === "true") return true;
5555
+ if (value === "false") return false;
5556
+ throw createUsageError(`Invalid ${flag}: ${value}`);
5557
+ };
5558
+ var parseSources = (raw) => {
5559
+ const parsed = raw.split(",").map((entry) => entry.trim().toLowerCase()).filter(Boolean);
5560
+ if (parsed.length === 0) {
5561
+ throw createUsageError("--sources requires at least one source");
5562
+ }
5563
+ const deduped = [...new Set(parsed)];
5564
+ for (const source of deduped) {
5565
+ if (!SOURCE_VALUES.has(source)) {
5566
+ throw createUsageError(`Invalid --sources value: ${source}`);
5567
+ }
5568
+ }
5569
+ return deduped;
5570
+ };
5571
+ var parseResearchRunArgs = (rawArgs) => {
5572
+ const parsed = {};
5573
+ for (let index = 0; index < rawArgs.length; index += 1) {
5574
+ const arg = rawArgs[index];
5575
+ if (arg === "--topic") {
5576
+ parsed.topic = requireValue9(rawArgs, index, "--topic");
5577
+ index += 1;
5578
+ continue;
5579
+ }
5580
+ if (arg?.startsWith("--topic=")) {
5581
+ parsed.topic = arg.split("=", 2)[1];
5582
+ continue;
5583
+ }
5584
+ if (arg === "--days") {
5585
+ parsed.days = parseNumberFlag(requireValue9(rawArgs, index, "--days"), "--days", { min: 1, max: 365 });
5586
+ index += 1;
5587
+ continue;
5588
+ }
5589
+ if (arg?.startsWith("--days=")) {
5590
+ parsed.days = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--days", { min: 1, max: 365 });
5591
+ continue;
5592
+ }
5593
+ if (arg === "--from") {
5594
+ parsed.from = requireValue9(rawArgs, index, "--from");
5595
+ index += 1;
5596
+ continue;
5597
+ }
5598
+ if (arg?.startsWith("--from=")) {
5599
+ parsed.from = arg.split("=", 2)[1];
5600
+ continue;
5601
+ }
5602
+ if (arg === "--to") {
5603
+ parsed.to = requireValue9(rawArgs, index, "--to");
5604
+ index += 1;
5605
+ continue;
5606
+ }
5607
+ if (arg?.startsWith("--to=")) {
5608
+ parsed.to = arg.split("=", 2)[1];
5609
+ continue;
5610
+ }
5611
+ if (arg === "--source-selection") {
5612
+ const value = requireValue9(rawArgs, index, "--source-selection").toLowerCase();
5613
+ if (!SOURCE_SELECTION_VALUES.has(value)) {
5614
+ throw createUsageError(`Invalid --source-selection: ${value}`);
5615
+ }
5616
+ parsed.sourceSelection = value;
5617
+ index += 1;
5618
+ continue;
5619
+ }
5620
+ if (arg?.startsWith("--source-selection=")) {
5621
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
5622
+ if (!SOURCE_SELECTION_VALUES.has(value)) {
5623
+ throw createUsageError(`Invalid --source-selection: ${value}`);
5624
+ }
5625
+ parsed.sourceSelection = value;
5626
+ continue;
5627
+ }
5628
+ if (arg === "--sources") {
5629
+ parsed.sources = parseSources(requireValue9(rawArgs, index, "--sources"));
5630
+ index += 1;
5631
+ continue;
5632
+ }
5633
+ if (arg?.startsWith("--sources=")) {
5634
+ parsed.sources = parseSources(arg.split("=", 2)[1] ?? "");
5635
+ continue;
5636
+ }
5637
+ if (arg === "--mode") {
5638
+ const value = requireValue9(rawArgs, index, "--mode").toLowerCase();
5639
+ if (!MODE_VALUES.has(value)) {
5640
+ throw createUsageError(`Invalid --mode: ${value}`);
5641
+ }
5642
+ parsed.mode = value;
5643
+ index += 1;
5644
+ continue;
5645
+ }
5646
+ if (arg?.startsWith("--mode=")) {
5647
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
5648
+ if (!MODE_VALUES.has(value)) {
5649
+ throw createUsageError(`Invalid --mode: ${value}`);
5650
+ }
5651
+ parsed.mode = value;
5652
+ continue;
5653
+ }
5654
+ if (arg === "--include-engagement") {
5655
+ parsed.includeEngagement = true;
5656
+ continue;
5657
+ }
5658
+ if (arg === "--limit-per-source") {
5659
+ parsed.limitPerSource = parseNumberFlag(requireValue9(rawArgs, index, "--limit-per-source"), "--limit-per-source", { min: 1, max: 100 });
5660
+ index += 1;
5661
+ continue;
5662
+ }
5663
+ if (arg?.startsWith("--limit-per-source=")) {
5664
+ parsed.limitPerSource = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--limit-per-source", { min: 1, max: 100 });
5665
+ continue;
5666
+ }
5667
+ if (arg === "--output-dir") {
5668
+ parsed.outputDir = requireValue9(rawArgs, index, "--output-dir");
5669
+ index += 1;
5670
+ continue;
5671
+ }
5672
+ if (arg?.startsWith("--output-dir=")) {
5673
+ parsed.outputDir = arg.split("=", 2)[1];
5674
+ continue;
5675
+ }
5676
+ if (arg === "--ttl-hours") {
5677
+ parsed.ttlHours = parseNumberFlag(requireValue9(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5678
+ index += 1;
5679
+ continue;
5680
+ }
5681
+ if (arg?.startsWith("--ttl-hours=")) {
5682
+ parsed.ttlHours = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--ttl-hours", { min: 1, max: 168 });
5683
+ continue;
5684
+ }
5685
+ if (arg === "--use-cookies") {
5686
+ parsed.useCookies = true;
5687
+ continue;
5688
+ }
5689
+ if (arg?.startsWith("--use-cookies=")) {
5690
+ parsed.useCookies = parseBoolean(arg.split("=", 2)[1] ?? "", "--use-cookies");
5691
+ continue;
5692
+ }
5693
+ if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
5694
+ const value = requireValue9(rawArgs, index, arg).toLowerCase();
5695
+ if (!COOKIE_POLICY_VALUES.has(value)) {
5696
+ throw createUsageError(`Invalid ${arg}: ${value}`);
5697
+ }
5698
+ parsed.cookiePolicyOverride = value;
5699
+ index += 1;
5700
+ continue;
5701
+ }
5702
+ if (arg?.startsWith("--cookie-policy-override=") || arg?.startsWith("--cookie-policy=")) {
5703
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
5704
+ if (!COOKIE_POLICY_VALUES.has(value)) {
5705
+ throw createUsageError(`Invalid --cookie-policy-override: ${value}`);
5706
+ }
5707
+ parsed.cookiePolicyOverride = value;
5708
+ continue;
5709
+ }
5710
+ }
5711
+ return parsed;
5712
+ };
5713
+ async function runResearchCommand(args) {
5714
+ const [subcommand, ...rest] = args.rawArgs;
5715
+ if (subcommand !== "run") {
5716
+ throw createUsageError("Usage: opendevbrowser research run --topic <value> [options]");
5717
+ }
5718
+ const parsed = parseResearchRunArgs(rest);
5719
+ if (!parsed.topic?.trim()) {
5720
+ throw createUsageError("Missing --topic");
5721
+ }
5722
+ const data = await callDaemon("research.run", {
5723
+ topic: parsed.topic,
5724
+ days: parsed.days,
5725
+ from: parsed.from,
5726
+ to: parsed.to,
5727
+ sourceSelection: parsed.sourceSelection,
5728
+ sources: parsed.sources,
5729
+ mode: parsed.mode ?? "compact",
5730
+ includeEngagement: parsed.includeEngagement ?? false,
5731
+ limitPerSource: parsed.limitPerSource,
5732
+ outputDir: parsed.outputDir,
5733
+ ttlHours: parsed.ttlHours,
5734
+ useCookies: parsed.useCookies,
5735
+ cookiePolicyOverride: parsed.cookiePolicyOverride
5736
+ });
5737
+ return {
5738
+ success: true,
5739
+ message: "Research workflow completed.",
5740
+ data
5741
+ };
5742
+ }
5743
+
5744
+ // src/cli/commands/shopping.ts
5745
+ var SORT_VALUES = /* @__PURE__ */ new Set(["best_deal", "lowest_price", "highest_rating", "fastest_shipping"]);
5746
+ var MODE_VALUES2 = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
5747
+ var COOKIE_POLICY_VALUES2 = /* @__PURE__ */ new Set(["off", "auto", "required"]);
5748
+ var requireValue10 = (rawArgs, index, flag) => {
5749
+ const value = rawArgs[index + 1];
5750
+ if (!value) {
5751
+ throw createUsageError(`Missing value for ${flag}`);
5752
+ }
5753
+ return value;
5754
+ };
5755
+ var parseBoolean2 = (value, flag) => {
5756
+ if (value === "true") return true;
5757
+ if (value === "false") return false;
5758
+ throw createUsageError(`Invalid ${flag}: ${value}`);
5759
+ };
5760
+ var parseProviders = (raw) => {
5761
+ const providers = raw.split(",").map((entry) => entry.trim()).filter(Boolean);
5762
+ if (providers.length === 0) {
5763
+ throw createUsageError("--providers requires at least one provider");
5764
+ }
5765
+ return [...new Set(providers)];
5766
+ };
5767
+ var parseShoppingRunArgs = (rawArgs) => {
5768
+ const parsed = {};
5769
+ for (let index = 0; index < rawArgs.length; index += 1) {
5770
+ const arg = rawArgs[index];
5771
+ if (arg === "--query") {
5772
+ parsed.query = requireValue10(rawArgs, index, "--query");
5773
+ index += 1;
5774
+ continue;
5775
+ }
5776
+ if (arg?.startsWith("--query=")) {
5777
+ parsed.query = arg.split("=", 2)[1];
5778
+ continue;
5779
+ }
5780
+ if (arg === "--providers") {
5781
+ parsed.providers = parseProviders(requireValue10(rawArgs, index, "--providers"));
5782
+ index += 1;
5783
+ continue;
5784
+ }
5785
+ if (arg?.startsWith("--providers=")) {
5786
+ parsed.providers = parseProviders(arg.split("=", 2)[1] ?? "");
5787
+ continue;
5788
+ }
5789
+ if (arg === "--budget") {
5790
+ parsed.budget = parseNumberFlag(requireValue10(rawArgs, index, "--budget"), "--budget", { min: 1, integer: false });
5791
+ index += 1;
5792
+ continue;
5793
+ }
5794
+ if (arg?.startsWith("--budget=")) {
5795
+ parsed.budget = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--budget", { min: 1, integer: false });
5796
+ continue;
5797
+ }
5798
+ if (arg === "--region") {
5799
+ parsed.region = requireValue10(rawArgs, index, "--region");
5800
+ index += 1;
5801
+ continue;
5802
+ }
5803
+ if (arg?.startsWith("--region=")) {
5804
+ parsed.region = arg.split("=", 2)[1];
5805
+ continue;
5806
+ }
5807
+ if (arg === "--sort") {
5808
+ const value = requireValue10(rawArgs, index, "--sort").toLowerCase();
5809
+ if (!SORT_VALUES.has(value)) {
5810
+ throw createUsageError(`Invalid --sort: ${value}`);
5811
+ }
5812
+ parsed.sort = value;
5813
+ index += 1;
5814
+ continue;
5815
+ }
5816
+ if (arg?.startsWith("--sort=")) {
5817
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
5818
+ if (!SORT_VALUES.has(value)) {
5819
+ throw createUsageError(`Invalid --sort: ${value}`);
5820
+ }
5821
+ parsed.sort = value;
5822
+ continue;
5823
+ }
5824
+ if (arg === "--mode") {
5825
+ const value = requireValue10(rawArgs, index, "--mode").toLowerCase();
5826
+ if (!MODE_VALUES2.has(value)) {
5827
+ throw createUsageError(`Invalid --mode: ${value}`);
5828
+ }
5829
+ parsed.mode = value;
5830
+ index += 1;
5831
+ continue;
5832
+ }
5833
+ if (arg?.startsWith("--mode=")) {
5834
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
5835
+ if (!MODE_VALUES2.has(value)) {
5836
+ throw createUsageError(`Invalid --mode: ${value}`);
5837
+ }
5838
+ parsed.mode = value;
5839
+ continue;
5840
+ }
5841
+ if (arg === "--timeout-ms") {
5842
+ parsed.timeoutMs = parseNumberFlag(requireValue10(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
5843
+ index += 1;
5844
+ continue;
5845
+ }
5846
+ if (arg?.startsWith("--timeout-ms=")) {
5847
+ parsed.timeoutMs = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--timeout-ms", { min: 1 });
5848
+ continue;
5849
+ }
5850
+ if (arg === "--output-dir") {
5851
+ parsed.outputDir = requireValue10(rawArgs, index, "--output-dir");
5852
+ index += 1;
5853
+ continue;
5854
+ }
5855
+ if (arg?.startsWith("--output-dir=")) {
5856
+ parsed.outputDir = arg.split("=", 2)[1];
5857
+ continue;
5858
+ }
5859
+ if (arg === "--ttl-hours") {
5860
+ parsed.ttlHours = parseNumberFlag(requireValue10(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5861
+ index += 1;
5862
+ continue;
5863
+ }
5864
+ if (arg?.startsWith("--ttl-hours=")) {
5865
+ parsed.ttlHours = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--ttl-hours", { min: 1, max: 168 });
5866
+ continue;
5867
+ }
5868
+ if (arg === "--use-cookies") {
5869
+ parsed.useCookies = true;
5870
+ continue;
5871
+ }
5872
+ if (arg?.startsWith("--use-cookies=")) {
5873
+ parsed.useCookies = parseBoolean2(arg.split("=", 2)[1] ?? "", "--use-cookies");
5874
+ continue;
5875
+ }
5876
+ if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
5877
+ const value = requireValue10(rawArgs, index, arg).toLowerCase();
5878
+ if (!COOKIE_POLICY_VALUES2.has(value)) {
5879
+ throw createUsageError(`Invalid ${arg}: ${value}`);
5880
+ }
5881
+ parsed.cookiePolicyOverride = value;
5882
+ index += 1;
5883
+ continue;
5884
+ }
5885
+ if (arg?.startsWith("--cookie-policy-override=") || arg?.startsWith("--cookie-policy=")) {
5886
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
5887
+ if (!COOKIE_POLICY_VALUES2.has(value)) {
5888
+ throw createUsageError(`Invalid --cookie-policy-override: ${value}`);
5889
+ }
5890
+ parsed.cookiePolicyOverride = value;
5891
+ continue;
5892
+ }
5893
+ }
5894
+ return parsed;
5895
+ };
5896
+ async function runShoppingCommand(args) {
5897
+ const [subcommand, ...rest] = args.rawArgs;
5898
+ if (subcommand !== "run") {
5899
+ throw createUsageError("Usage: opendevbrowser shopping run --query <value> [options]");
5900
+ }
5901
+ const parsed = parseShoppingRunArgs(rest);
5902
+ if (!parsed.query?.trim()) {
5903
+ throw createUsageError("Missing --query");
5904
+ }
5905
+ const payload = {
5906
+ query: parsed.query,
5907
+ providers: parsed.providers,
5908
+ budget: parsed.budget,
5909
+ region: parsed.region,
5910
+ sort: parsed.sort,
5911
+ mode: parsed.mode ?? "compact",
5912
+ ...typeof parsed.timeoutMs === "number" ? { timeoutMs: parsed.timeoutMs } : {},
5913
+ outputDir: parsed.outputDir,
5914
+ ttlHours: parsed.ttlHours,
5915
+ useCookies: parsed.useCookies,
5916
+ cookiePolicyOverride: parsed.cookiePolicyOverride
5917
+ };
5918
+ const data = typeof parsed.timeoutMs === "number" ? await callDaemon("shopping.run", payload, { timeoutMs: parsed.timeoutMs }) : await callDaemon("shopping.run", payload);
5919
+ return {
5920
+ success: true,
5921
+ message: "Shopping workflow completed.",
5922
+ data
5923
+ };
5924
+ }
5925
+
5926
+ // src/cli/commands/product-video.ts
5927
+ var requireValue11 = (rawArgs, index, flag) => {
5928
+ const value = rawArgs[index + 1];
5929
+ if (!value) {
5930
+ throw createUsageError(`Missing value for ${flag}`);
5931
+ }
5932
+ return value;
5933
+ };
5934
+ var parseBoolean3 = (value, flag) => {
5935
+ if (value === "true") return true;
5936
+ if (value === "false") return false;
5937
+ throw createUsageError(`Invalid ${flag}: ${value}`);
5938
+ };
5939
+ var COOKIE_POLICY_VALUES3 = /* @__PURE__ */ new Set(["off", "auto", "required"]);
5940
+ var parseProductVideoArgs = (rawArgs) => {
5941
+ const parsed = {};
5942
+ for (let index = 0; index < rawArgs.length; index += 1) {
5943
+ const arg = rawArgs[index];
5944
+ if (arg === "--product-url") {
5945
+ parsed.productUrl = requireValue11(rawArgs, index, "--product-url");
5946
+ index += 1;
5947
+ continue;
5948
+ }
5949
+ if (arg?.startsWith("--product-url=")) {
5950
+ parsed.productUrl = arg.split("=", 2)[1];
5951
+ continue;
5952
+ }
5953
+ if (arg === "--product-name") {
5954
+ parsed.productName = requireValue11(rawArgs, index, "--product-name");
5955
+ index += 1;
5956
+ continue;
5957
+ }
5958
+ if (arg?.startsWith("--product-name=")) {
5959
+ parsed.productName = arg.split("=", 2)[1];
5960
+ continue;
5961
+ }
5962
+ if (arg === "--provider-hint") {
5963
+ parsed.providerHint = requireValue11(rawArgs, index, "--provider-hint");
5964
+ index += 1;
5965
+ continue;
5966
+ }
5967
+ if (arg?.startsWith("--provider-hint=")) {
5968
+ parsed.providerHint = arg.split("=", 2)[1];
5969
+ continue;
5970
+ }
5971
+ if (arg === "--include-screenshots") {
5972
+ parsed.includeScreenshots = true;
5973
+ continue;
5974
+ }
5975
+ if (arg?.startsWith("--include-screenshots=")) {
5976
+ parsed.includeScreenshots = parseBoolean3(arg.split("=", 2)[1] ?? "", "--include-screenshots");
5977
+ continue;
5978
+ }
5979
+ if (arg === "--include-all-images") {
5980
+ parsed.includeAllImages = true;
5981
+ continue;
5982
+ }
5983
+ if (arg?.startsWith("--include-all-images=")) {
5984
+ parsed.includeAllImages = parseBoolean3(arg.split("=", 2)[1] ?? "", "--include-all-images");
5985
+ continue;
5986
+ }
5987
+ if (arg === "--include-copy") {
5988
+ parsed.includeCopy = true;
5989
+ continue;
5990
+ }
5991
+ if (arg?.startsWith("--include-copy=")) {
5992
+ parsed.includeCopy = parseBoolean3(arg.split("=", 2)[1] ?? "", "--include-copy");
5993
+ continue;
5994
+ }
5995
+ if (arg === "--output-dir") {
5996
+ parsed.outputDir = requireValue11(rawArgs, index, "--output-dir");
5997
+ index += 1;
5998
+ continue;
5999
+ }
6000
+ if (arg?.startsWith("--output-dir=")) {
6001
+ parsed.outputDir = arg.split("=", 2)[1];
6002
+ continue;
6003
+ }
6004
+ if (arg === "--ttl-hours") {
6005
+ parsed.ttlHours = parseNumberFlag(requireValue11(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
6006
+ index += 1;
6007
+ continue;
6008
+ }
6009
+ if (arg?.startsWith("--ttl-hours=")) {
6010
+ parsed.ttlHours = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--ttl-hours", { min: 1, max: 168 });
6011
+ continue;
6012
+ }
6013
+ if (arg === "--timeout-ms") {
6014
+ parsed.timeoutMs = parseNumberFlag(requireValue11(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
6015
+ index += 1;
6016
+ continue;
6017
+ }
6018
+ if (arg?.startsWith("--timeout-ms=")) {
6019
+ parsed.timeoutMs = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--timeout-ms", { min: 1 });
6020
+ continue;
6021
+ }
6022
+ if (arg === "--use-cookies") {
6023
+ parsed.useCookies = true;
6024
+ continue;
6025
+ }
6026
+ if (arg?.startsWith("--use-cookies=")) {
6027
+ parsed.useCookies = parseBoolean3(arg.split("=", 2)[1] ?? "", "--use-cookies");
6028
+ continue;
6029
+ }
6030
+ if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
6031
+ const value = requireValue11(rawArgs, index, arg).toLowerCase();
6032
+ if (!COOKIE_POLICY_VALUES3.has(value)) {
6033
+ throw createUsageError(`Invalid ${arg}: ${value}`);
6034
+ }
6035
+ parsed.cookiePolicyOverride = value;
6036
+ index += 1;
6037
+ continue;
6038
+ }
6039
+ if (arg?.startsWith("--cookie-policy-override=") || arg?.startsWith("--cookie-policy=")) {
6040
+ const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
6041
+ if (!COOKIE_POLICY_VALUES3.has(value)) {
6042
+ throw createUsageError(`Invalid --cookie-policy-override: ${value}`);
6043
+ }
6044
+ parsed.cookiePolicyOverride = value;
6045
+ continue;
6046
+ }
6047
+ }
6048
+ return parsed;
6049
+ };
6050
+ async function runProductVideoCommand(args) {
6051
+ const [subcommand, ...rest] = args.rawArgs;
6052
+ if (subcommand !== "run") {
6053
+ throw createUsageError("Usage: opendevbrowser product-video run --product-url <url> | --product-name <name>");
6054
+ }
6055
+ const parsed = parseProductVideoArgs(rest);
6056
+ if (!parsed.productUrl && !parsed.productName) {
6057
+ throw createUsageError("Missing --product-url or --product-name");
6058
+ }
6059
+ const timeoutMs = parsed.timeoutMs ?? 12e4;
6060
+ const data = await callDaemon("product.video.run", {
6061
+ product_url: parsed.productUrl,
6062
+ product_name: parsed.productName,
6063
+ provider_hint: parsed.providerHint,
6064
+ include_screenshots: parsed.includeScreenshots,
6065
+ include_all_images: parsed.includeAllImages,
6066
+ include_copy: parsed.includeCopy,
6067
+ output_dir: parsed.outputDir,
6068
+ ttl_hours: parsed.ttlHours,
6069
+ useCookies: parsed.useCookies,
6070
+ cookiePolicyOverride: parsed.cookiePolicyOverride
6071
+ }, { timeoutMs });
6072
+ return {
6073
+ success: true,
6074
+ message: "Product video asset workflow completed.",
6075
+ data
6076
+ };
6077
+ }
6078
+
6079
+ // package.json
6080
+ var package_default = {
6081
+ name: "opendevbrowser",
6082
+ version: "0.0.17",
6083
+ description: "OpenCode plugin for browser automation via CDP with snapshot-refs-actions workflow",
6084
+ type: "module",
6085
+ main: "dist/index.js",
6086
+ types: "dist/index.d.ts",
6087
+ bin: {
6088
+ opendevbrowser: "dist/cli/index.js"
6089
+ },
6090
+ files: [
6091
+ "dist",
6092
+ "skills",
6093
+ "scripts/native",
6094
+ "extension/canvas.html",
6095
+ "extension/manifest.json",
6096
+ "extension/popup.html",
6097
+ "extension/dist",
6098
+ "extension/icons"
6099
+ ],
6100
+ keywords: [
6101
+ "opencode",
6102
+ "plugin",
6103
+ "browser",
6104
+ "automation",
6105
+ "cdp",
6106
+ "playwright",
6107
+ "testing",
6108
+ "web-scraping",
6109
+ "chrome"
6110
+ ],
6111
+ license: "MIT",
6112
+ repository: {
6113
+ type: "git",
6114
+ url: "git+https://github.com/freshtechbro/opendevbrowser.git"
6115
+ },
6116
+ engines: {
6117
+ node: ">=18"
6118
+ },
6119
+ scripts: {
6120
+ build: `tsup src/index.ts src/cli/index.ts --format esm --clean --sourcemap && tsc --emitDeclarationOnly --declaration --declarationMap -p tsconfig.json && node --input-type=module -e "import { copyFileSync, existsSync } from 'node:fs';
6121
+ import { resolve } from 'node:path';
6122
+ const dist = resolve('dist');
6123
+ const pairs = [
6124
+ ['index.js', 'opendevbrowser.js'],
6125
+ ['index.js.map', 'opendevbrowser.js.map'],
6126
+ ['index.d.ts', 'opendevbrowser.d.ts'],
6127
+ ['index.d.ts.map', 'opendevbrowser.d.ts.map'],
6128
+ ];
6129
+ for (const [src, dst] of pairs) {
6130
+ const from = resolve(dist, src);
6131
+ const to = resolve(dist, dst);
6132
+ if (existsSync(from)) copyFileSync(from, to);
6133
+ }"`,
6134
+ dev: "tsup src/index.ts src/cli/index.ts --format esm --dts --watch",
6135
+ lint: 'eslint "src/**/*.ts" "tests/**/*.ts"',
6136
+ typecheck: "tsc --noEmit -p tsconfig.json",
6137
+ test: `node --input-type=module -e "import { mkdirSync } from 'node:fs'; mkdirSync('coverage/.tmp', { recursive: true });" && vitest run --coverage`,
6138
+ "test:release-gate": "node scripts/release-gate-test-groups.mjs",
6139
+ "test:release-gate:g1": "node scripts/release-gate-test-groups.mjs --group 1",
6140
+ "test:release-gate:g2": "node scripts/release-gate-test-groups.mjs --group 2",
6141
+ "test:release-gate:g3": "node scripts/release-gate-test-groups.mjs --group 3",
6142
+ "test:release-gate:g4": "node scripts/release-gate-test-groups.mjs --group 4",
6143
+ "test:release-gate:g5": "node scripts/release-gate-test-groups.mjs --group 5",
6144
+ "extension:sync": "node scripts/sync-extension-version.mjs",
6145
+ "extension:build": "npm run extension:sync && tsc -p extension/tsconfig.json && node scripts/copy-extension-assets.mjs",
6146
+ "extension:pack": "cd extension && zip -r ../opendevbrowser-extension.zip manifest.json popup.html canvas.html dist/ icons/",
6147
+ "extension:store": "node scripts/chrome-store-publish.mjs",
6148
+ "version:check": "node scripts/verify-versions.mjs",
6149
+ prepack: "npm run version:check && npm run build && npm run extension:build"
6150
+ },
6151
+ dependencies: {
6152
+ "@opencode-ai/plugin": "^1.2.11",
6153
+ "@puppeteer/browsers": "^2.13.0",
6154
+ "async-mutex": "^0.5.0",
6155
+ "jsonc-parser": "^3.2.0",
6156
+ "playwright-core": "^1.58.2",
6157
+ typescript: "^5.9.3",
6158
+ ws: "^8.19.0",
6159
+ yjs: "^13.6.29",
6160
+ zod: "^3.25.76"
6161
+ },
6162
+ devDependencies: {
6163
+ "@types/chrome": "^0.1.37",
6164
+ "@types/node": "^20.19.35",
6165
+ "@types/ws": "^8.18.1",
6166
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
6167
+ "@typescript-eslint/parser": "^8.56.1",
6168
+ "@vitest/coverage-v8": "^4.0.18",
6169
+ eslint: "^9.39.3",
6170
+ "happy-dom": "^20.7.0",
6171
+ tsup: "^8.5.1",
6172
+ vitest: "^4.0.18"
6173
+ }
6174
+ };
6175
+
3727
6176
  // src/cli/index.ts
3728
- var VERSION = "0.1.0";
6177
+ var VERSION = typeof package_default.version === "string" ? package_default.version : "0.0.0";
3729
6178
  async function promptInstallMode() {
3730
6179
  if (!process.stdin.isTTY) {
3731
6180
  console.log("Non-interactive mode detected. Using global install.");
3732
6181
  return "global";
3733
6182
  }
3734
- return new Promise((resolve4) => {
6183
+ return new Promise((resolve6) => {
3735
6184
  console.log("\nWhere would you like to install opendevbrowser?\n");
3736
6185
  console.log(" 1. Global (~/.config/opencode/opencode.json)");
3737
6186
  console.log(" 2. Local (./opencode.json in this project)\n");
@@ -3751,23 +6200,23 @@ async function promptInstallMode() {
3751
6200
  resolved = true;
3752
6201
  const input = data.toString().trim();
3753
6202
  if (input === "2") {
3754
- resolve4("local");
6203
+ resolve6("local");
3755
6204
  } else {
3756
- resolve4("global");
6205
+ resolve6("global");
3757
6206
  }
3758
6207
  });
3759
6208
  process.stdin.once("close", () => {
3760
6209
  cleanup();
3761
6210
  if (resolved) return;
3762
6211
  resolved = true;
3763
- resolve4("global");
6212
+ resolve6("global");
3764
6213
  });
3765
6214
  timeoutId = setTimeout(() => {
3766
6215
  timeoutId = null;
3767
6216
  if (resolved) return;
3768
6217
  resolved = true;
3769
6218
  console.log("\nTimeout - using global install.");
3770
- resolve4("global");
6219
+ resolve6("global");
3771
6220
  }, 3e4);
3772
6221
  });
3773
6222
  }
@@ -3787,7 +6236,7 @@ async function promptUninstallMode() {
3787
6236
  console.log("Plugin found in both global and local configs. Use --global or --local flag.");
3788
6237
  return null;
3789
6238
  }
3790
- return new Promise((resolve4) => {
6239
+ return new Promise((resolve6) => {
3791
6240
  console.log("\nopendevbrowser is installed in multiple locations:\n");
3792
6241
  console.log(" 1. Global (~/.config/opencode/opencode.json)");
3793
6242
  console.log(" 2. Local (./opencode.json)");
@@ -3797,15 +6246,15 @@ async function promptUninstallMode() {
3797
6246
  process.stdin.once("data", (data) => {
3798
6247
  const input = data.toString().trim();
3799
6248
  if (input === "1") {
3800
- resolve4("global");
6249
+ resolve6("global");
3801
6250
  } else if (input === "2") {
3802
- resolve4("local");
6251
+ resolve6("local");
3803
6252
  } else {
3804
- resolve4(null);
6253
+ resolve6(null);
3805
6254
  }
3806
6255
  });
3807
6256
  process.stdin.once("close", () => {
3808
- resolve4(null);
6257
+ resolve6(null);
3809
6258
  });
3810
6259
  });
3811
6260
  }
@@ -4043,9 +6492,19 @@ async function main() {
4043
6492
  });
4044
6493
  registerCommand({
4045
6494
  name: "annotate",
4046
- description: "Request interactive annotations (extension relay)",
6495
+ description: "Request interactive annotations via direct or relay transport",
4047
6496
  run: async () => runAnnotate(args)
4048
6497
  });
6498
+ registerCommand({
6499
+ name: "canvas",
6500
+ description: "Execute a design-canvas command",
6501
+ run: async () => runCanvas(args)
6502
+ });
6503
+ registerCommand({
6504
+ name: "rpc",
6505
+ description: "Execute an internal daemon RPC command (power-user)",
6506
+ run: async () => runRpc(args)
6507
+ });
4049
6508
  registerCommand({
4050
6509
  name: "click",
4051
6510
  description: "Click an element by ref",
@@ -4191,6 +6650,46 @@ async function main() {
4191
6650
  description: "Poll network events",
4192
6651
  run: async () => runNetworkPoll(args)
4193
6652
  });
6653
+ registerCommand({
6654
+ name: "debug-trace-snapshot",
6655
+ description: "Capture page + console + network + exception diagnostics",
6656
+ run: async () => runDebugTraceSnapshot(args)
6657
+ });
6658
+ registerCommand({
6659
+ name: "cookie-import",
6660
+ description: "Import validated cookies into a session",
6661
+ run: async () => runCookieImport(args)
6662
+ });
6663
+ registerCommand({
6664
+ name: "cookie-list",
6665
+ description: "List cookies for a session (optionally filtered by URL)",
6666
+ run: async () => runCookieList(args)
6667
+ });
6668
+ registerCommand({
6669
+ name: "macro-resolve",
6670
+ description: "Resolve or execute a macro expression via provider actions",
6671
+ run: async () => runMacroResolve(args)
6672
+ });
6673
+ registerCommand({
6674
+ name: "research",
6675
+ description: "Run research workflows",
6676
+ run: async () => runResearchCommand(args)
6677
+ });
6678
+ registerCommand({
6679
+ name: "shopping",
6680
+ description: "Run shopping workflows",
6681
+ run: async () => runShoppingCommand(args)
6682
+ });
6683
+ registerCommand({
6684
+ name: "product-video",
6685
+ description: "Run product presentation asset workflows",
6686
+ run: async () => runProductVideoCommand(args)
6687
+ });
6688
+ registerCommand({
6689
+ name: "artifacts",
6690
+ description: "Manage workflow artifact lifecycle",
6691
+ run: async () => runArtifactsCommand(args)
6692
+ });
4194
6693
  const command = getCommand(args.command);
4195
6694
  if (!command) {
4196
6695
  throw new Error(`Unknown command: ${args.command}`);