opendevbrowser 0.0.16 → 0.0.18

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 (616) hide show
  1. package/README.md +201 -79
  2. package/dist/annotate/agent-inbox-store.d.ts +58 -0
  3. package/dist/annotate/agent-inbox-store.d.ts.map +1 -0
  4. package/dist/annotate/agent-inbox.d.ts +25 -0
  5. package/dist/annotate/agent-inbox.d.ts.map +1 -0
  6. package/dist/annotate/direct-annotator.d.ts.map +1 -1
  7. package/dist/annotate/timeout-messages.d.ts +4 -0
  8. package/dist/annotate/timeout-messages.d.ts.map +1 -0
  9. package/dist/automation/coordinator.d.ts +55 -0
  10. package/dist/automation/coordinator.d.ts.map +1 -0
  11. package/dist/browser/annotation-manager.d.ts +7 -1
  12. package/dist/browser/annotation-manager.d.ts.map +1 -1
  13. package/dist/browser/browser-manager.d.ts +153 -48
  14. package/dist/browser/browser-manager.d.ts.map +1 -1
  15. package/dist/browser/canvas-client.d.ts +54 -0
  16. package/dist/browser/canvas-client.d.ts.map +1 -0
  17. package/dist/browser/canvas-code-sync-manager.d.ts +87 -0
  18. package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -0
  19. package/dist/browser/canvas-manager.d.ts +122 -0
  20. package/dist/browser/canvas-manager.d.ts.map +1 -0
  21. package/dist/browser/canvas-runtime-preview-bridge.d.ts +20 -0
  22. package/dist/browser/canvas-runtime-preview-bridge.d.ts.map +1 -0
  23. package/dist/browser/canvas-session-sync-manager.d.ts +21 -0
  24. package/dist/browser/canvas-session-sync-manager.d.ts.map +1 -0
  25. package/dist/browser/global-challenge-coordinator.d.ts +27 -0
  26. package/dist/browser/global-challenge-coordinator.d.ts.map +1 -0
  27. package/dist/browser/manager-types.d.ts +179 -1
  28. package/dist/browser/manager-types.d.ts.map +1 -1
  29. package/dist/browser/ops-browser-manager.d.ts +114 -4
  30. package/dist/browser/ops-browser-manager.d.ts.map +1 -1
  31. package/dist/browser/ops-client.d.ts +17 -1
  32. package/dist/browser/ops-client.d.ts.map +1 -1
  33. package/dist/browser/playwright-runtime.d.ts +4 -0
  34. package/dist/browser/playwright-runtime.d.ts.map +1 -0
  35. package/dist/browser/review-surface.d.ts +9 -0
  36. package/dist/browser/review-surface.d.ts.map +1 -0
  37. package/dist/browser/screencast-recorder.d.ts +57 -0
  38. package/dist/browser/screencast-recorder.d.ts.map +1 -0
  39. package/dist/browser/session-inspector.d.ts +71 -0
  40. package/dist/browser/session-inspector.d.ts.map +1 -0
  41. package/dist/browser/session-store.d.ts +5 -1
  42. package/dist/browser/session-store.d.ts.map +1 -1
  43. package/dist/browser/system-chrome-cookies.d.ts +46 -0
  44. package/dist/browser/system-chrome-cookies.d.ts.map +1 -0
  45. package/dist/browser/target-manager.d.ts +1 -0
  46. package/dist/browser/target-manager.d.ts.map +1 -1
  47. package/dist/cache/chrome-locator.d.ts.map +1 -1
  48. package/dist/cache/chrome-user-data.d.ts +17 -0
  49. package/dist/cache/chrome-user-data.d.ts.map +1 -0
  50. package/dist/canvas/adapter-plugins/loader.d.ts +13 -0
  51. package/dist/canvas/adapter-plugins/loader.d.ts.map +1 -0
  52. package/dist/canvas/adapter-plugins/manifest.d.ts +146 -0
  53. package/dist/canvas/adapter-plugins/manifest.d.ts.map +1 -0
  54. package/dist/canvas/adapter-plugins/types.d.ts +83 -0
  55. package/dist/canvas/adapter-plugins/types.d.ts.map +1 -0
  56. package/dist/canvas/adapter-plugins/validator.d.ts +10 -0
  57. package/dist/canvas/adapter-plugins/validator.d.ts.map +1 -0
  58. package/dist/canvas/code-sync/apply-tsx.d.ts +25 -0
  59. package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -0
  60. package/dist/canvas/code-sync/graph.d.ts +5 -0
  61. package/dist/canvas/code-sync/graph.d.ts.map +1 -0
  62. package/dist/canvas/code-sync/hash.d.ts +3 -0
  63. package/dist/canvas/code-sync/hash.d.ts.map +1 -0
  64. package/dist/canvas/code-sync/import.d.ts +19 -0
  65. package/dist/canvas/code-sync/import.d.ts.map +1 -0
  66. package/dist/canvas/code-sync/manifest.d.ts +6 -0
  67. package/dist/canvas/code-sync/manifest.d.ts.map +1 -0
  68. package/dist/canvas/code-sync/tsx-adapter.d.ts +8 -0
  69. package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -0
  70. package/dist/canvas/code-sync/types.d.ts +244 -0
  71. package/dist/canvas/code-sync/types.d.ts.map +1 -0
  72. package/dist/canvas/code-sync/write.d.ts +9 -0
  73. package/dist/canvas/code-sync/write.d.ts.map +1 -0
  74. package/dist/canvas/document-store.d.ts +91 -0
  75. package/dist/canvas/document-store.d.ts.map +1 -0
  76. package/dist/canvas/export.d.ts +12 -0
  77. package/dist/canvas/export.d.ts.map +1 -0
  78. package/dist/canvas/framework-adapters/custom-elements-v1.d.ts +3 -0
  79. package/dist/canvas/framework-adapters/custom-elements-v1.d.ts.map +1 -0
  80. package/dist/canvas/framework-adapters/html-static-v1.d.ts +3 -0
  81. package/dist/canvas/framework-adapters/html-static-v1.d.ts.map +1 -0
  82. package/dist/canvas/framework-adapters/markup.d.ts +9 -0
  83. package/dist/canvas/framework-adapters/markup.d.ts.map +1 -0
  84. package/dist/canvas/framework-adapters/react-tsx-v2.d.ts +3 -0
  85. package/dist/canvas/framework-adapters/react-tsx-v2.d.ts.map +1 -0
  86. package/dist/canvas/framework-adapters/registry.d.ts +12 -0
  87. package/dist/canvas/framework-adapters/registry.d.ts.map +1 -0
  88. package/dist/canvas/framework-adapters/svelte-sfc-v1.d.ts +3 -0
  89. package/dist/canvas/framework-adapters/svelte-sfc-v1.d.ts.map +1 -0
  90. package/dist/canvas/framework-adapters/types.d.ts +57 -0
  91. package/dist/canvas/framework-adapters/types.d.ts.map +1 -0
  92. package/dist/canvas/framework-adapters/vue-sfc-v1.d.ts +3 -0
  93. package/dist/canvas/framework-adapters/vue-sfc-v1.d.ts.map +1 -0
  94. package/dist/canvas/kits/catalog.d.ts +5 -0
  95. package/dist/canvas/kits/catalog.d.ts.map +1 -0
  96. package/dist/canvas/library-adapters/react/index.d.ts +3 -0
  97. package/dist/canvas/library-adapters/react/index.d.ts.map +1 -0
  98. package/dist/canvas/library-adapters/registry.d.ts +11 -0
  99. package/dist/canvas/library-adapters/registry.d.ts.map +1 -0
  100. package/dist/canvas/library-adapters/types.d.ts +43 -0
  101. package/dist/canvas/library-adapters/types.d.ts.map +1 -0
  102. package/dist/canvas/repo-store.d.ts +12 -0
  103. package/dist/canvas/repo-store.d.ts.map +1 -0
  104. package/dist/canvas/starters/catalog.d.ts +34 -0
  105. package/dist/canvas/starters/catalog.d.ts.map +1 -0
  106. package/dist/canvas/surface-palette.d.ts +15 -0
  107. package/dist/canvas/surface-palette.d.ts.map +1 -0
  108. package/dist/canvas/token-references.d.ts +22 -0
  109. package/dist/canvas/token-references.d.ts.map +1 -0
  110. package/dist/canvas/types.d.ts +594 -0
  111. package/dist/canvas/types.d.ts.map +1 -0
  112. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js +7 -0
  113. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js.map +1 -0
  114. package/dist/challenges/action-loop.d.ts +13 -0
  115. package/dist/challenges/action-loop.d.ts.map +1 -0
  116. package/dist/challenges/capability-matrix.d.ts +3 -0
  117. package/dist/challenges/capability-matrix.d.ts.map +1 -0
  118. package/dist/challenges/evidence-bundle.d.ts +48 -0
  119. package/dist/challenges/evidence-bundle.d.ts.map +1 -0
  120. package/dist/challenges/governed-adapter-gateway.d.ts +4 -0
  121. package/dist/challenges/governed-adapter-gateway.d.ts.map +1 -0
  122. package/dist/challenges/human-yield-gate.d.ts +20 -0
  123. package/dist/challenges/human-yield-gate.d.ts.map +1 -0
  124. package/dist/challenges/index.d.ts +15 -0
  125. package/dist/challenges/index.d.ts.map +1 -0
  126. package/dist/challenges/interpreter.d.ts +3 -0
  127. package/dist/challenges/interpreter.d.ts.map +1 -0
  128. package/dist/challenges/optional-computer-use-bridge.d.ts +9 -0
  129. package/dist/challenges/optional-computer-use-bridge.d.ts.map +1 -0
  130. package/dist/challenges/orchestrator.d.ts +32 -0
  131. package/dist/challenges/orchestrator.d.ts.map +1 -0
  132. package/dist/challenges/outcome-recorder.d.ts +8 -0
  133. package/dist/challenges/outcome-recorder.d.ts.map +1 -0
  134. package/dist/challenges/owned-environment-lane.d.ts +3 -0
  135. package/dist/challenges/owned-environment-lane.d.ts.map +1 -0
  136. package/dist/challenges/policy-gate.d.ts +9 -0
  137. package/dist/challenges/policy-gate.d.ts.map +1 -0
  138. package/dist/challenges/sanctioned-identity-lane.d.ts +3 -0
  139. package/dist/challenges/sanctioned-identity-lane.d.ts.map +1 -0
  140. package/dist/challenges/service-adapter-lane.d.ts +3 -0
  141. package/dist/challenges/service-adapter-lane.d.ts.map +1 -0
  142. package/dist/challenges/strategy-selector.d.ts +10 -0
  143. package/dist/challenges/strategy-selector.d.ts.map +1 -0
  144. package/dist/challenges/types.d.ts +277 -0
  145. package/dist/challenges/types.d.ts.map +1 -0
  146. package/dist/challenges/verification-gate.d.ts +15 -0
  147. package/dist/challenges/verification-gate.d.ts.map +1 -0
  148. package/dist/chunk-5FZQJRBQ.js +15256 -0
  149. package/dist/chunk-5FZQJRBQ.js.map +1 -0
  150. package/dist/{chunk-7W3SPXIB.js → chunk-FUSXMW3G.js} +4 -1
  151. package/dist/chunk-L57D35TB.js +33513 -0
  152. package/dist/chunk-L57D35TB.js.map +1 -0
  153. package/dist/chunk-TBUCZX4A.js +34 -0
  154. package/dist/chunk-TBUCZX4A.js.map +1 -0
  155. package/dist/chunk-Y2KL55OG.js +59 -0
  156. package/dist/chunk-Y2KL55OG.js.map +1 -0
  157. package/dist/chunk-YBQECXZX.js +409 -0
  158. package/dist/chunk-YBQECXZX.js.map +1 -0
  159. package/dist/cli/args.d.ts +4 -4
  160. package/dist/cli/args.d.ts.map +1 -1
  161. package/dist/cli/commands/annotate.d.ts +11 -0
  162. package/dist/cli/commands/annotate.d.ts.map +1 -1
  163. package/dist/cli/commands/artifacts.d.ts.map +1 -1
  164. package/dist/cli/commands/canvas.d.ts +45 -0
  165. package/dist/cli/commands/canvas.d.ts.map +1 -0
  166. package/dist/cli/commands/daemon.d.ts +7 -0
  167. package/dist/cli/commands/daemon.d.ts.map +1 -1
  168. package/dist/cli/commands/desktop/accessibility-snapshot.d.ts +3 -0
  169. package/dist/cli/commands/desktop/accessibility-snapshot.d.ts.map +1 -0
  170. package/dist/cli/commands/desktop/active-window.d.ts +3 -0
  171. package/dist/cli/commands/desktop/active-window.d.ts.map +1 -0
  172. package/dist/cli/commands/desktop/capture-desktop.d.ts +3 -0
  173. package/dist/cli/commands/desktop/capture-desktop.d.ts.map +1 -0
  174. package/dist/cli/commands/desktop/capture-window.d.ts +3 -0
  175. package/dist/cli/commands/desktop/capture-window.d.ts.map +1 -0
  176. package/dist/cli/commands/desktop/shared.d.ts +19 -0
  177. package/dist/cli/commands/desktop/shared.d.ts.map +1 -0
  178. package/dist/cli/commands/desktop/status.d.ts +3 -0
  179. package/dist/cli/commands/desktop/status.d.ts.map +1 -0
  180. package/dist/cli/commands/desktop/windows.d.ts +3 -0
  181. package/dist/cli/commands/desktop/windows.d.ts.map +1 -0
  182. package/dist/cli/commands/devtools/dialog.d.ts +19 -0
  183. package/dist/cli/commands/devtools/dialog.d.ts.map +1 -0
  184. package/dist/cli/commands/devtools/perf.d.ts.map +1 -1
  185. package/dist/cli/commands/devtools/screencast-start.d.ts +20 -0
  186. package/dist/cli/commands/devtools/screencast-start.d.ts.map +1 -0
  187. package/dist/cli/commands/devtools/screencast-stop.d.ts +17 -0
  188. package/dist/cli/commands/devtools/screencast-stop.d.ts.map +1 -0
  189. package/dist/cli/commands/devtools/screenshot.d.ts +3 -0
  190. package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -1
  191. package/dist/cli/commands/dom/attr.d.ts.map +1 -1
  192. package/dist/cli/commands/dom/checked.d.ts.map +1 -1
  193. package/dist/cli/commands/dom/enabled.d.ts.map +1 -1
  194. package/dist/cli/commands/dom/html.d.ts.map +1 -1
  195. package/dist/cli/commands/dom/text.d.ts.map +1 -1
  196. package/dist/cli/commands/dom/value.d.ts.map +1 -1
  197. package/dist/cli/commands/dom/visible.d.ts.map +1 -1
  198. package/dist/cli/commands/export/clone-component.d.ts +9 -0
  199. package/dist/cli/commands/export/clone-component.d.ts.map +1 -1
  200. package/dist/cli/commands/export/clone-page.d.ts +8 -0
  201. package/dist/cli/commands/export/clone-page.d.ts.map +1 -1
  202. package/dist/cli/commands/interact/check.d.ts.map +1 -1
  203. package/dist/cli/commands/interact/click.d.ts.map +1 -1
  204. package/dist/cli/commands/interact/hover.d.ts.map +1 -1
  205. package/dist/cli/commands/interact/pointer-down.d.ts +7 -0
  206. package/dist/cli/commands/interact/pointer-down.d.ts.map +1 -0
  207. package/dist/cli/commands/interact/pointer-drag.d.ts +7 -0
  208. package/dist/cli/commands/interact/pointer-drag.d.ts.map +1 -0
  209. package/dist/cli/commands/interact/pointer-move.d.ts +7 -0
  210. package/dist/cli/commands/interact/pointer-move.d.ts.map +1 -0
  211. package/dist/cli/commands/interact/pointer-shared.d.ts +6 -0
  212. package/dist/cli/commands/interact/pointer-shared.d.ts.map +1 -0
  213. package/dist/cli/commands/interact/pointer-up.d.ts +7 -0
  214. package/dist/cli/commands/interact/pointer-up.d.ts.map +1 -0
  215. package/dist/cli/commands/interact/press.d.ts.map +1 -1
  216. package/dist/cli/commands/interact/scroll-into-view.d.ts.map +1 -1
  217. package/dist/cli/commands/interact/scroll.d.ts.map +1 -1
  218. package/dist/cli/commands/interact/select.d.ts.map +1 -1
  219. package/dist/cli/commands/interact/type.d.ts.map +1 -1
  220. package/dist/cli/commands/interact/uncheck.d.ts.map +1 -1
  221. package/dist/cli/commands/interact/upload.d.ts +18 -0
  222. package/dist/cli/commands/interact/upload.d.ts.map +1 -0
  223. package/dist/cli/commands/macro-resolve.d.ts +2 -0
  224. package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
  225. package/dist/cli/commands/native.d.ts +22 -8
  226. package/dist/cli/commands/native.d.ts.map +1 -1
  227. package/dist/cli/commands/nav/goto.d.ts.map +1 -1
  228. package/dist/cli/commands/nav/review.d.ts +7 -0
  229. package/dist/cli/commands/nav/review.d.ts.map +1 -0
  230. package/dist/cli/commands/nav/snapshot.d.ts.map +1 -1
  231. package/dist/cli/commands/nav/wait.d.ts.map +1 -1
  232. package/dist/cli/commands/pages/open.d.ts.map +1 -1
  233. package/dist/cli/commands/product-video.d.ts +2 -0
  234. package/dist/cli/commands/product-video.d.ts.map +1 -1
  235. package/dist/cli/commands/research.d.ts +3 -0
  236. package/dist/cli/commands/research.d.ts.map +1 -1
  237. package/dist/cli/commands/run.d.ts +14 -0
  238. package/dist/cli/commands/run.d.ts.map +1 -1
  239. package/dist/cli/commands/serve.d.ts +1 -21
  240. package/dist/cli/commands/serve.d.ts.map +1 -1
  241. package/dist/cli/commands/session/connect.d.ts.map +1 -1
  242. package/dist/cli/commands/session/disconnect.d.ts.map +1 -1
  243. package/dist/cli/commands/session/inspector.d.ts +21 -0
  244. package/dist/cli/commands/session/inspector.d.ts.map +1 -0
  245. package/dist/cli/commands/session/launch.d.ts.map +1 -1
  246. package/dist/cli/commands/shopping.d.ts +5 -0
  247. package/dist/cli/commands/shopping.d.ts.map +1 -1
  248. package/dist/cli/commands/status.d.ts +2 -9
  249. package/dist/cli/commands/status.d.ts.map +1 -1
  250. package/dist/cli/commands/targets/new.d.ts.map +1 -1
  251. package/dist/cli/daemon-autostart.d.ts +11 -0
  252. package/dist/cli/daemon-autostart.d.ts.map +1 -1
  253. package/dist/cli/daemon-client.d.ts +3 -0
  254. package/dist/cli/daemon-client.d.ts.map +1 -1
  255. package/dist/cli/daemon-commands.d.ts.map +1 -1
  256. package/dist/cli/daemon-state.d.ts +16 -0
  257. package/dist/cli/daemon-state.d.ts.map +1 -1
  258. package/dist/cli/daemon-status.d.ts +7 -2
  259. package/dist/cli/daemon-status.d.ts.map +1 -1
  260. package/dist/cli/daemon.d.ts +1 -0
  261. package/dist/cli/daemon.d.ts.map +1 -1
  262. package/dist/cli/help.d.ts +19 -3
  263. package/dist/cli/help.d.ts.map +1 -1
  264. package/dist/cli/index.js +2927 -932
  265. package/dist/cli/index.js.map +1 -1
  266. package/dist/cli/install-autostart-output.d.ts +6 -0
  267. package/dist/cli/install-autostart-output.d.ts.map +1 -0
  268. package/dist/cli/install-autostart-reconciliation.d.ts +23 -0
  269. package/dist/cli/install-autostart-reconciliation.d.ts.map +1 -0
  270. package/dist/cli/installers/skills.d.ts +42 -6
  271. package/dist/cli/installers/skills.d.ts.map +1 -1
  272. package/dist/cli/output.d.ts +3 -0
  273. package/dist/cli/output.d.ts.map +1 -1
  274. package/dist/cli/remote-canvas-manager.d.ts +8 -0
  275. package/dist/cli/remote-canvas-manager.d.ts.map +1 -0
  276. package/dist/cli/remote-desktop-runtime.d.ts +15 -0
  277. package/dist/cli/remote-desktop-runtime.d.ts.map +1 -0
  278. package/dist/cli/remote-manager.d.ts +27 -3
  279. package/dist/cli/remote-manager.d.ts.map +1 -1
  280. package/dist/cli/remote-relay.d.ts +2 -0
  281. package/dist/cli/remote-relay.d.ts.map +1 -1
  282. package/dist/cli/transport-timeouts.d.ts +8 -0
  283. package/dist/cli/transport-timeouts.d.ts.map +1 -0
  284. package/dist/cli/utils/http.d.ts +9 -0
  285. package/dist/cli/utils/http.d.ts.map +1 -1
  286. package/dist/cli/utils/parse.d.ts +3 -0
  287. package/dist/cli/utils/parse.d.ts.map +1 -1
  288. package/dist/cli/utils/skills.d.ts +1 -2
  289. package/dist/cli/utils/skills.d.ts.map +1 -1
  290. package/dist/cli/utils/workflow-message.d.ts +2 -0
  291. package/dist/cli/utils/workflow-message.d.ts.map +1 -0
  292. package/dist/config.d.ts +47 -0
  293. package/dist/config.d.ts.map +1 -1
  294. package/dist/core/bootstrap.d.ts.map +1 -1
  295. package/dist/core/index.d.ts +1 -0
  296. package/dist/core/index.d.ts.map +1 -1
  297. package/dist/core/logging.d.ts +3 -1
  298. package/dist/core/logging.d.ts.map +1 -1
  299. package/dist/core/runtime-assemblies.d.ts +22 -0
  300. package/dist/core/runtime-assemblies.d.ts.map +1 -0
  301. package/dist/core/types.d.ts +17 -0
  302. package/dist/core/types.d.ts.map +1 -1
  303. package/dist/desktop/audit.d.ts +37 -0
  304. package/dist/desktop/audit.d.ts.map +1 -0
  305. package/dist/desktop/errors.d.ts +7 -0
  306. package/dist/desktop/errors.d.ts.map +1 -0
  307. package/dist/desktop/index.d.ts +6 -0
  308. package/dist/desktop/index.d.ts.map +1 -0
  309. package/dist/desktop/runtime.d.ts +26 -0
  310. package/dist/desktop/runtime.d.ts.map +1 -0
  311. package/dist/desktop/types.d.ts +76 -0
  312. package/dist/desktop/types.d.ts.map +1 -0
  313. package/dist/extension-extractor.d.ts +6 -0
  314. package/dist/extension-extractor.d.ts.map +1 -1
  315. package/dist/fs-UMRKOBNN.js +7 -0
  316. package/dist/fs-UMRKOBNN.js.map +1 -0
  317. package/dist/index.d.ts.map +1 -1
  318. package/dist/index.js +1221 -460
  319. package/dist/index.js.map +1 -1
  320. package/dist/integrations/figma/assets.d.ts +13 -0
  321. package/dist/integrations/figma/assets.d.ts.map +1 -0
  322. package/dist/integrations/figma/auth.d.ts +3 -0
  323. package/dist/integrations/figma/auth.d.ts.map +1 -0
  324. package/dist/integrations/figma/client.d.ts +42 -0
  325. package/dist/integrations/figma/client.d.ts.map +1 -0
  326. package/dist/integrations/figma/mappers.d.ts +23 -0
  327. package/dist/integrations/figma/mappers.d.ts.map +1 -0
  328. package/dist/integrations/figma/normalize.d.ts +99 -0
  329. package/dist/integrations/figma/normalize.d.ts.map +1 -0
  330. package/dist/integrations/figma/url.d.ts +17 -0
  331. package/dist/integrations/figma/url.d.ts.map +1 -0
  332. package/dist/integrations/figma/variables.d.ts +21 -0
  333. package/dist/integrations/figma/variables.d.ts.map +1 -0
  334. package/dist/macros/execute-runtime.d.ts +19 -0
  335. package/dist/macros/execute-runtime.d.ts.map +1 -0
  336. package/dist/macros/execute.d.ts +3 -1
  337. package/dist/macros/execute.d.ts.map +1 -1
  338. package/dist/{macros-NUBRM44Y.js → macros-ND2M7LWU.js} +2 -2
  339. package/dist/opendevbrowser.d.ts.map +1 -1
  340. package/dist/opendevbrowser.js +1221 -460
  341. package/dist/opendevbrowser.js.map +1 -1
  342. package/dist/providers/blocker.d.ts.map +1 -1
  343. package/dist/providers/browser-fallback.d.ts +30 -0
  344. package/dist/providers/browser-fallback.d.ts.map +1 -0
  345. package/dist/providers/constraint.d.ts +45 -0
  346. package/dist/providers/constraint.d.ts.map +1 -0
  347. package/dist/providers/index.d.ts +11 -2
  348. package/dist/providers/index.d.ts.map +1 -1
  349. package/dist/providers/policy.d.ts.map +1 -1
  350. package/dist/providers/product-video-compiler.d.ts +92 -0
  351. package/dist/providers/product-video-compiler.d.ts.map +1 -0
  352. package/dist/providers/registry.d.ts +37 -1
  353. package/dist/providers/registry.d.ts.map +1 -1
  354. package/dist/providers/renderer.d.ts.map +1 -1
  355. package/dist/providers/research-compiler.d.ts +64 -0
  356. package/dist/providers/research-compiler.d.ts.map +1 -0
  357. package/dist/providers/research-executor.d.ts +27 -0
  358. package/dist/providers/research-executor.d.ts.map +1 -0
  359. package/dist/providers/runtime-bundle.d.ts +26 -0
  360. package/dist/providers/runtime-bundle.d.ts.map +1 -0
  361. package/dist/providers/runtime-factory.d.ts +6 -1
  362. package/dist/providers/runtime-factory.d.ts.map +1 -1
  363. package/dist/providers/runtime-policy.d.ts +24 -0
  364. package/dist/providers/runtime-policy.d.ts.map +1 -0
  365. package/dist/providers/shared/anti-bot-policy.d.ts +3 -2
  366. package/dist/providers/shared/anti-bot-policy.d.ts.map +1 -1
  367. package/dist/providers/shopping/index.d.ts +11 -1
  368. package/dist/providers/shopping/index.d.ts.map +1 -1
  369. package/dist/providers/shopping-compiler.d.ts +51 -0
  370. package/dist/providers/shopping-compiler.d.ts.map +1 -0
  371. package/dist/providers/shopping-executor.d.ts +18 -0
  372. package/dist/providers/shopping-executor.d.ts.map +1 -0
  373. package/dist/providers/shopping-postprocess.d.ts +46 -0
  374. package/dist/providers/shopping-postprocess.d.ts.map +1 -0
  375. package/dist/providers/shopping-workflow.d.ts +33 -0
  376. package/dist/providers/shopping-workflow.d.ts.map +1 -0
  377. package/dist/providers/social/platform.d.ts +2 -1
  378. package/dist/providers/social/platform.d.ts.map +1 -1
  379. package/dist/providers/social/search-quality.d.ts +16 -0
  380. package/dist/providers/social/search-quality.d.ts.map +1 -0
  381. package/dist/providers/social/youtube-resolver.d.ts +2 -1
  382. package/dist/providers/social/youtube-resolver.d.ts.map +1 -1
  383. package/dist/providers/social/youtube.d.ts.map +1 -1
  384. package/dist/providers/types.d.ts +116 -4
  385. package/dist/providers/types.d.ts.map +1 -1
  386. package/dist/providers/web/crawl-worker.d.ts.map +1 -1
  387. package/dist/providers/web/extract.d.ts +16 -0
  388. package/dist/providers/web/extract.d.ts.map +1 -1
  389. package/dist/providers/web/index.d.ts.map +1 -1
  390. package/dist/providers/workflow-contracts.d.ts +53 -0
  391. package/dist/providers/workflow-contracts.d.ts.map +1 -0
  392. package/dist/providers/workflows.d.ts +30 -6
  393. package/dist/providers/workflows.d.ts.map +1 -1
  394. package/dist/providers-G36AM3Z2.js +121 -0
  395. package/dist/providers-G36AM3Z2.js.map +1 -0
  396. package/dist/public-surface/generated-manifest.d.ts +1168 -0
  397. package/dist/public-surface/generated-manifest.d.ts.map +1 -0
  398. package/dist/public-surface/source.d.ts +437 -0
  399. package/dist/public-surface/source.d.ts.map +1 -0
  400. package/dist/relay/protocol.d.ts +108 -4
  401. package/dist/relay/protocol.d.ts.map +1 -1
  402. package/dist/relay/relay-endpoints.d.ts +21 -0
  403. package/dist/relay/relay-endpoints.d.ts.map +1 -1
  404. package/dist/relay/relay-server.d.ts +32 -1
  405. package/dist/relay/relay-server.d.ts.map +1 -1
  406. package/dist/relay/relay-types.d.ts +3 -0
  407. package/dist/relay/relay-types.d.ts.map +1 -1
  408. package/dist/skills/bundled-skill-directories.d.ts +8 -0
  409. package/dist/skills/bundled-skill-directories.d.ts.map +1 -0
  410. package/dist/skills/skill-loader.d.ts +9 -1
  411. package/dist/skills/skill-loader.d.ts.map +1 -1
  412. package/dist/skills/skill-loader.js +7 -0
  413. package/dist/skills/skill-loader.js.map +1 -0
  414. package/dist/skills/skill-nudge.d.ts.map +1 -1
  415. package/dist/skills/types.d.ts +31 -0
  416. package/dist/skills/types.d.ts.map +1 -1
  417. package/dist/snapshot/ops-snapshot.d.ts +1 -1
  418. package/dist/snapshot/ops-snapshot.d.ts.map +1 -1
  419. package/dist/snapshot/refs.d.ts +6 -1
  420. package/dist/snapshot/refs.d.ts.map +1 -1
  421. package/dist/snapshot/snapshotter.d.ts.map +1 -1
  422. package/dist/tools/annotate.d.ts.map +1 -1
  423. package/dist/tools/canvas.d.ts +4 -0
  424. package/dist/tools/canvas.d.ts.map +1 -0
  425. package/dist/tools/check.d.ts.map +1 -1
  426. package/dist/tools/click.d.ts.map +1 -1
  427. package/dist/tools/clone_component.d.ts.map +1 -1
  428. package/dist/tools/clone_page.d.ts.map +1 -1
  429. package/dist/tools/connect.d.ts.map +1 -1
  430. package/dist/tools/deps.d.ts +6 -0
  431. package/dist/tools/deps.d.ts.map +1 -1
  432. package/dist/tools/desktop-shared.d.ts +6 -0
  433. package/dist/tools/desktop-shared.d.ts.map +1 -0
  434. package/dist/tools/desktop_accessibility_snapshot.d.ts +4 -0
  435. package/dist/tools/desktop_accessibility_snapshot.d.ts.map +1 -0
  436. package/dist/tools/desktop_active_window.d.ts +4 -0
  437. package/dist/tools/desktop_active_window.d.ts.map +1 -0
  438. package/dist/tools/desktop_capture_desktop.d.ts +4 -0
  439. package/dist/tools/desktop_capture_desktop.d.ts.map +1 -0
  440. package/dist/tools/desktop_capture_window.d.ts +4 -0
  441. package/dist/tools/desktop_capture_window.d.ts.map +1 -0
  442. package/dist/tools/desktop_status.d.ts +4 -0
  443. package/dist/tools/desktop_status.d.ts.map +1 -0
  444. package/dist/tools/desktop_windows.d.ts +4 -0
  445. package/dist/tools/desktop_windows.d.ts.map +1 -0
  446. package/dist/tools/dialog.d.ts +4 -0
  447. package/dist/tools/dialog.d.ts.map +1 -0
  448. package/dist/tools/dom_get_html.d.ts.map +1 -1
  449. package/dist/tools/dom_get_text.d.ts.map +1 -1
  450. package/dist/tools/get_attr.d.ts.map +1 -1
  451. package/dist/tools/get_value.d.ts.map +1 -1
  452. package/dist/tools/goto.d.ts.map +1 -1
  453. package/dist/tools/hover.d.ts.map +1 -1
  454. package/dist/tools/index.d.ts +3 -0
  455. package/dist/tools/index.d.ts.map +1 -1
  456. package/dist/tools/is_checked.d.ts.map +1 -1
  457. package/dist/tools/is_enabled.d.ts.map +1 -1
  458. package/dist/tools/is_visible.d.ts.map +1 -1
  459. package/dist/tools/launch.d.ts.map +1 -1
  460. package/dist/tools/macro_resolve.d.ts.map +1 -1
  461. package/dist/tools/perf.d.ts.map +1 -1
  462. package/dist/tools/pointer_down.d.ts +4 -0
  463. package/dist/tools/pointer_down.d.ts.map +1 -0
  464. package/dist/tools/pointer_drag.d.ts +4 -0
  465. package/dist/tools/pointer_drag.d.ts.map +1 -0
  466. package/dist/tools/pointer_move.d.ts +4 -0
  467. package/dist/tools/pointer_move.d.ts.map +1 -0
  468. package/dist/tools/pointer_up.d.ts +4 -0
  469. package/dist/tools/pointer_up.d.ts.map +1 -0
  470. package/dist/tools/press.d.ts.map +1 -1
  471. package/dist/tools/product_video_run.d.ts.map +1 -1
  472. package/dist/tools/prompting_guide.d.ts.map +1 -1
  473. package/dist/tools/research_run.d.ts.map +1 -1
  474. package/dist/tools/response.d.ts +4 -1
  475. package/dist/tools/response.d.ts.map +1 -1
  476. package/dist/tools/review.d.ts +4 -0
  477. package/dist/tools/review.d.ts.map +1 -0
  478. package/dist/tools/screencast_start.d.ts +4 -0
  479. package/dist/tools/screencast_start.d.ts.map +1 -0
  480. package/dist/tools/screencast_stop.d.ts +4 -0
  481. package/dist/tools/screencast_stop.d.ts.map +1 -0
  482. package/dist/tools/screenshot.d.ts.map +1 -1
  483. package/dist/tools/scroll.d.ts.map +1 -1
  484. package/dist/tools/scroll_into_view.d.ts.map +1 -1
  485. package/dist/tools/select.d.ts.map +1 -1
  486. package/dist/tools/session_inspector.d.ts +4 -0
  487. package/dist/tools/session_inspector.d.ts.map +1 -0
  488. package/dist/tools/shopping_run.d.ts.map +1 -1
  489. package/dist/tools/skill_list.d.ts.map +1 -1
  490. package/dist/tools/skill_load.d.ts.map +1 -1
  491. package/dist/tools/snapshot.d.ts.map +1 -1
  492. package/dist/tools/type.d.ts.map +1 -1
  493. package/dist/tools/uncheck.d.ts.map +1 -1
  494. package/dist/tools/upload.d.ts +4 -0
  495. package/dist/tools/upload.d.ts.map +1 -0
  496. package/dist/tools/wait.d.ts.map +1 -1
  497. package/dist/tools/workflow-runtime.d.ts +4 -2
  498. package/dist/tools/workflow-runtime.d.ts.map +1 -1
  499. package/dist/utils/package-assets.d.ts +4 -0
  500. package/dist/utils/package-assets.d.ts.map +1 -0
  501. package/extension/canvas.html +1006 -0
  502. package/extension/dist/annotate-content.css +15 -6
  503. package/extension/dist/annotate-content.js +175 -35
  504. package/extension/dist/annotation-payload.js +199 -0
  505. package/extension/dist/background.js +544 -69
  506. package/extension/dist/canvas/canvas-runtime.js +1490 -0
  507. package/extension/dist/canvas/model.js +341 -0
  508. package/extension/dist/canvas/viewport-fit.js +67 -0
  509. package/extension/dist/canvas-page.js +3609 -0
  510. package/extension/dist/ops/dom-bridge.js +255 -3
  511. package/extension/dist/ops/ops-runtime.js +3324 -301
  512. package/extension/dist/ops/ops-session-store.js +97 -112
  513. package/extension/dist/ops/snapshot-builder.js +2 -2
  514. package/extension/dist/ops/snapshot-shared.js +2 -2
  515. package/extension/dist/ops/target-session-coordinator.js +159 -0
  516. package/extension/dist/popup.js +201 -42
  517. package/extension/dist/services/CDPRouter.js +1567 -63
  518. package/extension/dist/services/ConnectionManager.js +453 -78
  519. package/extension/dist/services/RelayClient.js +79 -30
  520. package/extension/dist/services/TabManager.js +118 -22
  521. package/extension/dist/services/TargetSessionMap.js +127 -3
  522. package/extension/dist/services/attach-errors.js +20 -0
  523. package/extension/dist/services/cdp-router-commands.js +135 -8
  524. package/extension/dist/services/url-restrictions.js +9 -13
  525. package/extension/dist/types.js +2 -0
  526. package/extension/manifest.json +2 -2
  527. package/extension/popup.html +59 -6
  528. package/package.json +19 -9
  529. package/skills/AGENTS.md +8 -4
  530. package/skills/opendevbrowser-best-practices/SKILL.md +183 -6
  531. package/skills/opendevbrowser-best-practices/artifacts/browser-agent-known-issues-matrix.md +1 -0
  532. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +141 -0
  533. package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +129 -19
  534. package/skills/opendevbrowser-best-practices/artifacts/parity-gates.md +9 -2
  535. package/skills/opendevbrowser-best-practices/artifacts/provider-workflows.md +6 -0
  536. package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +58 -0
  537. package/skills/opendevbrowser-best-practices/assets/templates/canvas-blocker-checklist.json +70 -0
  538. package/skills/opendevbrowser-best-practices/assets/templates/canvas-feedback-eval.json +73 -0
  539. package/skills/opendevbrowser-best-practices/assets/templates/canvas-generation-plan.v1.json +67 -0
  540. package/skills/opendevbrowser-best-practices/assets/templates/canvas-handshake-example.json +126 -0
  541. package/skills/opendevbrowser-best-practices/assets/templates/robustness-checklist.json +57 -0
  542. package/skills/opendevbrowser-best-practices/assets/templates/skill-runtime-pack-matrix.json +674 -0
  543. package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +12 -3
  544. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +107 -12
  545. package/skills/opendevbrowser-best-practices/scripts/resolve-odb-cli.sh +100 -0
  546. package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +83 -1
  547. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +365 -84
  548. package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +208 -0
  549. package/skills/opendevbrowser-continuity-ledger/SKILL.md +14 -1
  550. package/skills/opendevbrowser-continuity-ledger/scripts/validate-skill-assets.sh +61 -0
  551. package/skills/opendevbrowser-data-extraction/SKILL.md +6 -0
  552. package/skills/opendevbrowser-data-extraction/scripts/validate-skill-assets.sh +112 -0
  553. package/skills/opendevbrowser-design-agent/SKILL.md +275 -0
  554. package/skills/opendevbrowser-design-agent/artifacts/app-shell-and-state-wiring.md +84 -0
  555. package/skills/opendevbrowser-design-agent/artifacts/async-search-state-ownership.md +58 -0
  556. package/skills/opendevbrowser-design-agent/artifacts/component-pattern-index.md +130 -0
  557. package/skills/opendevbrowser-design-agent/artifacts/design-contract-playbook.md +157 -0
  558. package/skills/opendevbrowser-design-agent/artifacts/design-release-gate.md +40 -0
  559. package/skills/opendevbrowser-design-agent/artifacts/design-workflows.md +153 -0
  560. package/skills/opendevbrowser-design-agent/artifacts/existing-surface-adaptation.md +56 -0
  561. package/skills/opendevbrowser-design-agent/artifacts/external-pattern-synthesis.md +103 -0
  562. package/skills/opendevbrowser-design-agent/artifacts/frontend-evaluation-rubric.md +61 -0
  563. package/skills/opendevbrowser-design-agent/artifacts/implementation-anti-patterns.md +163 -0
  564. package/skills/opendevbrowser-design-agent/artifacts/isolated-preview-validation.md +68 -0
  565. package/skills/opendevbrowser-design-agent/artifacts/loading-and-feedback-surfaces.md +56 -0
  566. package/skills/opendevbrowser-design-agent/artifacts/opendevbrowser-ui-example-map.md +44 -0
  567. package/skills/opendevbrowser-design-agent/artifacts/performance-audit-playbook.md +70 -0
  568. package/skills/opendevbrowser-design-agent/artifacts/research-harvest-workflow.md +81 -0
  569. package/skills/opendevbrowser-design-agent/artifacts/scroll-reveal-surface-planning.md +64 -0
  570. package/skills/opendevbrowser-design-agent/artifacts/state-ownership-matrix.md +36 -0
  571. package/skills/opendevbrowser-design-agent/artifacts/theming-and-token-ownership.md +43 -0
  572. package/skills/opendevbrowser-design-agent/assets/templates/canvas-generation-plan.design.v1.json +58 -0
  573. package/skills/opendevbrowser-design-agent/assets/templates/design-audit-report.v1.md +34 -0
  574. package/skills/opendevbrowser-design-agent/assets/templates/design-brief.v1.md +40 -0
  575. package/skills/opendevbrowser-design-agent/assets/templates/design-contract.v1.json +226 -0
  576. package/skills/opendevbrowser-design-agent/assets/templates/design-release-gate.v1.json +35 -0
  577. package/skills/opendevbrowser-design-agent/assets/templates/design-review-checklist.json +57 -0
  578. package/skills/opendevbrowser-design-agent/assets/templates/real-surface-design-matrix.json +32 -0
  579. package/skills/opendevbrowser-design-agent/assets/templates/reference-pattern-board.v1.json +31 -0
  580. package/skills/opendevbrowser-design-agent/scripts/design-workflow.sh +171 -0
  581. package/skills/opendevbrowser-design-agent/scripts/extract-canvas-plan.sh +56 -0
  582. package/skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh +223 -0
  583. package/skills/opendevbrowser-form-testing/SKILL.md +19 -3
  584. package/skills/opendevbrowser-form-testing/artifacts/form-workflows.md +5 -4
  585. package/skills/opendevbrowser-form-testing/assets/templates/challenge-decision-tree.json +2 -0
  586. package/skills/opendevbrowser-form-testing/scripts/validate-skill-assets.sh +109 -0
  587. package/skills/opendevbrowser-login-automation/SKILL.md +21 -3
  588. package/skills/opendevbrowser-login-automation/artifacts/login-workflows.md +5 -4
  589. package/skills/opendevbrowser-login-automation/assets/templates/auth-signals.json +5 -0
  590. package/skills/opendevbrowser-login-automation/assets/templates/login-scenario-matrix.json +3 -2
  591. package/skills/opendevbrowser-login-automation/scripts/run-login-workflow.sh +17 -1
  592. package/skills/opendevbrowser-login-automation/scripts/validate-skill-assets.sh +133 -0
  593. package/skills/opendevbrowser-product-presentation-asset/SKILL.md +23 -11
  594. package/skills/opendevbrowser-product-presentation-asset/artifacts/asset-pack-assembly.md +5 -3
  595. package/skills/opendevbrowser-product-presentation-asset/assets/templates/shot-list.md +2 -0
  596. package/skills/opendevbrowser-product-presentation-asset/assets/templates/video-assembly.md +3 -2
  597. package/skills/opendevbrowser-product-presentation-asset/scripts/capture-screenshots.sh +5 -1
  598. package/skills/opendevbrowser-product-presentation-asset/scripts/collect-product.sh +6 -2
  599. package/skills/opendevbrowser-product-presentation-asset/scripts/download-images.sh +5 -1
  600. package/skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh +20 -7
  601. package/skills/opendevbrowser-product-presentation-asset/scripts/validate-skill-assets.sh +39 -0
  602. package/skills/opendevbrowser-product-presentation-asset/scripts/write-manifest.sh +5 -1
  603. package/skills/opendevbrowser-research/SKILL.md +14 -6
  604. package/skills/opendevbrowser-research/scripts/render-output.sh +5 -1
  605. package/skills/opendevbrowser-research/scripts/run-research.sh +5 -1
  606. package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +45 -0
  607. package/skills/opendevbrowser-research/scripts/write-artifacts.sh +5 -1
  608. package/skills/opendevbrowser-shopping/SKILL.md +20 -1
  609. package/skills/opendevbrowser-shopping/scripts/normalize-offers.sh +6 -2
  610. package/skills/opendevbrowser-shopping/scripts/run-deal-hunt.sh +5 -1
  611. package/skills/opendevbrowser-shopping/scripts/run-shopping.sh +5 -1
  612. package/skills/opendevbrowser-shopping/scripts/validate-skill-assets.sh +54 -0
  613. package/dist/chunk-ST7CO5FA.js +0 -18668
  614. package/dist/chunk-ST7CO5FA.js.map +0 -1
  615. /package/dist/{chunk-7W3SPXIB.js.map → chunk-FUSXMW3G.js.map} +0 -0
  616. /package/dist/{macros-NUBRM44Y.js.map → macros-ND2M7LWU.js.map} +0 -0
