opendevbrowser 0.0.28 → 0.0.30

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 (325) hide show
  1. package/README.md +2 -2
  2. package/dist/accessibility-snapshot-CQ4ZKWKC.js +39 -0
  3. package/dist/accessibility-snapshot-CQ4ZKWKC.js.map +1 -0
  4. package/dist/active-window-TD5HYJ72.js +37 -0
  5. package/dist/active-window-TD5HYJ72.js.map +1 -0
  6. package/dist/annotate-VTLFS2XV.js +205 -0
  7. package/dist/annotate-VTLFS2XV.js.map +1 -0
  8. package/dist/artifacts-KJ6RNDO2.js +120 -0
  9. package/dist/artifacts-KJ6RNDO2.js.map +1 -0
  10. package/dist/attr-BCI5KYCW.js +84 -0
  11. package/dist/attr-BCI5KYCW.js.map +1 -0
  12. package/dist/browser/ops-client.d.ts +1 -0
  13. package/dist/browser/ops-client.d.ts.map +1 -1
  14. package/dist/canvas-5DFEEOKM.js +309 -0
  15. package/dist/canvas-5DFEEOKM.js.map +1 -0
  16. package/dist/capture-desktop-HFTTWY4Z.js +38 -0
  17. package/dist/capture-desktop-HFTTWY4Z.js.map +1 -0
  18. package/dist/capture-window-X63XPIFF.js +40 -0
  19. package/dist/capture-window-X63XPIFF.js.map +1 -0
  20. package/dist/check-LWAUY7GC.js +71 -0
  21. package/dist/check-LWAUY7GC.js.map +1 -0
  22. package/dist/checked-ZSOUKVYT.js +71 -0
  23. package/dist/checked-ZSOUKVYT.js.map +1 -0
  24. package/dist/chunk-2SIMIPLY.js +67 -0
  25. package/dist/chunk-2SIMIPLY.js.map +1 -0
  26. package/dist/chunk-37VSRUW4.js +141 -0
  27. package/dist/chunk-37VSRUW4.js.map +1 -0
  28. package/dist/{chunk-T3VVHJTK.js → chunk-4BEJVZRK.js} +1078 -1458
  29. package/dist/chunk-4BEJVZRK.js.map +1 -0
  30. package/dist/chunk-5SWZDVOW.js +144 -0
  31. package/dist/chunk-5SWZDVOW.js.map +1 -0
  32. package/dist/chunk-6PVZ2ABC.js +429 -0
  33. package/dist/chunk-6PVZ2ABC.js.map +1 -0
  34. package/dist/chunk-7GVOUZMQ.js +64 -0
  35. package/dist/chunk-7GVOUZMQ.js.map +1 -0
  36. package/dist/chunk-7THCPS52.js +84 -0
  37. package/dist/chunk-7THCPS52.js.map +1 -0
  38. package/dist/chunk-AHEWXOKY.js +64 -0
  39. package/dist/chunk-AHEWXOKY.js.map +1 -0
  40. package/dist/chunk-ASMHEEKY.js +10 -0
  41. package/dist/chunk-ASMHEEKY.js.map +1 -0
  42. package/dist/chunk-COAOWH3G.js +3651 -0
  43. package/dist/chunk-COAOWH3G.js.map +1 -0
  44. package/dist/chunk-DBF5OKH3.js +111 -0
  45. package/dist/chunk-DBF5OKH3.js.map +1 -0
  46. package/dist/chunk-DW4TX7MU.js +54 -0
  47. package/dist/chunk-DW4TX7MU.js.map +1 -0
  48. package/dist/chunk-GQJ5S3BL.js +20 -0
  49. package/dist/chunk-GQJ5S3BL.js.map +1 -0
  50. package/dist/chunk-IPE7TF2P.js +54 -0
  51. package/dist/chunk-IPE7TF2P.js.map +1 -0
  52. package/dist/chunk-IQTJHXZJ.js +126 -0
  53. package/dist/chunk-IQTJHXZJ.js.map +1 -0
  54. package/dist/chunk-J47N77VG.js +2969 -0
  55. package/dist/chunk-J47N77VG.js.map +1 -0
  56. package/dist/chunk-JZXD6FWR.js +25 -0
  57. package/dist/chunk-JZXD6FWR.js.map +1 -0
  58. package/dist/{chunk-QVWOPIZJ.js → chunk-KDSNXS6N.js} +75 -149
  59. package/dist/chunk-KDSNXS6N.js.map +1 -0
  60. package/dist/chunk-KZ2IXVQT.js +219 -0
  61. package/dist/chunk-KZ2IXVQT.js.map +1 -0
  62. package/dist/chunk-MD655IPO.js +838 -0
  63. package/dist/chunk-MD655IPO.js.map +1 -0
  64. package/dist/chunk-MX3NFLCE.js +940 -0
  65. package/dist/chunk-MX3NFLCE.js.map +1 -0
  66. package/dist/chunk-OW5HMYMI.js +19 -0
  67. package/dist/chunk-OW5HMYMI.js.map +1 -0
  68. package/dist/chunk-PPUWQKIC.js +26 -0
  69. package/dist/chunk-PPUWQKIC.js.map +1 -0
  70. package/dist/{chunk-I5ZCOZZV.js → chunk-QOMWCRE3.js} +1202 -9561
  71. package/dist/chunk-QOMWCRE3.js.map +1 -0
  72. package/dist/chunk-RCZZGGJS.js +226 -0
  73. package/dist/chunk-RCZZGGJS.js.map +1 -0
  74. package/dist/chunk-RJNI3BHT.js +1 -0
  75. package/dist/chunk-RPXWUCQQ.js +112 -0
  76. package/dist/chunk-RPXWUCQQ.js.map +1 -0
  77. package/dist/chunk-S5KZQJJI.js +107 -0
  78. package/dist/chunk-S5KZQJJI.js.map +1 -0
  79. package/dist/chunk-T4GMCW6Z.js +46 -0
  80. package/dist/chunk-T4GMCW6Z.js.map +1 -0
  81. package/dist/chunk-WHQZBUNY.js +982 -0
  82. package/dist/chunk-WHQZBUNY.js.map +1 -0
  83. package/dist/chunk-WOXBLP7V.js +610 -0
  84. package/dist/chunk-WOXBLP7V.js.map +1 -0
  85. package/dist/cli/commands/inspiredesign.d.ts.map +1 -1
  86. package/dist/cli/commands/macro-resolve.d.ts +4 -1
  87. package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
  88. package/dist/cli/commands/product-video.d.ts.map +1 -1
  89. package/dist/cli/commands/research.d.ts.map +1 -1
  90. package/dist/cli/commands/serve.d.ts.map +1 -1
  91. package/dist/cli/commands/shopping.d.ts.map +1 -1
  92. package/dist/cli/commands/workflow-output.d.ts +2 -0
  93. package/dist/cli/commands/workflow-output.d.ts.map +1 -0
  94. package/dist/cli/daemon-commands.d.ts.map +1 -1
  95. package/dist/cli/daemon.d.ts.map +1 -1
  96. package/dist/cli/index.js +204 -8123
  97. package/dist/cli/index.js.map +1 -1
  98. package/dist/cli/installers/postinstall-skill-sync.js +2 -1
  99. package/dist/cli/installers/postinstall-skill-sync.js.map +1 -1
  100. package/dist/cli/remote-relay.d.ts.map +1 -1
  101. package/dist/click-2AILSEIZ.js +81 -0
  102. package/dist/click-2AILSEIZ.js.map +1 -0
  103. package/dist/clone-component-TPJS3PEG.js +82 -0
  104. package/dist/clone-component-TPJS3PEG.js.map +1 -0
  105. package/dist/clone-page-LE74CIFC.js +69 -0
  106. package/dist/clone-page-LE74CIFC.js.map +1 -0
  107. package/dist/close-HN4YI47K.js +63 -0
  108. package/dist/close-HN4YI47K.js.map +1 -0
  109. package/dist/close-WFERRHX6.js +63 -0
  110. package/dist/close-WFERRHX6.js.map +1 -0
  111. package/dist/connect-RWBV2UCQ.js +107 -0
  112. package/dist/connect-RWBV2UCQ.js.map +1 -0
  113. package/dist/console-poll-PP4YYPDF.js +76 -0
  114. package/dist/console-poll-PP4YYPDF.js.map +1 -0
  115. package/dist/cookie-import-6IP776FC.js +177 -0
  116. package/dist/cookie-import-6IP776FC.js.map +1 -0
  117. package/dist/cookie-list-O2KG6DPU.js +117 -0
  118. package/dist/cookie-list-O2KG6DPU.js.map +1 -0
  119. package/dist/daemon-2BSAZXLT.js +194 -0
  120. package/dist/daemon-2BSAZXLT.js.map +1 -0
  121. package/dist/daemon-fingerprint.json +1 -1
  122. package/dist/debug-trace-snapshot-F3BDVZXS.js +136 -0
  123. package/dist/debug-trace-snapshot-F3BDVZXS.js.map +1 -0
  124. package/dist/dialog-6JQYUWMQ.js +75 -0
  125. package/dist/dialog-6JQYUWMQ.js.map +1 -0
  126. package/dist/disconnect-763TP7GH.js +58 -0
  127. package/dist/disconnect-763TP7GH.js.map +1 -0
  128. package/dist/enabled-DLYQFNIP.js +71 -0
  129. package/dist/enabled-DLYQFNIP.js.map +1 -0
  130. package/dist/extension-extractor-GKWSFHPN.js +11 -0
  131. package/dist/extension-extractor-GKWSFHPN.js.map +1 -0
  132. package/dist/global-D6WLWBXA.js +56 -0
  133. package/dist/global-D6WLWBXA.js.map +1 -0
  134. package/dist/goto-S346TJJH.js +98 -0
  135. package/dist/goto-S346TJJH.js.map +1 -0
  136. package/dist/help-EKKKEDL5.js +491 -0
  137. package/dist/help-EKKKEDL5.js.map +1 -0
  138. package/dist/hover-6JVJFGO7.js +71 -0
  139. package/dist/hover-6JVJFGO7.js.map +1 -0
  140. package/dist/html-EVOSPBIT.js +84 -0
  141. package/dist/html-EVOSPBIT.js.map +1 -0
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +87 -38
  144. package/dist/index.js.map +1 -1
  145. package/dist/inspector-H57BVUJP.js +62 -0
  146. package/dist/inspector-H57BVUJP.js.map +1 -0
  147. package/dist/inspector-audit-NQBAJWC7.js +84 -0
  148. package/dist/inspector-audit-NQBAJWC7.js.map +1 -0
  149. package/dist/inspector-plan-ZDIQVND3.js +69 -0
  150. package/dist/inspector-plan-ZDIQVND3.js.map +1 -0
  151. package/dist/inspiredesign-IEUL4PX3.js +234 -0
  152. package/dist/inspiredesign-IEUL4PX3.js.map +1 -0
  153. package/dist/install-autostart-output-5DOMKCQL.js +41 -0
  154. package/dist/install-autostart-output-5DOMKCQL.js.map +1 -0
  155. package/dist/install-autostart-reconciliation-NHKOFYTD.js +73 -0
  156. package/dist/install-autostart-reconciliation-NHKOFYTD.js.map +1 -0
  157. package/dist/launch-EK66VQPF.js +225 -0
  158. package/dist/launch-EK66VQPF.js.map +1 -0
  159. package/dist/list-ADZAQ2IU.js +51 -0
  160. package/dist/list-ADZAQ2IU.js.map +1 -0
  161. package/dist/list-KKUKN467.js +54 -0
  162. package/dist/list-KKUKN467.js.map +1 -0
  163. package/dist/local-HXJLUUNT.js +54 -0
  164. package/dist/local-HXJLUUNT.js.map +1 -0
  165. package/dist/macro-resolve-6DOQJ7CA.js +253 -0
  166. package/dist/macro-resolve-6DOQJ7CA.js.map +1 -0
  167. package/dist/macros/execute-runtime.d.ts +3 -1
  168. package/dist/macros/execute-runtime.d.ts.map +1 -1
  169. package/dist/macros/execute.d.ts +2 -0
  170. package/dist/macros/execute.d.ts.map +1 -1
  171. package/dist/native-UPLVQ2SG.js +22 -0
  172. package/dist/native-UPLVQ2SG.js.map +1 -0
  173. package/dist/network-poll-NUL4PDPY.js +76 -0
  174. package/dist/network-poll-NUL4PDPY.js.map +1 -0
  175. package/dist/new-5NKYPEFT.js +69 -0
  176. package/dist/new-5NKYPEFT.js.map +1 -0
  177. package/dist/onboarding-metadata-7E3KLYSZ.js +27 -0
  178. package/dist/onboarding-metadata-7E3KLYSZ.js.map +1 -0
  179. package/dist/open-NR3BPLXV.js +81 -0
  180. package/dist/open-NR3BPLXV.js.map +1 -0
  181. package/dist/opendevbrowser.d.ts.map +1 -1
  182. package/dist/opendevbrowser.js +87 -38
  183. package/dist/opendevbrowser.js.map +1 -1
  184. package/dist/perf-HJ36ZI6H.js +58 -0
  185. package/dist/perf-HJ36ZI6H.js.map +1 -0
  186. package/dist/pointer-down-IYTTQWXZ.js +55 -0
  187. package/dist/pointer-down-IYTTQWXZ.js.map +1 -0
  188. package/dist/pointer-drag-A2YC5PWI.js +54 -0
  189. package/dist/pointer-drag-A2YC5PWI.js.map +1 -0
  190. package/dist/pointer-move-W5K5FUI4.js +52 -0
  191. package/dist/pointer-move-W5K5FUI4.js.map +1 -0
  192. package/dist/pointer-up-6GWVO64Y.js +55 -0
  193. package/dist/pointer-up-6GWVO64Y.js.map +1 -0
  194. package/dist/press-A3V5WB3S.js +83 -0
  195. package/dist/press-A3V5WB3S.js.map +1 -0
  196. package/dist/product-video-52REKWF3.js +235 -0
  197. package/dist/product-video-52REKWF3.js.map +1 -0
  198. package/dist/providers/artifacts.d.ts +0 -2
  199. package/dist/providers/artifacts.d.ts.map +1 -1
  200. package/dist/providers/blocker.d.ts.map +1 -1
  201. package/dist/providers/bounded-map.d.ts +2 -0
  202. package/dist/providers/bounded-map.d.ts.map +1 -0
  203. package/dist/providers/community/index.d.ts.map +1 -1
  204. package/dist/providers/constraint.d.ts.map +1 -1
  205. package/dist/providers/index.d.ts +1 -0
  206. package/dist/providers/index.d.ts.map +1 -1
  207. package/dist/providers/renderer.d.ts.map +1 -1
  208. package/dist/providers/research-compiler.d.ts +1 -1
  209. package/dist/providers/research-compiler.d.ts.map +1 -1
  210. package/dist/providers/research-executor.d.ts.map +1 -1
  211. package/dist/providers/runtime-factory.d.ts.map +1 -1
  212. package/dist/providers/shared/traversal-url.d.ts +3 -0
  213. package/dist/providers/shared/traversal-url.d.ts.map +1 -1
  214. package/dist/providers/shopping/index.d.ts.map +1 -1
  215. package/dist/providers/social/search-quality.d.ts.map +1 -1
  216. package/dist/providers/workflow-handoff.d.ts +4 -0
  217. package/dist/providers/workflow-handoff.d.ts.map +1 -1
  218. package/dist/providers/workflow-output-root.d.ts +6 -0
  219. package/dist/providers/workflow-output-root.d.ts.map +1 -0
  220. package/dist/providers/workflows.d.ts.map +1 -1
  221. package/dist/{providers-QF2RFB4J.js → providers-IMFYMMHQ.js} +19 -14
  222. package/dist/providers-IMFYMMHQ.js.map +1 -0
  223. package/dist/public-surface/generated-manifest.d.ts +2 -2
  224. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  225. package/dist/public-surface/source.d.ts +2 -2
  226. package/dist/public-surface/source.d.ts.map +1 -1
  227. package/dist/relay/protocol.d.ts +3 -1
  228. package/dist/relay/protocol.d.ts.map +1 -1
  229. package/dist/relay/relay-server.d.ts +6 -0
  230. package/dist/relay/relay-server.d.ts.map +1 -1
  231. package/dist/research-WB6BBCDD.js +295 -0
  232. package/dist/research-WB6BBCDD.js.map +1 -0
  233. package/dist/review-BGWVY4RA.js +48 -0
  234. package/dist/review-BGWVY4RA.js.map +1 -0
  235. package/dist/review-desktop-LEORC5VS.js +54 -0
  236. package/dist/review-desktop-LEORC5VS.js.map +1 -0
  237. package/dist/rpc-4TSKSFGC.js +159 -0
  238. package/dist/rpc-4TSKSFGC.js.map +1 -0
  239. package/dist/run-3NBLVWXD.js +180 -0
  240. package/dist/run-3NBLVWXD.js.map +1 -0
  241. package/dist/screencast-start-UZVIT3IN.js +67 -0
  242. package/dist/screencast-start-UZVIT3IN.js.map +1 -0
  243. package/dist/screencast-stop-NOSJSIUO.js +59 -0
  244. package/dist/screencast-stop-NOSJSIUO.js.map +1 -0
  245. package/dist/screenshot-LARG4JQG.js +68 -0
  246. package/dist/screenshot-LARG4JQG.js.map +1 -0
  247. package/dist/scroll-VNFMV6TW.js +84 -0
  248. package/dist/scroll-VNFMV6TW.js.map +1 -0
  249. package/dist/scroll-into-view-VYRT3JPT.js +71 -0
  250. package/dist/scroll-into-view-VYRT3JPT.js.map +1 -0
  251. package/dist/select-KJTUZDVO.js +86 -0
  252. package/dist/select-KJTUZDVO.js.map +1 -0
  253. package/dist/serve-EV7K4HKR.js +498 -0
  254. package/dist/serve-EV7K4HKR.js.map +1 -0
  255. package/dist/shopping-DTXHVQ2X.js +273 -0
  256. package/dist/shopping-DTXHVQ2X.js.map +1 -0
  257. package/dist/skill-lifecycle-5UAZGKSN.js +89 -0
  258. package/dist/skill-lifecycle-5UAZGKSN.js.map +1 -0
  259. package/dist/skills-NSXDX6YM.js +26 -0
  260. package/dist/skills-NSXDX6YM.js.map +1 -0
  261. package/dist/snapshot-3XQMCMRJ.js +113 -0
  262. package/dist/snapshot-3XQMCMRJ.js.map +1 -0
  263. package/dist/status-OXSYA5XD.js +35 -0
  264. package/dist/status-OXSYA5XD.js.map +1 -0
  265. package/dist/status-YUMDP5KY.js +132 -0
  266. package/dist/status-YUMDP5KY.js.map +1 -0
  267. package/dist/status-capabilities-P4KDSE2Y.js +57 -0
  268. package/dist/status-capabilities-P4KDSE2Y.js.map +1 -0
  269. package/dist/text-V3B7UVIH.js +84 -0
  270. package/dist/text-V3B7UVIH.js.map +1 -0
  271. package/dist/tools/deps.d.ts +1 -0
  272. package/dist/tools/deps.d.ts.map +1 -1
  273. package/dist/tools/inspiredesign_run.d.ts.map +1 -1
  274. package/dist/tools/macro_resolve.d.ts.map +1 -1
  275. package/dist/tools/product_video_run.d.ts.map +1 -1
  276. package/dist/tools/research_run.d.ts.map +1 -1
  277. package/dist/tools/shopping_run.d.ts.map +1 -1
  278. package/dist/tools/workflow-output.d.ts +3 -0
  279. package/dist/tools/workflow-output.d.ts.map +1 -0
  280. package/dist/type-IYBN3ZLR.js +94 -0
  281. package/dist/type-IYBN3ZLR.js.map +1 -0
  282. package/dist/uncheck-SG737EGI.js +71 -0
  283. package/dist/uncheck-SG737EGI.js.map +1 -0
  284. package/dist/uninstall-KYKGJAX7.js +91 -0
  285. package/dist/uninstall-KYKGJAX7.js.map +1 -0
  286. package/dist/update-SMXPYGXS.js +305 -0
  287. package/dist/update-SMXPYGXS.js.map +1 -0
  288. package/dist/update-skill-modes-BVX7IVMW.js +38 -0
  289. package/dist/update-skill-modes-BVX7IVMW.js.map +1 -0
  290. package/dist/upload-KH6ZABJA.js +56 -0
  291. package/dist/upload-KH6ZABJA.js.map +1 -0
  292. package/dist/use-7YDKO3U4.js +63 -0
  293. package/dist/use-7YDKO3U4.js.map +1 -0
  294. package/dist/value-RZBWSKKM.js +71 -0
  295. package/dist/value-RZBWSKKM.js.map +1 -0
  296. package/dist/visible-BSFTAKXR.js +71 -0
  297. package/dist/visible-BSFTAKXR.js.map +1 -0
  298. package/dist/wait-TMTEAYOP.js +109 -0
  299. package/dist/wait-TMTEAYOP.js.map +1 -0
  300. package/dist/windows-HIZ23OHS.js +37 -0
  301. package/dist/windows-HIZ23OHS.js.map +1 -0
  302. package/extension/dist/background.js +99 -22
  303. package/extension/dist/ops/ops-runtime.js +85 -7
  304. package/extension/dist/ops/ops-session-store.js +3 -0
  305. package/extension/dist/ops/target-session-coordinator.js +3 -0
  306. package/extension/dist/services/CDPRouter.js +9 -0
  307. package/extension/manifest.json +1 -1
  308. package/package.json +1 -1
  309. package/skills/opendevbrowser-best-practices/SKILL.md +8 -6
  310. package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +1 -1
  311. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +3 -2
  312. package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +39 -2
  313. package/skills/opendevbrowser-research/SKILL.md +64 -12
  314. package/skills/opendevbrowser-research/artifacts/research-workflows.md +56 -19
  315. package/skills/opendevbrowser-research/assets/templates/compact.md +31 -5
  316. package/skills/opendevbrowser-research/assets/templates/context.json +52 -1
  317. package/skills/opendevbrowser-research/assets/templates/report.md +57 -4
  318. package/skills/opendevbrowser-research/examples/sample-input.json +1 -1
  319. package/skills/opendevbrowser-research/examples/sample-output.md +27 -2
  320. package/skills/opendevbrowser-research/scripts/run-research.sh +2 -6
  321. package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +115 -1
  322. package/dist/chunk-I5ZCOZZV.js.map +0 -1
  323. package/dist/chunk-QVWOPIZJ.js.map +0 -1
  324. package/dist/chunk-T3VVHJTK.js.map +0 -1
  325. /package/dist/{providers-QF2RFB4J.js.map → chunk-RJNI3BHT.js.map} +0 -0
@@ -0,0 +1,71 @@
1
+ import "./chunk-RJNI3BHT.js";
2
+ import {
3
+ parseOptionalStringFlag
4
+ } from "./chunk-RPXWUCQQ.js";
5
+ import {
6
+ callDaemon
7
+ } from "./chunk-MD655IPO.js";
8
+ import "./chunk-COAOWH3G.js";
9
+ import "./chunk-QOMWCRE3.js";
10
+ import "./chunk-MX3NFLCE.js";
11
+ import "./chunk-ASMHEEKY.js";
12
+ import {
13
+ createUsageError
14
+ } from "./chunk-IPE7TF2P.js";
15
+ import "./chunk-STGGGVYT.js";
16
+ import "./chunk-3ILXPKSJ.js";
17
+ import "./chunk-TBUCZX4A.js";
18
+ import "./chunk-Y2KL55OG.js";
19
+ import "./chunk-5SWZDVOW.js";
20
+ import "./chunk-4BEJVZRK.js";
21
+ import "./chunk-S5KZQJJI.js";
22
+ import "./chunk-KZ2IXVQT.js";
23
+ import "./chunk-WHQZBUNY.js";
24
+ import "./chunk-FUSXMW3G.js";
25
+
26
+ // src/cli/commands/dom/visible.ts
27
+ function parseDomVisibleArgs(rawArgs) {
28
+ const parsed = {};
29
+ for (let i = 0; i < rawArgs.length; i += 1) {
30
+ const arg = rawArgs[i];
31
+ if (arg === "--session-id") {
32
+ const value = rawArgs[i + 1];
33
+ if (!value) throw createUsageError("Missing value for --session-id");
34
+ parsed.sessionId = value;
35
+ i += 1;
36
+ continue;
37
+ }
38
+ if (arg?.startsWith("--session-id=")) {
39
+ parsed.sessionId = arg.split("=", 2)[1];
40
+ continue;
41
+ }
42
+ if (arg === "--ref") {
43
+ const value = rawArgs[i + 1];
44
+ if (!value) throw createUsageError("Missing value for --ref");
45
+ parsed.ref = value;
46
+ i += 1;
47
+ continue;
48
+ }
49
+ if (arg?.startsWith("--ref=")) {
50
+ parsed.ref = arg.split("=", 2)[1];
51
+ continue;
52
+ }
53
+ }
54
+ return parsed;
55
+ }
56
+ async function runDomVisible(args) {
57
+ const { sessionId, ref } = parseDomVisibleArgs(args.rawArgs);
58
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
59
+ if (!sessionId) throw createUsageError("Missing --session-id");
60
+ if (!ref) throw createUsageError("Missing --ref");
61
+ const result = await callDaemon("dom.isVisible", {
62
+ sessionId,
63
+ ref,
64
+ ...typeof targetId === "string" ? { targetId } : {}
65
+ });
66
+ return { success: true, message: "Visibility checked.", data: result };
67
+ }
68
+ export {
69
+ runDomVisible
70
+ };
71
+ //# sourceMappingURL=visible-BSFTAKXR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/dom/visible.ts"],"sourcesContent":["import type { ParsedArgs } from \"../../args\";\nimport { callDaemon } from \"../../client\";\nimport { createUsageError } from \"../../errors\";\nimport { parseOptionalStringFlag } from \"../../utils/parse\";\n\nfunction parseDomVisibleArgs(rawArgs: string[]): { sessionId?: string; ref?: string } {\n const parsed: { sessionId?: string; ref?: string } = {};\n for (let i = 0; i < rawArgs.length; i += 1) {\n const arg = rawArgs[i];\n if (arg === \"--session-id\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --session-id\");\n parsed.sessionId = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--session-id=\")) {\n parsed.sessionId = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--ref\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --ref\");\n parsed.ref = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--ref=\")) {\n parsed.ref = arg.split(\"=\", 2)[1];\n continue;\n }\n }\n return parsed;\n}\n\nexport async function runDomVisible(args: ParsedArgs) {\n const { sessionId, ref } = parseDomVisibleArgs(args.rawArgs);\n const targetId = parseOptionalStringFlag(args.rawArgs, \"--target-id\");\n if (!sessionId) throw createUsageError(\"Missing --session-id\");\n if (!ref) throw createUsageError(\"Missing --ref\");\n const result = await callDaemon(\"dom.isVisible\", {\n sessionId,\n ref,\n ...(typeof targetId === \"string\" ? { targetId } : {})\n });\n return { success: true, message: \"Visibility checked.\", data: result };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,SAAS,oBAAoB,SAAyD;AACpF,QAAM,SAA+C,CAAC;AACtD,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;AAC1C,UAAM,MAAM,QAAQ,CAAC;AACrB,QAAI,QAAQ,gBAAgB;AAC1B,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,gCAAgC;AACnE,aAAO,YAAY;AACnB,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,aAAO,YAAY,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AACtC;AAAA,IACF;AACA,QAAI,QAAQ,SAAS;AACnB,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,yBAAyB;AAC5D,aAAO,MAAM;AACb,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,aAAO,MAAM,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AAChC;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,cAAc,MAAkB;AACpD,QAAM,EAAE,WAAW,IAAI,IAAI,oBAAoB,KAAK,OAAO;AAC3D,QAAM,WAAW,wBAAwB,KAAK,SAAS,aAAa;AACpE,MAAI,CAAC,UAAW,OAAM,iBAAiB,sBAAsB;AAC7D,MAAI,CAAC,IAAK,OAAM,iBAAiB,eAAe;AAChD,QAAM,SAAS,MAAM,WAAW,iBAAiB;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,GAAI,OAAO,aAAa,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACrD,CAAC;AACD,SAAO,EAAE,SAAS,MAAM,SAAS,uBAAuB,MAAM,OAAO;AACvE;","names":[]}
@@ -0,0 +1,109 @@
1
+ import "./chunk-RJNI3BHT.js";
2
+ import {
3
+ parseNumberFlag,
4
+ parseOptionalStringFlag
5
+ } from "./chunk-RPXWUCQQ.js";
6
+ import {
7
+ callDaemon
8
+ } from "./chunk-MD655IPO.js";
9
+ import "./chunk-COAOWH3G.js";
10
+ import "./chunk-QOMWCRE3.js";
11
+ import "./chunk-MX3NFLCE.js";
12
+ import "./chunk-ASMHEEKY.js";
13
+ import {
14
+ createUsageError
15
+ } from "./chunk-IPE7TF2P.js";
16
+ import "./chunk-STGGGVYT.js";
17
+ import "./chunk-3ILXPKSJ.js";
18
+ import "./chunk-TBUCZX4A.js";
19
+ import "./chunk-Y2KL55OG.js";
20
+ import "./chunk-5SWZDVOW.js";
21
+ import "./chunk-4BEJVZRK.js";
22
+ import "./chunk-S5KZQJJI.js";
23
+ import "./chunk-KZ2IXVQT.js";
24
+ import "./chunk-WHQZBUNY.js";
25
+ import "./chunk-FUSXMW3G.js";
26
+
27
+ // src/cli/commands/nav/wait.ts
28
+ function parseWaitArgs(rawArgs) {
29
+ const parsed = {};
30
+ for (let i = 0; i < rawArgs.length; i += 1) {
31
+ const arg = rawArgs[i];
32
+ if (arg === "--session-id") {
33
+ const value = rawArgs[i + 1];
34
+ if (!value) throw createUsageError("Missing value for --session-id");
35
+ parsed.sessionId = value;
36
+ i += 1;
37
+ continue;
38
+ }
39
+ if (arg?.startsWith("--session-id=")) {
40
+ parsed.sessionId = arg.split("=", 2)[1];
41
+ continue;
42
+ }
43
+ if (arg === "--ref") {
44
+ const value = rawArgs[i + 1];
45
+ if (!value) throw createUsageError("Missing value for --ref");
46
+ parsed.ref = value;
47
+ i += 1;
48
+ continue;
49
+ }
50
+ if (arg?.startsWith("--ref=")) {
51
+ parsed.ref = arg.split("=", 2)[1];
52
+ continue;
53
+ }
54
+ if (arg === "--state") {
55
+ const value = rawArgs[i + 1];
56
+ if (!value) throw createUsageError("Missing value for --state");
57
+ parsed.state = value;
58
+ i += 1;
59
+ continue;
60
+ }
61
+ if (arg?.startsWith("--state=")) {
62
+ parsed.state = arg.split("=", 2)[1];
63
+ continue;
64
+ }
65
+ if (arg === "--until") {
66
+ const value = rawArgs[i + 1];
67
+ if (!value) throw createUsageError("Missing value for --until");
68
+ parsed.until = value;
69
+ i += 1;
70
+ continue;
71
+ }
72
+ if (arg?.startsWith("--until=")) {
73
+ parsed.until = arg.split("=", 2)[1];
74
+ continue;
75
+ }
76
+ if (arg === "--timeout-ms") {
77
+ const value = rawArgs[i + 1];
78
+ if (!value) throw createUsageError("Missing value for --timeout-ms");
79
+ parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
80
+ i += 1;
81
+ continue;
82
+ }
83
+ if (arg?.startsWith("--timeout-ms=")) {
84
+ const value = arg.split("=", 2)[1];
85
+ if (!value) throw createUsageError("Missing value for --timeout-ms");
86
+ parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
87
+ continue;
88
+ }
89
+ }
90
+ return parsed;
91
+ }
92
+ async function runWait(args) {
93
+ const { sessionId, ref, state, until, timeoutMs } = parseWaitArgs(args.rawArgs);
94
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
95
+ if (!sessionId) throw createUsageError("Missing --session-id");
96
+ const result = await callDaemon("nav.wait", {
97
+ sessionId,
98
+ ref,
99
+ state,
100
+ until,
101
+ timeoutMs,
102
+ ...typeof targetId === "string" ? { targetId } : {}
103
+ });
104
+ return { success: true, message: "Wait complete.", data: result };
105
+ }
106
+ export {
107
+ runWait
108
+ };
109
+ //# sourceMappingURL=wait-TMTEAYOP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/nav/wait.ts"],"sourcesContent":["import type { ParsedArgs } from \"../../args\";\nimport { callDaemon } from \"../../client\";\nimport { createUsageError } from \"../../errors\";\nimport { parseNumberFlag, parseOptionalStringFlag } from \"../../utils/parse\";\n\nfunction parseWaitArgs(rawArgs: string[]): { sessionId?: string; ref?: string; state?: string; until?: string; timeoutMs?: number } {\n const parsed: { sessionId?: string; ref?: string; state?: string; until?: string; timeoutMs?: number } = {};\n for (let i = 0; i < rawArgs.length; i += 1) {\n const arg = rawArgs[i];\n if (arg === \"--session-id\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --session-id\");\n parsed.sessionId = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--session-id=\")) {\n parsed.sessionId = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--ref\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --ref\");\n parsed.ref = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--ref=\")) {\n parsed.ref = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--state\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --state\");\n parsed.state = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--state=\")) {\n parsed.state = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--until\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --until\");\n parsed.until = value;\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--until=\")) {\n parsed.until = arg.split(\"=\", 2)[1];\n continue;\n }\n if (arg === \"--timeout-ms\") {\n const value = rawArgs[i + 1];\n if (!value) throw createUsageError(\"Missing value for --timeout-ms\");\n parsed.timeoutMs = parseNumberFlag(value, \"--timeout-ms\", { min: 1 });\n i += 1;\n continue;\n }\n if (arg?.startsWith(\"--timeout-ms=\")) {\n const value = arg.split(\"=\", 2)[1];\n if (!value) throw createUsageError(\"Missing value for --timeout-ms\");\n parsed.timeoutMs = parseNumberFlag(value, \"--timeout-ms\", { min: 1 });\n continue;\n }\n }\n return parsed;\n}\n\nexport async function runWait(args: ParsedArgs) {\n const { sessionId, ref, state, until, timeoutMs } = parseWaitArgs(args.rawArgs);\n const targetId = parseOptionalStringFlag(args.rawArgs, \"--target-id\");\n if (!sessionId) throw createUsageError(\"Missing --session-id\");\n const result = await callDaemon(\"nav.wait\", {\n sessionId,\n ref,\n state,\n until,\n timeoutMs,\n ...(typeof targetId === \"string\" ? { targetId } : {})\n });\n return { success: true, message: \"Wait complete.\", data: result };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,SAAS,cAAc,SAA6G;AAClI,QAAM,SAAmG,CAAC;AAC1G,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;AAC1C,UAAM,MAAM,QAAQ,CAAC;AACrB,QAAI,QAAQ,gBAAgB;AAC1B,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,gCAAgC;AACnE,aAAO,YAAY;AACnB,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,aAAO,YAAY,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AACtC;AAAA,IACF;AACA,QAAI,QAAQ,SAAS;AACnB,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,yBAAyB;AAC5D,aAAO,MAAM;AACb,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,aAAO,MAAM,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AAChC;AAAA,IACF;AACA,QAAI,QAAQ,WAAW;AACrB,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,2BAA2B;AAC9D,aAAO,QAAQ;AACf,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,UAAU,GAAG;AAC/B,aAAO,QAAQ,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AAClC;AAAA,IACF;AACA,QAAI,QAAQ,WAAW;AACrB,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,2BAA2B;AAC9D,aAAO,QAAQ;AACf,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,UAAU,GAAG;AAC/B,aAAO,QAAQ,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AAClC;AAAA,IACF;AACA,QAAI,QAAQ,gBAAgB;AAC1B,YAAM,QAAQ,QAAQ,IAAI,CAAC;AAC3B,UAAI,CAAC,MAAO,OAAM,iBAAiB,gCAAgC;AACnE,aAAO,YAAY,gBAAgB,OAAO,gBAAgB,EAAE,KAAK,EAAE,CAAC;AACpE,WAAK;AACL;AAAA,IACF;AACA,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,YAAM,QAAQ,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;AACjC,UAAI,CAAC,MAAO,OAAM,iBAAiB,gCAAgC;AACnE,aAAO,YAAY,gBAAgB,OAAO,gBAAgB,EAAE,KAAK,EAAE,CAAC;AACpE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,QAAQ,MAAkB;AAC9C,QAAM,EAAE,WAAW,KAAK,OAAO,OAAO,UAAU,IAAI,cAAc,KAAK,OAAO;AAC9E,QAAM,WAAW,wBAAwB,KAAK,SAAS,aAAa;AACpE,MAAI,CAAC,UAAW,OAAM,iBAAiB,sBAAsB;AAC7D,QAAM,SAAS,MAAM,WAAW,YAAY;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,OAAO,aAAa,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACrD,CAAC;AACD,SAAO,EAAE,SAAS,MAAM,SAAS,kBAAkB,MAAM,OAAO;AAClE;","names":[]}
@@ -0,0 +1,37 @@
1
+ import {
2
+ callDesktopCommand,
3
+ desktopCommandResult,
4
+ parseDesktopReasonArgs
5
+ } from "./chunk-AHEWXOKY.js";
6
+ import "./chunk-RJNI3BHT.js";
7
+ import "./chunk-RPXWUCQQ.js";
8
+ import "./chunk-OW5HMYMI.js";
9
+ import "./chunk-MD655IPO.js";
10
+ import "./chunk-COAOWH3G.js";
11
+ import "./chunk-QOMWCRE3.js";
12
+ import "./chunk-MX3NFLCE.js";
13
+ import "./chunk-ASMHEEKY.js";
14
+ import "./chunk-IPE7TF2P.js";
15
+ import "./chunk-STGGGVYT.js";
16
+ import "./chunk-3ILXPKSJ.js";
17
+ import "./chunk-TBUCZX4A.js";
18
+ import "./chunk-Y2KL55OG.js";
19
+ import "./chunk-5SWZDVOW.js";
20
+ import "./chunk-4BEJVZRK.js";
21
+ import "./chunk-S5KZQJJI.js";
22
+ import "./chunk-KZ2IXVQT.js";
23
+ import "./chunk-WHQZBUNY.js";
24
+ import "./chunk-FUSXMW3G.js";
25
+
26
+ // src/cli/commands/desktop/windows.ts
27
+ async function runDesktopWindows(args) {
28
+ const { reason, timeoutMs } = parseDesktopReasonArgs(args.rawArgs);
29
+ const result = await callDesktopCommand("desktop.windows.list", {
30
+ ...typeof reason === "string" ? { reason } : {}
31
+ }, timeoutMs);
32
+ return desktopCommandResult("Desktop windows listed.", result);
33
+ }
34
+ export {
35
+ runDesktopWindows
36
+ };
37
+ //# sourceMappingURL=windows-HIZ23OHS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/desktop/windows.ts"],"sourcesContent":["import type { ParsedArgs } from \"../../args\";\nimport { callDesktopCommand, desktopCommandResult, parseDesktopReasonArgs } from \"./shared\";\n\nexport async function runDesktopWindows(args: ParsedArgs) {\n const { reason, timeoutMs } = parseDesktopReasonArgs(args.rawArgs);\n const result = await callDesktopCommand(\"desktop.windows.list\", {\n ...(typeof reason === \"string\" ? { reason } : {})\n }, timeoutMs);\n return desktopCommandResult(\"Desktop windows listed.\", result);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,eAAsB,kBAAkB,MAAkB;AACxD,QAAM,EAAE,QAAQ,UAAU,IAAI,uBAAuB,KAAK,OAAO;AACjE,QAAM,SAAS,MAAM,mBAAmB,wBAAwB;AAAA,IAC9D,GAAI,OAAO,WAAW,WAAW,EAAE,OAAO,IAAI,CAAC;AAAA,EACjD,GAAG,SAAS;AACZ,SAAO,qBAAqB,2BAA2B,MAAM;AAC/D;","names":[]}
@@ -36,8 +36,11 @@ let retryScheduled = false;
36
36
  let retryDelayMs = 5000;