@@ -29,6 +29,20 @@ const logInfo = (message) => {
29
29
  const logWarn = (message) => {
30
30
  console.warn(`[opendevbrowser] ${message}`);
31
31
  };
32
+ const getTrackedTabUrl = (tab) => {
33
+ if (!tab) {
34
+ return undefined;
35
+ }
36
+ const pendingUrl = typeof tab.pendingUrl === "string" && tab.pendingUrl.length > 0 ? tab.pendingUrl : undefined;
37
+ const currentUrl = typeof tab.url === "string" && tab.url.length > 0 ? tab.url : undefined;
38
+ return pendingUrl ?? currentUrl;
39
+ };
40
+ const getTrackedTabTitle = (tab) => {
41
+ if (!tab || tab.status === "loading") {
42
+ return undefined;
43
+ }
44
+ return typeof tab.title === "string" && tab.title.length > 0 ? tab.title : undefined;
45
+ };
32
46
  const RECONNECT_INITIAL_DELAY_MS = 12_000;
33
47
  const RECONNECT_MAX_DELAY_MS = 30_000;
34
48
  export class ConnectionManager {
@@ -55,8 +69,11 @@ export class ConnectionManager {
55
69
  connectPromise = null;
56
70
  annotationHandler = null;
57
71
  opsHandler = null;
72
+ canvasHandler = null;
58
73
  heartbeatTimer = null;
59
74
  heartbeatInFlight = false;
75
+ handshakeRefreshQueued = false;
76
+ handshakeRefreshPromise = null;
60
77
  heartbeatIntervalMs = 25_000;
61
78
  heartbeatTimeoutMs = 2_000;
62
79
  constructor() {
@@ -91,6 +108,9 @@ export class ConnectionManager {
91
108
  onOpsMessage(handler) {
92
109
  this.opsHandler = handler;
93
110
  }
111
+ onCanvasMessage(handler) {
112
+ this.canvasHandler = handler;
113
+ }
94
114
  sendAnnotationResponse(response) {
95
115
  if (!this.relay)
96
116
  return;
@@ -121,6 +141,16 @@ export class ConnectionManager {
121
141
  logError("relay.send_ops_message", error, { code: "relay_send_failed" });
122
142
  }
123
143
  }
144
+ sendCanvasMessage(message) {
145
+ if (!this.relay)
146
+ return;
147
+ try {
148
+ this.relay.sendCanvasMessage(message);
149
+ }
150
+ catch (error) {
151
+ logError("relay.send_canvas_message", error, { code: "relay_send_failed" });
152
+ }
153
+ }
124
154
  getCdpRouter() {
125
155
  return this.cdp;
126
156
  }
@@ -129,13 +159,82 @@ export class ConnectionManager {
129
159
  return null;
130
160
  }
131
161
  try {
132
- return await this.relay.sendHealthCheck();
162
+ const health = await this.relay.sendHealthCheck();
163
+ if (health.extensionConnected && !health.extensionHandshakeComplete) {
164
+ this.relayNotice = "Extension websocket is connected but the daemon-extension handshake is unhealthy. Re-establishing a clean handshake.";
165
+ this.refreshHandshake();
166
+ }
167
+ return health;
133
168
  }
134
169
  catch (error) {
135
170
  logError("relay.health_check", error, { code: "relay_health_failed" });
136
171
  return null;
137
172
  }
138
173
  }
174
+ async sendAnnotationCommand(command, timeoutMs = 5000) {
175
+ const socket = new WebSocket(this.buildAnnotationUrl());
176
+ let settled = false;
177
+ return await new Promise((resolve, reject) => {
178
+ const timeoutId = setTimeout(() => {
179
+ finish(() => reject(new Error("Annotation relay request timed out")));
180
+ }, timeoutMs);
181
+ const finish = (callback) => {
182
+ if (settled) {
183
+ return;
184
+ }
185
+ settled = true;
186
+ clearTimeout(timeoutId);
187
+ try {
188
+ if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
189
+ socket.close(1000, "annotation-command-complete");
190
+ }
191
+ }
192
+ catch {
193
+ // Ignore socket close failures during cleanup.
194
+ }
195
+ callback();
196
+ };
197
+ socket.addEventListener("open", () => {
198
+ try {
199
+ socket.send(JSON.stringify({
200
+ type: "annotationCommand",
201
+ payload: command
202
+ }));
203
+ }
204
+ catch (error) {
205
+ finish(() => reject(error instanceof Error ? error : new Error("Annotation relay send failed")));
206
+ }
207
+ }, { once: true });
208
+ socket.addEventListener("message", (event) => {
209
+ if (typeof event.data !== "string") {
210
+ return;
211
+ }
212
+ try {
213
+ const message = JSON.parse(event.data);
214
+ if (message.type !== "annotationResponse") {
215
+ return;
216
+ }
217
+ const payload = message.payload;
218
+ if (!isAnnotationResponse(payload) || payload.requestId !== command.requestId) {
219
+ return;
220
+ }
221
+ finish(() => resolve(payload));
222
+ }
223
+ catch {
224
+ // Ignore malformed one-off annotation responses.
225
+ }
226
+ });
227
+ socket.addEventListener("error", () => {
228
+ finish(() => reject(new Error("Annotation relay unavailable")));
229
+ }, { once: true });
230
+ socket.addEventListener("close", () => {
231
+ if (settled) {
232
+ return;
233
+ }
234
+ finish(() => reject(new Error("Annotation relay closed")));
235
+ }, { once: true });
236
+ });
237
+ }
139
238
  async connect() {
140
239
  if (this.connectPromise) {
141
240
  return await this.connectPromise;
@@ -179,6 +278,7 @@ export class ConnectionManager {
179
278
  this.shouldReconnect = false;
180
279
  this.clearReconnectTimer();
181
280
  this.stopHeartbeat();
281
+ this.handshakeRefreshQueued = false;
182
282
  try {
183
283
  if (this.relay) {
184
284
  this.relay.disconnect();
@@ -214,6 +314,38 @@ export class ConnectionManager {
214
314
  logError(context, error, { code: "relay_send_failed" });
215
315
  }
216
316
  }
317
+ async getFirstHttpFallbackTab(currentTabId) {
318
+ const fallbackTab = await this.tabs.getFirstAttachableTab(currentTabId);
319
+ if (!fallbackTab || typeof fallbackTab.id !== "number" || !fallbackTab.url) {
320
+ return null;
321
+ }
322
+ logInfo("Falling back to first http(s) tab.");
323
+ return fallbackTab;
324
+ }
325
+ async bootstrapRelayAttachTab() {
326
+ try {
327
+ const fallbackTab = await this.tabs.createTab("about:blank", true);
328
+ if (fallbackTab && typeof fallbackTab.id === "number") {
329
+ logInfo("Bootstrapping a fresh browser tab for relay attach.");
330
+ return fallbackTab;
331
+ }
332
+ }
333
+ catch {
334
+ // Ignore tab creation failures and let the caller surface the original error.
335
+ }
336
+ return null;
337
+ }
338
+ async resolveRelayAttachFallback(currentTabId) {
339
+ const httpTab = await this.getFirstHttpFallbackTab(currentTabId);
340
+ if (httpTab) {
341
+ return { tab: httpTab, allowBlankRelayFallback: false };
342
+ }
343
+ const blankTab = await this.bootstrapRelayAttachTab();
344
+ if (blankTab) {
345
+ return { tab: blankTab, allowBlankRelayFallback: true };
346
+ }
347
+ return { tab: null, allowBlankRelayFallback: false };
348
+ }
217
349
  startHeartbeat() {
218
350
  if (this.heartbeatTimer !== null) {
219
351
  return;
@@ -240,7 +372,15 @@ export class ConnectionManager {
240
372
  }
241
373
  this.heartbeatInFlight = true;
242
374
  try {
243
- await this.relay.sendPing(this.heartbeatTimeoutMs);
375
+ const health = await this.relay.sendPing(this.heartbeatTimeoutMs);
376
+ if (health.extensionConnected && !health.extensionHandshakeComplete) {
377
+ this.relayNotice = "Extension websocket is connected but the daemon-extension handshake is incomplete. Re-establishing a clean handshake.";
378
+ this.refreshHandshake();
379
+ return;
380
+ }
381
+ if (health.ok) {
382
+ this.relayNotice = null;
383
+ }
244
384
  }
245
385
  catch (error) {
246
386
  logError("relay.heartbeat", error, { code: "relay_heartbeat_failed" });
@@ -254,29 +394,35 @@ export class ConnectionManager {
254
394
  }
255
395
  async attachToActiveTab() {
256
396
  let tab = await this.tabs.getActiveTab();
397
+ let allowBlankRelayFallback = false;
398
+ let tabUrl = getTrackedTabUrl(tab);
257
399
  if (!tab || typeof tab.id !== "number") {
258
- this.trackedTab = null;
259
- this.setStatus("disconnected");
260
- logWarn("Active tab not found.");
261
- throw new ConnectionError("no_active_tab", "No active browser tab found. Focus a normal tab (not the popup) and retry.");
400
+ const fallback = await this.resolveRelayAttachFallback();
401
+ tab = fallback.tab;
402
+ allowBlankRelayFallback = fallback.allowBlankRelayFallback;
403
+ tabUrl = getTrackedTabUrl(tab);
404
+ if (!tab || typeof tab.id !== "number") {
405
+ this.trackedTab = null;
406
+ this.setStatus("disconnected");
407
+ logWarn("Active tab not found.");
408
+ throw new ConnectionError("no_active_tab", "No active browser page found. Focus the site tab or popup window you want to automate, not the extension popup, and retry.");
409
+ }
262
410
  }
263
- if (!tab.url) {
411
+ if (!tabUrl) {
264
412
  logWarn("Active tab URL missing.");
265
- const fallbackId = await this.tabs.getFirstHttpTabId();
266
- if (fallbackId && fallbackId !== tab.id) {
267
- const fallbackTab = await this.tabs.getTab(fallbackId);
268
- if (fallbackTab && typeof fallbackTab.id === "number" && fallbackTab.url) {
269
- logInfo("Falling back to first http(s) tab.");
270
- tab = fallbackTab;
271
- }
413
+ const fallback = await this.resolveRelayAttachFallback(tab.id);
414
+ if (fallback.tab) {
415
+ tab = fallback.tab;
416
+ allowBlankRelayFallback ||= fallback.allowBlankRelayFallback;
417
+ tabUrl = getTrackedTabUrl(tab);
272
418
  }
273
- if (!tab.url) {
419
+ if (!tabUrl) {
274
420
  throw new ConnectionError("tab_url_missing", "Active tab URL is unavailable. Reload the tab and retry.");
275
421
  }
276
422
  }
277
423
  let parsedUrl = null;
278
424
  try {
279
- parsedUrl = new URL(tab.url);
425
+ parsedUrl = tabUrl ? new URL(tabUrl) : null;
280
426
  }
281
427
  catch (error) {
282
428
  logError("connection.parse_tab_url", error, { code: "tab_url_parse_failed" });
@@ -284,54 +430,48 @@ export class ConnectionManager {
284
430
  }
285
431
  if (!parsedUrl) {
286
432
  logWarn("Active tab URL is invalid.");
287
- const fallbackId = await this.tabs.getFirstHttpTabId();
288
- if (fallbackId && fallbackId !== tab.id) {
289
- const fallbackTab = await this.tabs.getTab(fallbackId);
290
- if (fallbackTab && typeof fallbackTab.id === "number" && fallbackTab.url) {
291
- logInfo("Falling back to first http(s) tab.");
292
- try {
293
- parsedUrl = new URL(fallbackTab.url);
294
- tab = fallbackTab;
295
- }
296
- catch {
297
- parsedUrl = null;
298
- }
433
+ const fallback = await this.resolveRelayAttachFallback(tab.id);
434
+ if (fallback.tab) {
435
+ tab = fallback.tab;
436
+ allowBlankRelayFallback ||= fallback.allowBlankRelayFallback;
437
+ tabUrl = getTrackedTabUrl(tab);
438
+ try {
439
+ parsedUrl = tabUrl ? new URL(tabUrl) : null;
440
+ }
441
+ catch {
442
+ parsedUrl = null;
299
443
  }
300
444
  }
301
445
  if (!parsedUrl) {
302
- throw new ConnectionError("tab_url_restricted", "Active tab URL is unsupported. Focus a normal http(s) tab and retry.");
446
+ throw new ConnectionError("tab_url_restricted", "Active browser page URL is unsupported. Focus an http(s) page or site popup window, not the extension popup, and retry.");
303
447
  }
304
448
  }
305
449
  const restrictionMessage = getRestrictionMessage(parsedUrl);
306
450
  if (restrictionMessage) {
307
- logWarn(`Active tab blocked: ${summarizeProtocol(tab.url)} scheme.`);
308
- const fallbackId = await this.tabs.getFirstHttpTabId();
309
- if (fallbackId && fallbackId !== tab.id) {
310
- const fallbackTab = await this.tabs.getTab(fallbackId);
311
- if (fallbackTab && typeof fallbackTab.id === "number" && fallbackTab.url) {
312
- try {
313
- const fallbackUrl = new URL(fallbackTab.url);
314
- const fallbackRestriction = getRestrictionMessage(fallbackUrl);
315
- if (!fallbackRestriction) {
316
- logInfo("Falling back to first http(s) tab.");
317
- tab = fallbackTab;
318
- parsedUrl = fallbackUrl;
319
- }
320
- }
321
- catch {
322
- // Ignore invalid fallback URL.
323
- }
451
+ logWarn(`Active tab blocked: ${summarizeProtocol(tabUrl)} scheme.`);
452
+ const fallback = await this.resolveRelayAttachFallback(tab.id);
453
+ if (fallback.tab) {
454
+ tab = fallback.tab;
455
+ allowBlankRelayFallback ||= fallback.allowBlankRelayFallback;
456
+ tabUrl = getTrackedTabUrl(tab);
457
+ try {
458
+ parsedUrl = tabUrl ? new URL(tabUrl) : null;
459
+ }
460
+ catch {
461
+ parsedUrl = null;
324
462
  }
325
463
  }
326
- if (restrictionMessage && getRestrictionMessage(parsedUrl)) {
327
- throw new ConnectionError("tab_url_restricted", restrictionMessage);
464
+ if (restrictionMessage && (!parsedUrl || getRestrictionMessage(parsedUrl))) {
465
+ if (!allowBlankRelayFallback) {
466
+ throw new ConnectionError("tab_url_restricted", restrictionMessage);
467
+ }
328
468
  }
329
469
  }
330
470
  const tabId = tab.id;
331
471
  if (typeof tabId !== "number") {
332
472
  this.trackedTab = null;
333
473
  this.setStatus("disconnected");
334
- throw new ConnectionError("no_active_tab", "No active browser tab found. Focus a normal tab (not the popup) and retry.");
474
+ throw new ConnectionError("no_active_tab", "No active browser page found. Focus the site tab or popup window you want to automate, not the extension popup, and retry.");
335
475
  }
336
476
  logInfo("Active tab resolved.");
337
477
  try {
@@ -346,12 +486,7 @@ export class ConnectionManager {
346
486
  : "Debugger attach failed. Close DevTools for the tab and retry.";
347
487
  throw new ConnectionError("debugger_attach_failed", message);
348
488
  }
349
- this.trackedTab = {
350
- id: tabId,
351
- url: tab.url ?? undefined,
352
- title: tab.title ?? undefined,
353
- groupId: typeof tab.groupId === "number" ? tab.groupId : undefined
354
- };
489
+ this.trackedTab = this.toTrackedTab(tab, null);
355
490
  }
356
491
  async connectRelay() {
357
492
  if (!this.trackedTab) {
@@ -364,12 +499,18 @@ export class ConnectionManager {
364
499
  this.handleCdpDetach({ reason: "cdp_command_failed" });
365
500
  });
366
501
  },
502
+ onCdpControl: (message) => {
503
+ this.handleCdpControl(message);
504
+ },
367
505
  onAnnotationCommand: (command) => {
368
506
  this.annotationHandler?.(command);
369
507
  },
370
508
  onOpsMessage: (message) => {
371
509
  this.opsHandler?.(message);
372
510
  },
511
+ onCanvasMessage: (message) => {
512
+ this.canvasHandler?.(message);
513
+ },
373
514
  onClose: (detail) => {
374
515
  this.handleRelayClose(detail);
375
516
  }
@@ -403,6 +544,10 @@ export class ConnectionManager {
403
544
  if (!mismatch) {
404
545
  this.persistRelayIdentity(ack.payload.relayPort, this.relayInstanceId, this.relayEpoch);
405
546
  }
547
+ const handshakeHealthy = await this.verifyHandshakeHealth(relay, "connect");
548
+ if (!handshakeHealthy) {
549
+ return;
550
+ }
406
551
  logInfo("Relay WebSocket connected.");
407
552
  this.setStatus("connected");
408
553
  this.startHeartbeat();
@@ -421,6 +566,7 @@ export class ConnectionManager {
421
566
  handleRelayClose(detail) {
422
567
  this.stopHeartbeat();
423
568
  this.relay = null;
569
+ this.cdp.markClientClosed();
424
570
  if (detail && (detail.code === 1008 || detail.reason?.includes("Invalid pairing token"))) {
425
571
  this.clearStoredPairingToken();
426
572
  }
@@ -448,6 +594,10 @@ export class ConnectionManager {
448
594
  if (this.cdp.getAttachedTabIds().length > 0) {
449
595
  return;
450
596
  }
597
+ if (detail?.reason === "manual_disconnect") {
598
+ void this.recoverFromManualDetach(detail);
599
+ return;
600
+ }
451
601
  this.setStatus("disconnected");
452
602
  if (this.relay?.isConnected()) {
453
603
  this.relay.disconnect();
@@ -455,12 +605,49 @@ export class ConnectionManager {
455
605
  }
456
606
  this.scheduleReconnect();
457
607
  }
608
+ async recoverFromManualDetach(detail) {
609
+ try {
610
+ const preferredTabId = typeof detail?.tabId === "number" ? detail.tabId : this.trackedTab?.id ?? null;
611
+ if (typeof preferredTabId === "number") {
612
+ await this.cdp.attach(preferredTabId);
613
+ const recoveredTabId = this.cdp.getPrimaryTabId() ?? preferredTabId;
614
+ await this.refreshTrackedTab(recoveredTabId, { preserveCurrentOnRestricted: true });
615
+ }
616
+ else {
617
+ await this.attachToActiveTab();
618
+ }
619
+ if (!this.relay?.isConnected()) {
620
+ this.scheduleReconnect();
621
+ return;
622
+ }
623
+ this.setStatus("connected");
624
+ this.refreshHandshake();
625
+ }
626
+ catch (error) {
627
+ logError("connection.manual_detach_recover", error, { code: "tracked_tab_refresh_failed" });
628
+ this.setStatus("disconnected");
629
+ if (this.relay?.isConnected()) {
630
+ this.relay.disconnect();
631
+ return;
632
+ }
633
+ this.scheduleReconnect();
634
+ }
635
+ }
636
+ handleCdpControl(message) {
637
+ if (message.action !== "client_closed") {
638
+ return;
639
+ }
640
+ this.cdp.markClientClosed();
641
+ }
458
642
  scheduleReconnect() {
459
643
  if (this.reconnectTimer !== null) {
460
644
  return;
461
645
  }
462
646
  this.reconnectTimer = setTimeout(() => {
463
647
  this.reconnectTimer = null;
648
+ if (!this.shouldReconnect || this.status === "connected" || this.relay?.isConnected()) {
649
+ return;
650
+ }
464
651
  this.reconnectAttempts += 1;
465
652
  this.reconnectDelayMs = Math.min(this.reconnectDelayMs * 2, this.maxReconnectDelayMs);
466
653
  this.reconnectRelay().catch((error) => {
@@ -470,7 +657,7 @@ export class ConnectionManager {
470
657
  }, this.reconnectDelayMs);
471
658
  }
472
659
  async reconnectRelay() {
473
- if (!this.shouldReconnect) {
660
+ if (!this.shouldReconnect || this.status === "connected" || this.relay?.isConnected()) {
474
661
  return;
475
662
  }
476
663
  const primaryId = this.cdp.getPrimaryTabId();
@@ -527,24 +714,59 @@ export class ConnectionManager {
527
714
  if (!this.trackedTab || this.trackedTab.id !== tabId) {
528
715
  return;
529
716
  }
530
- if (this.cdp.getAttachedTabIds().length <= 1) {
717
+ const attachedTabIds = this.cdp.getAttachedTabIds().filter((attachedId) => attachedId !== tabId);
718
+ if (attachedTabIds.length === 0) {
531
719
  this.disconnect().catch((error) => {
532
720
  logError("connection.tab_removed_disconnect", error, { code: "disconnect_failed" });
533
721
  });
722
+ return;
534
723
  }
724
+ const primaryTabId = this.cdp.getPrimaryTabId();
725
+ const nextTrackedTabId = primaryTabId && primaryTabId !== tabId
726
+ ? primaryTabId
727
+ : attachedTabIds[0] ?? null;
728
+ if (!nextTrackedTabId) {
729
+ this.disconnect().catch((error) => {
730
+ logError("connection.tab_removed_disconnect", error, { code: "disconnect_failed" });
731
+ });
732
+ return;
733
+ }
734
+ this.refreshTrackedTab(nextTrackedTabId, { preserveCurrentOnRestricted: true })
735
+ .then(() => {
736
+ this.refreshHandshake();
737
+ })
738
+ .catch((error) => {
739
+ logError("connection.tab_removed_refresh", error, { code: "tracked_tab_refresh_failed" });
740
+ });
535
741
  };
536
742
  handleTabUpdated = (_tabId, _changeInfo, tab) => {
537
- if (!this.trackedTab || tab.id !== this.trackedTab.id) {
743
+ const updatedTabId = typeof tab.id === "number" ? tab.id : null;
744
+ if (updatedTabId === null) {
538
745
  return;
539
746
  }
540
- this.trackedTab = {
541
- id: tab.id,
542
- url: tab.url ?? this.trackedTab.url,
543
- title: tab.title ?? this.trackedTab.title,
544
- groupId: typeof tab.groupId === "number" ? tab.groupId : this.trackedTab.groupId
545
- };
747
+ const trackedTabId = this.trackedTab?.id ?? null;
748
+ const primaryTabId = this.cdp.getPrimaryTabId();
749
+ if (trackedTabId !== updatedTabId && primaryTabId !== updatedTabId) {
750
+ return;
751
+ }
752
+ if (trackedTabId !== updatedTabId) {
753
+ if (!this.isRestrictedTab(tab)) {
754
+ this.setTrackedTab(tab);
755
+ this.refreshHandshake();
756
+ return;
757
+ }
758
+ this.refreshTrackedTab(updatedTabId, { preserveCurrentOnRestricted: true })
759
+ .then(() => {
760
+ this.refreshHandshake();
761
+ })
762
+ .catch((error) => {
763
+ logError("connection.tab_updated_refresh", error, { code: "tracked_tab_refresh_failed" });
764
+ });
765
+ return;
766
+ }
767
+ this.setTrackedTab(tab);
546
768
  if (this.relay?.isConnected()) {
547
- this.safeRelaySend(() => this.relay?.sendHandshake(this.buildHandshake()), "relay.send_handshake");
769
+ this.refreshHandshake();
548
770
  }
549
771
  };
550
772
  async loadSettings() {
@@ -567,7 +789,7 @@ export class ConnectionManager {
567
789
  }
568
790
  return {
569
791
  code: "unknown",
570
- message: "Connection failed. Focus a normal tab and retry."
792
+ message: "Connection failed. Focus the site tab or popup window you want to automate, not the extension popup, and retry."
571
793
  };
572
794
  }
573
795
  updatePairingToken(value) {
@@ -649,9 +871,9 @@ export class ConnectionManager {
649
871
  this.clearStoredRelayIdentity();
650
872
  this.clearStoredPairingToken(false);
651
873
  this.relayNotice = instanceMismatch
652
- ? "Relay instance changed. Re-pair and reconnect."
653
- : "Relay restarted. Re-pair and reconnect.";
654
- this.safeRelaySend(() => this.relay?.sendHandshake(this.buildHandshake()), "relay.rehandshake");
874
+ ? "Relay instance changed. Re-establishing a clean daemon-extension handshake."
875
+ : "Relay restarted. Re-establishing a clean daemon-extension handshake.";
876
+ this.refreshHandshake();
655
877
  return true;
656
878
  }
657
879
  this.relayNotice = null;
@@ -665,6 +887,13 @@ export class ConnectionManager {
665
887
  buildRelayUrl() {
666
888
  return `ws://127.0.0.1:${this.relayPort}/extension`;
667
889
  }
890
+ buildAnnotationUrl() {
891
+ const port = this.relayConfirmedPort ?? this.relayPort;
892
+ const query = this.pairingEnabled && this.pairingToken
893
+ ? `?token=${encodeURIComponent(this.pairingToken)}`
894
+ : "";
895
+ return `ws://127.0.0.1:${port}/annotation${query}`;
896
+ }
668
897
  async refreshRelay() {
669
898
  if (this.status !== "connected")
670
899
  return;
@@ -673,26 +902,101 @@ export class ConnectionManager {
673
902
  }
674
903
  async handlePrimaryTabChange(tabId) {
675
904
  if (!tabId) {
905
+ const trackedTabId = this.trackedTab?.id;
906
+ if (this.shouldReconnect && !this.disconnecting && typeof trackedTabId === "number") {
907
+ const trackedTab = await this.tabs.getTab(trackedTabId);
908
+ if (trackedTab && typeof trackedTab.id === "number") {
909
+ await this.refreshTrackedTab(trackedTab.id, { preserveCurrentOnRestricted: true });
910
+ this.refreshHandshake();
911
+ return;
912
+ }
913
+ }
676
914
  this.trackedTab = null;
677
915
  if (this.relay?.isConnected()) {
678
916
  this.relay.disconnect();
679
917
  }
680
918
  return;
681
919
  }
682
- await this.refreshTrackedTab(tabId);
920
+ await this.refreshTrackedTab(tabId, { preserveCurrentOnRestricted: true });
683
921
  this.refreshHandshake();
684
922
  }
685
- async refreshTrackedTab(tabId) {
686
- const tab = await this.tabs.getTab(tabId);
923
+ isRestrictedTab(tab) {
924
+ const rawUrl = getTrackedTabUrl(tab);
925
+ if (!rawUrl) {
926
+ return true;
927
+ }
928
+ try {
929
+ return Boolean(getRestrictionMessage(new URL(rawUrl)));
930
+ }
931
+ catch {
932
+ return true;
933
+ }
934
+ }
935
+ async refreshTrackedTab(tabId, options) {
936
+ const previous = this.trackedTab;
937
+ let tab = await this.tabs.getTab(tabId);
938
+ if ((!tab || typeof tab.id !== "number") && options?.preserveCurrentOnRestricted && previous) {
939
+ this.trackedTab = previous;
940
+ return;
941
+ }
687
942
  if (!tab || typeof tab.id !== "number") {
688
943
  this.trackedTab = null;
689
944
  return;
690
945
  }
691
- this.trackedTab = {
692
- id: tab.id,
693
- url: tab.url ?? this.trackedTab?.url,
694
- title: tab.title ?? this.trackedTab?.title,
695
- groupId: typeof tab.groupId === "number" ? tab.groupId : this.trackedTab?.groupId
946
+ if (this.isRestrictedTab(tab)) {
947
+ const httpFallback = await this.getFirstHttpFallbackTab(tab.id);
948
+ if (httpFallback) {
949
+ tab = httpFallback;
950
+ }
951
+ else if (options?.preserveCurrentOnRestricted && previous) {
952
+ this.trackedTab = previous;
953
+ return;
954
+ }
955
+ else {
956
+ const blankFallback = await this.bootstrapRelayAttachTab();
957
+ if (blankFallback) {
958
+ tab = blankFallback;
959
+ }
960
+ else {
961
+ this.trackedTab = null;
962
+ return;
963
+ }
964
+ }
965
+ }
966
+ const nextTrackedTabId = tab.id;
967
+ if (typeof nextTrackedTabId !== "number") {
968
+ if (options?.preserveCurrentOnRestricted && previous) {
969
+ this.trackedTab = previous;
970
+ return;
971
+ }
972
+ this.trackedTab = null;
973
+ return;
974
+ }
975
+ this.setTrackedTab(tab);
976
+ }
977
+ setTrackedTab(tab) {
978
+ const tabId = typeof tab.id === "number" ? tab.id : null;
979
+ if (tabId === null) {
980
+ return;
981
+ }
982
+ this.trackedTab = this.toTrackedTab(tab, this.trackedTab);
983
+ }
984
+ toTrackedTab(tab, previous) {
985
+ const tabId = typeof tab.id === "number" ? tab.id : null;
986
+ if (tabId === null) {
987
+ throw new Error("Tracked tab id is missing");
988
+ }
989
+ const sameTab = previous?.id === tabId;
990
+ const url = getTrackedTabUrl(tab) ?? (sameTab ? previous?.url : undefined);
991
+ const title = getTrackedTabTitle(tab) ?? (sameTab ? previous?.title : undefined);
992
+ const groupId = typeof tab.groupId === "number"
993
+ ? tab.groupId
994
+ : (sameTab ? previous?.groupId : undefined);
995
+ return {
996
+ id: tabId,
997
+ ...(url ? { url } : {}),
998
+ ...(title ? { title } : {}),
999
+ ...(typeof groupId === "number" ? { groupId } : {})
696
1000
  };
697
1001
  }
698
1002
  clearReconnectTimer() {
@@ -701,10 +1005,81 @@ export class ConnectionManager {
701
1005
  this.reconnectTimer = null;
702
1006
  }
703
1007
  }
1008
+ async verifyHandshakeHealth(relay, source) {
1009
+ try {
1010
+ const health = await relay.sendPing(this.heartbeatTimeoutMs);
1011
+ if (health.extensionConnected && health.extensionHandshakeComplete) {
1012
+ if (this.relay === relay) {
1013
+ this.relayNotice = null;
1014
+ }
1015
+ return true;
1016
+ }
1017
+ if (this.relay === relay) {
1018
+ this.relayNotice = "Extension websocket is connected but the daemon-extension handshake is still incomplete. Retrying a clean handshake.";
1019
+ if (this.shouldReconnect && !this.disconnecting) {
1020
+ relay.disconnect();
1021
+ }
1022
+ }
1023
+ }
1024
+ catch (error) {
1025
+ logError(`relay.${source}_handshake_health`, error, { code: "relay_handshake_health_failed" });
1026
+ if (this.relay === relay) {
1027
+ this.relayNotice = "Failed to verify a clean daemon-extension handshake. Retrying the relay connection.";
1028
+ if (this.shouldReconnect && !this.disconnecting) {
1029
+ relay.disconnect();
1030
+ }
1031
+ }
1032
+ }
1033
+ return false;
1034
+ }
704
1035
  refreshHandshake() {
705
1036
  if (!this.trackedTab || !this.relay?.isConnected()) {
706
1037
  return;
707
1038
  }
708
- this.safeRelaySend(() => this.relay?.sendHandshake(this.buildHandshake()), "relay.send_handshake");
1039
+ this.handshakeRefreshQueued = true;
1040
+ if (this.handshakeRefreshPromise) {
1041
+ return;
1042
+ }
1043
+ const run = (async () => {
1044
+ while (this.handshakeRefreshQueued) {
1045
+ this.handshakeRefreshQueued = false;
1046
+ const relay = this.relay;
1047
+ if (!this.trackedTab || !relay || !relay.isConnected()) {
1048
+ return;
1049
+ }
1050
+ try {
1051
+ await relay.sendHandshake(this.buildHandshake());
1052
+ const handshakeHealthy = await this.verifyHandshakeHealth(relay, "refresh");
1053
+ if (!handshakeHealthy) {
1054
+ return;
1055
+ }
1056
+ }
1057
+ catch (error) {
1058
+ logError("relay.refresh_handshake", error, { code: "relay_handshake_refresh_failed" });
1059
+ if (this.relay === relay) {
1060
+ this.relayNotice = "Failed to re-establish a clean daemon-extension handshake. Open the extension popup, click Connect again, confirm `status --daemon` shows ext=on and handshake=on, then retry.";
1061
+ if (this.shouldReconnect && !this.disconnecting) {
1062
+ relay.disconnect();
1063
+ }
1064
+ }
1065
+ return;
1066
+ }
1067
+ }
1068
+ })();
1069
+ const refreshPromise = run.finally(() => {
1070
+ if (this.handshakeRefreshPromise === refreshPromise) {
1071
+ this.handshakeRefreshPromise = null;
1072
+ }
1073
+ });
1074
+ this.handshakeRefreshPromise = refreshPromise;
709
1075
  }
710
1076
  }
1077
+ const isAnnotationResponse = (value) => {
1078
+ if (!value || typeof value !== "object") {
1079
+ return false;
1080
+ }
1081
+ const record = value;
1082
+ return record.version === 1
1083
+ && typeof record.requestId === "string"
1084
+ && (record.status === "ok" || record.status === "cancelled" || record.status === "error");
1085
+ };