37
37
  let autoConnectEnabled = DEFAULT_AUTO_CONNECT;
38
38
  let nativeEnabled = DEFAULT_NATIVE_ENABLED;
39
+ let lastRelayCleanupStatus = null;
39
40
  const RETRY_ALARM_NAME = "opendevbrowser-auto-connect";
41
+ const WATCHDOG_ALARM_NAME = "opendevbrowser-auto-connect-watchdog";
40
42
  const RETRY_MAX_MS = 60_000;
43
+ const WATCHDOG_PERIOD_MINUTES = 1;
41
44
  const ANNOTATION_CONTENT_SCRIPT = "dist/annotate-content.js";
42
45
  const ANNOTATION_CONTENT_STYLE = "dist/annotate-content.css";
43
46
  const ANNOTATION_MAX_PAYLOAD_BYTES = 10 * 1024 * 1024;
@@ -92,21 +95,27 @@ const getEffectiveStatus = () => {
92
95
  return "disconnected";
93
96
  };
94
97
  const hasReadyRelayHandshake = (health) => {
95
- return health?.extensionConnected === true && health.extensionHandshakeComplete === true;
98
+ return health?.ok !== false && health?.extensionConnected === true && health.extensionHandshakeComplete === true;
96
99
  };
97
100
  const deriveBackgroundStatus = (relayStatus, nativeHealth, relayHealth, reconnectSuppressed) => {
98
101
  if (relayStatus === "connected") {
99
- return "connected";
100
- }
101
- if (nativeHealth?.status === "connected") {
102
+ if (relayHealth?.ok === false) {
103
+ return "disconnected";
104
+ }
102
105
  return "connected";
103
106
  }
104
107
  if (reconnectSuppressed) {
105
108
  return "disconnected";
106
109
  }
110
+ if (nativeHealth?.status === "connected") {
111
+ return "connected";
112
+ }
107
113
  return hasReadyRelayHandshake(relayHealth) ? "connected" : "disconnected";
108
114
  };
109
115
  const deriveBadgeTone = (status, relayHealth) => {
116
+ if (relayHealth?.ok === false) {
117
+ return status === "connected" ? "warning" : "disconnected";
118
+ }
110
119
  if (status === "connected") {
111
120
  return "connected";
112
121
  }
@@ -139,9 +148,9 @@ const buildStatusMessage = async () => {
139
148
  note = `Connected to 127.0.0.1:${identity.relayPort}`;
140
149
  }
141
150
  relayHealth = await connection.relayHealthCheck();
142
- }
143
- else if (nativeHealth?.status === "connected") {
144
- note = "Connected via native host.";
151
+ if (relayHealth?.ok === false) {
152
+ note = statusNoteOverride ?? buildRelayHealthNote(relayHealth);
153
+ }
145
154
  }
146
155
  else {
147
156
  const stored = await new Promise((resolve) => {
@@ -149,9 +158,16 @@ const buildStatusMessage = async () => {
149
158
  });
150
159
  const port = parsePort(stored.relayPort) ?? DEFAULT_RELAY_PORT;
151
160
  relayHealth = await fetchRelayHealth(port);
152
- if (hasReadyRelayHandshake(relayHealth)) {
161
+ if (reconnectSuppressed) {
162
+ note = statusNoteOverride
163
+ ?? "Another extension client took over the relay connection. This client will stay disconnected until you reconnect it explicitly.";
164
+ }
165
+ else if (hasReadyRelayHandshake(relayHealth)) {
153
166
  note = `Connected to 127.0.0.1:${port}`;
154
167
  }
168
+ else if (nativeHealth?.status === "connected") {
169
+ note = "Connected via native host.";
170
+ }
155
171
  else {
156
172
  note = statusNoteOverride ?? buildRelayHealthNote(relayHealth);
157
173
  }
@@ -230,6 +246,8 @@ const buildRelayHealthNote = (health) => {
230
246
  return "Canvas channel disconnected. Reopen the design canvas command and retry.";
231
247
  case "cdp_disconnected":
232
248
  return "No CDP clients connected. Start a session and retry.";
249
+ case "relay_dirty":
250
+ return "Relay has active CDP, annotation, canvas clients, or ops-owned targets. Disconnect the current run and retry.";
233
251
  case "relay_down":
234
252
  return "Relay down. Start the daemon and retry.";
235
253
  default:
@@ -262,6 +280,16 @@ const clearRetry = () => {
262
280
  chrome.alarms.clear(RETRY_ALARM_NAME);
263
281
  }
264
282
  };
283
+ const scheduleWatchdog = () => {
284
+ if (chrome.alarms?.create) {
285
+ chrome.alarms.create(WATCHDOG_ALARM_NAME, { periodInMinutes: WATCHDOG_PERIOD_MINUTES });
286
+ }
287
+ };
288
+ const clearWatchdog = () => {
289
+ if (chrome.alarms?.clear) {
290
+ chrome.alarms.clear(WATCHDOG_ALARM_NAME);
291
+ }
292
+ };
265
293
  const scheduleRetry = () => {
266
294
  if (retryScheduled) {
267
295
  return;
@@ -357,24 +385,37 @@ const fetchRelayHealth = async (port) => {
357
385
  }
358
386
  const data = await response.json();
359
387
  if (data.health && typeof data.health === "object") {
360
- return data.health;
388
+ const health = data.health;
389
+ return typeof health.opsOwnedTargetCount === "number" && Number.isFinite(health.opsOwnedTargetCount)
390
+ ? health
391
+ : null;
361
392
  }
362
393
  const extensionConnected = data.extensionConnected === true;
363
394
  const handshake = data.extensionHandshakeComplete === true;
364
395
  const cdpConnected = data.cdpConnected === true;
365
396
  const annotationConnected = data.annotationConnected === true;
366
397
  const opsConnected = data.opsConnected === true;
398
+ const opsOwnedTargetCount = typeof data.opsOwnedTargetCount === "number" && Number.isFinite(data.opsOwnedTargetCount)
399
+ ? data.opsOwnedTargetCount
400
+ : null;
401
+ if (opsOwnedTargetCount === null || opsOwnedTargetCount < 0) {
402
+ return null;
403
+ }
367
404
  const canvasConnected = data.canvasConnected === true;
368
405
  const pairingRequired = data.pairingRequired === true;
369
- const ok = extensionConnected && handshake;
406
+ const dirty = cdpConnected || annotationConnected || canvasConnected || opsOwnedTargetCount > 0;
407
+ const ok = extensionConnected && handshake && !dirty;
370
408
  return {
371
409
  ok,
372
- reason: ok ? "ok" : (extensionConnected ? "handshake_incomplete" : "extension_disconnected"),
410
+ reason: ok
411
+ ? "ok"
412
+ : (dirty ? "relay_dirty" : (extensionConnected ? "handshake_incomplete" : "extension_disconnected")),
373
413
  extensionConnected,
374
414
  extensionHandshakeComplete: handshake,
375
415
  cdpConnected,
376
416
  annotationConnected,
377
417
  opsConnected,
418
+ opsOwnedTargetCount,
378
419
  canvasConnected,
379
420
  pairingRequired
380
421
  };
@@ -384,6 +425,10 @@ const fetchRelayHealth = async (port) => {
384
425
  return null;
385
426
  }
386
427
  };
428
+ const relayHasActiveExtensionClient = async (storedRelayPort) => {
429
+ const storedHealth = await fetchRelayHealth(storedRelayPort);
430
+ return hasReadyRelayHandshake(storedHealth);
431
+ };
387
432
  const sendAnnotationResponse = (payload, transport = "relay") => {
388
433
  if (transport === "popup") {
389
434
  return;
@@ -1292,11 +1337,8 @@ const fetchTokenFromPlugin = async (port) => {
1292
1337
  return null;
1293
1338
  }
1294
1339
  };
1295
- const clearStoredRelayState = async () => {
1340
+ const clearStoredRelayCredentials = async () => {
1296
1341
  await setStorage({
1297
- relayPort: null,
1298
- relayInstanceId: null,
1299
- relayEpoch: null,
1300
1342
  pairingToken: null,
1301
1343
  tokenEpoch: null
1302
1344
  });
@@ -1319,10 +1361,17 @@ const attemptAutoConnect = async () => {
1319
1361
  });
1320
1362
  const autoConnect = typeof data.autoConnect === "boolean" ? data.autoConnect : DEFAULT_AUTO_CONNECT;
1321
1363
  autoConnectEnabled = autoConnect;
1322
- if (!autoConnect || connection.getStatus() === "connected" || connection.isReconnectSuppressed()) {
1364
+ if (!autoConnect || connection.getStatus() === "connected") {
1323
1365
  clearRetry();
1366
+ if (!autoConnect) {
1367
+ clearWatchdog();
1368
+ }
1369
+ else {
1370
+ scheduleWatchdog();
1371
+ }
1324
1372
  return;
1325
1373
  }
1374
+ scheduleWatchdog();
1326
1375
  const autoPair = typeof data.autoPair === "boolean" ? data.autoPair : DEFAULT_AUTO_PAIR;
1327
1376
  const pairingEnabled = typeof data.pairingEnabled === "boolean" ? data.pairingEnabled : DEFAULT_PAIRING_ENABLED;
1328
1377
  const storedRelayPort = parsePort(data.relayPort) ?? DEFAULT_RELAY_PORT;
@@ -1331,6 +1380,15 @@ const attemptAutoConnect = async () => {
1331
1380
  if (typeof data.nativeEnabled !== "boolean") {
1332
1381
  await setStorage({ nativeEnabled });
1333
1382
  }
1383
+ if (connection.isReconnectSuppressed()) {
1384
+ const activeExtensionClient = await relayHasActiveExtensionClient(storedRelayPort);
1385
+ if (activeExtensionClient) {
1386
+ setStatusNoteOverride("Another extension client is connected. Retrying when the relay is free.");
1387
+ scheduleRetry();
1388
+ return;
1389
+ }
1390
+ setStatusNoteOverride("Relay no longer has an active extension client. Reconnecting.");
1391
+ }
1334
1392
  if (autoPair && pairingEnabled) {
1335
1393
  let config = await fetchRelayConfig(DEFAULT_DISCOVERY_PORT);
1336
1394
  if (!config && storedRelayPort !== DEFAULT_DISCOVERY_PORT) {
@@ -1355,12 +1413,12 @@ const attemptAutoConnect = async () => {
1355
1413
  });
1356
1414
  }
1357
1415
  if (hasEpoch && storedRelayEpoch !== null && storedRelayEpoch !== configEpoch) {
1358
- await clearStoredRelayState();
1416
+ await clearStoredRelayCredentials();
1359
1417
  storedPairingToken = null;
1360
1418
  setStatusNoteOverride("Relay restarted. Refresh the connection.");
1361
1419
  }
1362
1420
  if (config.instanceId && storedRelayInstanceId && config.instanceId !== storedRelayInstanceId) {
1363
- await clearStoredRelayState();
1421
+ await clearStoredRelayCredentials();
1364
1422
  storedPairingToken = null;
1365
1423
  setStatusNoteOverride("Relay instance mismatch. Open the popup and click Connect.");
1366
1424
  }
@@ -1428,6 +1486,8 @@ const autoConnect = async () => {
1428
1486
  }
1429
1487
  };
1430
1488
  connection.onStatus((status) => {
1489
+ const shouldCleanupRelayDisconnect = status === "disconnected" && lastRelayCleanupStatus !== "disconnected";
1490
+ lastRelayCleanupStatus = status;
1431
1491
  const effectiveStatus = status === "connected" ? "connected" : (nativeEnabled && nativePort.isConnected()) ? "connected" : "disconnected";
1432
1492
  updateBadge(effectiveStatus);
1433
1493
  void refreshBadgeFromBackgroundStatus();
@@ -1436,11 +1496,21 @@ connection.onStatus((status) => {
1436
1496
  setStatusNoteOverride(null);
1437
1497
  clearRetry();
1438
1498
  }
1439
- if (status === "disconnected" && !nativePort.isConnected()) {
1440
- for (const session of annotationSessions.values()) {
1441
- clearTimeout(session.timeoutId);
1499
+ if (status === "disconnected") {
1500
+ if (shouldCleanupRelayDisconnect) {
1501
+ for (const session of annotationSessions.values()) {
1502
+ clearTimeout(session.timeoutId);
1503
+ }
1504
+ annotationSessions.clear();
1505
+ opsRuntime.handleRelayDisconnected();
1506
+ }
1507
+ if (nativePort.isConnected()) {
1508
+ return;
1509
+ }
1510
+ if (connection.isReconnectSuppressed() && autoConnectEnabled) {
1511
+ scheduleRetry();
1512
+ return;
1442
1513
  }
1443
- annotationSessions.clear();
1444
1514
  if (connection.isReconnectSuppressed()) {
1445
1515
  clearRetry();
1446
1516
  return;
@@ -1469,6 +1539,11 @@ if (chrome.alarms?.onAlarm) {
1469
1539
  logError("auto_connect.alarm", error, { code: "auto_connect_failed" });
1470
1540
  });
1471
1541
  }
1542
+ if (alarm.name === WATCHDOG_ALARM_NAME) {
1543
+ autoConnect().catch((error) => {
1544
+ logError("auto_connect.watchdog", error, { code: "auto_connect_failed" });
1545
+ });
1546
+ }
1472
1547
  });
1473
1548
  }
1474
1549
  if (chrome.commands?.onCommand) {
@@ -1531,12 +1606,14 @@ chrome.storage.onChanged.addListener((changes, area) => {
1531
1606
  typeof changes.autoConnect.newValue === "boolean" ? changes.autoConnect.newValue : DEFAULT_AUTO_CONNECT;
1532
1607
  }
1533
1608
  if (changes.autoConnect?.newValue === true) {
1609
+ scheduleWatchdog();
1534
1610
  autoConnect().catch((error) => {
1535
1611
  logError("auto_connect.setting", error, { code: "auto_connect_failed" });
1536
1612
  });
1537
1613
  }
1538
1614
  else if (changes.autoConnect?.newValue === false) {
1539
1615
  clearRetry();
1616
+ clearWatchdog();
1540
1617
  }
1541
1618
  if (changes.pairingToken) {
1542
1619
  autoConnect().catch((error) => {