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
@@ -0,0 +1,1490 @@
1
+ import { CANVAS_PROTOCOL_VERSION, MAX_CANVAS_PAYLOAD_BYTES } from "../types.js";
2
+ import { logError } from "../logging.js";
3
+ import { TabManager } from "../services/TabManager.js";
4
+ import { TargetSessionCoordinator, createCoordinatorId } from "../ops/target-session-coordinator.js";
5
+ import { normalizeCanvasSessionSummary, normalizeCanvasTargetStateSummaries } from "./model.js";
6
+ import { DEFAULT_EDITOR_VIEWPORT } from "./viewport-fit.js";
7
+ const OVERLAY_STYLE = `
8
+ #opendevbrowser-canvas-style,
9
+ .opendevbrowser-canvas-highlight {
10
+ box-sizing: border-box;
11
+ }
12
+ .opendevbrowser-canvas-highlight {
13
+ outline: 2px solid #20d5c6 !important;
14
+ outline-offset: 3px !important;
15
+ }
16
+ .opendevbrowser-canvas-overlay {
17
+ position: fixed;
18
+ top: 16px;
19
+ right: 16px;
20
+ z-index: 2147483647;
21
+ max-width: 320px;
22
+ padding: 12px 14px;
23
+ border-radius: 14px;
24
+ border: 1px solid rgba(255,255,255,0.16);
25
+ background: rgba(7,17,29,0.92);
26
+ color: #f3f6fb;
27
+ font: 12px/1.4 "Segoe UI", sans-serif;
28
+ box-shadow: 0 18px 40px rgba(0,0,0,0.3);
29
+ }
30
+ .opendevbrowser-canvas-overlay strong {
31
+ display: block;
32
+ margin-bottom: 4px;
33
+ }
34
+ `;
35
+ export class CanvasRuntime {
36
+ sendEnvelope;
37
+ registerOpsCanvasTarget;
38
+ unregisterOpsCanvasTarget;
39
+ encoder = new TextEncoder();
40
+ tabs = new TabManager();
41
+ sessions = new TargetSessionCoordinator();
42
+ overlaySessions = new Map();
43
+ pagePorts = new Map();
44
+ pendingPageActions = new Map();
45
+ constructor(options) {
46
+ this.sendEnvelope = options.send;
47
+ this.registerOpsCanvasTarget = options.registerOpsCanvasTarget;
48
+ this.unregisterOpsCanvasTarget = options.unregisterOpsCanvasTarget;
49
+ }
50
+ attachPort(port) {
51
+ if (port.name !== "canvas-page") {
52
+ return;
53
+ }
54
+ const tabId = port.sender?.tab?.id;
55
+ if (typeof tabId !== "number") {
56
+ port.disconnect();
57
+ return;
58
+ }
59
+ let ports = this.pagePorts.get(tabId);
60
+ if (!ports) {
61
+ ports = new Set();
62
+ this.pagePorts.set(tabId, ports);
63
+ }
64
+ ports.add(port);
65
+ port.onDisconnect.addListener(() => {
66
+ const current = this.pagePorts.get(tabId);
67
+ current?.delete(port);
68
+ if (current && current.size === 0) {
69
+ this.pagePorts.delete(tabId);
70
+ }
71
+ for (const [requestId, pending] of this.pendingPageActions.entries()) {
72
+ if (pending.tabId !== tabId) {
73
+ continue;
74
+ }
75
+ clearTimeout(pending.timeoutId);
76
+ pending.reject(new Error("Canvas page disconnected before action completed."));
77
+ this.pendingPageActions.delete(requestId);
78
+ }
79
+ });
80
+ port.onMessage.addListener((message) => {
81
+ const record = isRecord(message) ? message : null;
82
+ if (!record) {
83
+ return;
84
+ }
85
+ this.handlePagePortMessage(tabId, record);
86
+ });
87
+ this.postCanvasState(port, this.getPageStateByTabId(tabId), "canvas-page:init");
88
+ }
89
+ getPageStateByTargetId(targetId) {
90
+ try {
91
+ return this.getPageStateByTabId(parseTargetId(targetId));
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ async performPageAction(targetId, action, selector, timeoutMs = 2500) {
98
+ const tabId = parseTargetId(targetId);
99
+ const port = await this.waitForPagePort(tabId, timeoutMs);
100
+ return await new Promise((resolve, reject) => {
101
+ const requestId = crypto.randomUUID();
102
+ const timeoutId = setTimeout(() => {
103
+ this.pendingPageActions.delete(requestId);
104
+ reject(new Error("Canvas page action timed out."));
105
+ }, timeoutMs);
106
+ this.pendingPageActions.set(requestId, { tabId, resolve, reject, timeoutId });
107
+ try {
108
+ port.postMessage({
109
+ type: "canvas-page-action-request",
110
+ requestId,
111
+ selector: selector ?? null,
112
+ action
113
+ });
114
+ }
115
+ catch (error) {
116
+ clearTimeout(timeoutId);
117
+ this.pendingPageActions.delete(requestId);
118
+ reject(error instanceof Error ? error : new Error("Canvas page action failed."));
119
+ }
120
+ });
121
+ }
122
+ handleMessage(message) {
123
+ if (message.type === "canvas_hello") {
124
+ this.handleHello(message);
125
+ return;
126
+ }
127
+ if (message.type === "canvas_ping") {
128
+ this.handlePing(message);
129
+ return;
130
+ }
131
+ if (message.type === "canvas_event" && message.event === "canvas_client_disconnected") {
132
+ this.handleClientDisconnected(message);
133
+ return;
134
+ }
135
+ if (message.type === "canvas_request") {
136
+ void this.handleRequest(message).catch((error) => {
137
+ logError("canvas.handle_request", error, { code: "canvas_request_failed", extra: { command: message.command } });
138
+ this.sendError(message, normalizeCanvasError(error));
139
+ });
140
+ }
141
+ }
142
+ handleHello(message) {
143
+ if (message.version !== CANVAS_PROTOCOL_VERSION) {
144
+ this.sendError({ requestId: "canvas_hello", clientId: message.clientId, canvasSessionId: undefined }, {
145
+ code: "not_supported",
146
+ message: "Unsupported canvas protocol version.",
147
+ retryable: false,
148
+ details: { supported: [CANVAS_PROTOCOL_VERSION], received: message.version }
149
+ });
150
+ return;
151
+ }
152
+ const ack = {
153
+ type: "canvas_hello_ack",
154
+ version: CANVAS_PROTOCOL_VERSION,
155
+ clientId: message.clientId,
156
+ maxPayloadBytes: MAX_CANVAS_PAYLOAD_BYTES,
157
+ capabilities: [
158
+ "canvas.tab.open",
159
+ "canvas.tab.close",
160
+ "canvas.tab.sync",
161
+ "canvas.overlay.mount",
162
+ "canvas.overlay.unmount",
163
+ "canvas.overlay.select",
164
+ "canvas.overlay.sync"
165
+ ]
166
+ };
167
+ this.sendEnvelope(ack);
168
+ }
169
+ handlePing(message) {
170
+ const pong = {
171
+ type: "canvas_pong",
172
+ id: message.id,
173
+ clientId: message.clientId
174
+ };
175
+ this.sendEnvelope(pong);
176
+ }
177
+ handleClientDisconnected(message) {
178
+ const clientId = message.clientId;
179
+ if (!clientId) {
180
+ return;
181
+ }
182
+ for (const session of this.sessions.listOwnedBy(clientId)) {
183
+ void this.closeRuntimeSession(session, "client_disconnected");
184
+ }
185
+ for (const [sessionId, session] of this.overlaySessions.entries()) {
186
+ if (session.ownerClientId === clientId) {
187
+ this.overlaySessions.delete(sessionId);
188
+ }
189
+ }
190
+ }
191
+ handlePagePortMessage(tabId, message) {
192
+ if (message.type === "canvas-page-action-response") {
193
+ const pending = this.pendingPageActions.get(message.requestId);
194
+ if (!pending) {
195
+ return;
196
+ }
197
+ clearTimeout(pending.timeoutId);
198
+ this.pendingPageActions.delete(message.requestId);
199
+ if (message.ok) {
200
+ pending.resolve(message.value);
201
+ }
202
+ else {
203
+ pending.reject(new Error(message.error || "Canvas page action failed."));
204
+ }
205
+ return;
206
+ }
207
+ const session = this.sessions.getByTabId(tabId);
208
+ if (message.type === "canvas-page-ready" || message.type === "canvas-page-request-state") {
209
+ this.broadcastCanvasState(tabId, "canvas-page:init");
210
+ return;
211
+ }
212
+ if (!session) {
213
+ return;
214
+ }
215
+ if (message.type === "canvas-page-view-state") {
216
+ this.mergeEditorState(session, message.viewport, message.selection);
217
+ this.broadcastCanvasState(tabId, "canvas-page:update");
218
+ return;
219
+ }
220
+ if (message.type === "canvas-page-patch-request") {
221
+ if (!Array.isArray(message.patches) || message.patches.length === 0 || typeof message.baseRevision !== "number") {
222
+ return;
223
+ }
224
+ this.mergeEditorState(session, message.viewport, message.selection);
225
+ session.pendingMutation = true;
226
+ this.broadcastCanvasState(tabId, "canvas-page:update");
227
+ this.sendEvent({
228
+ type: "canvas_event",
229
+ clientId: session.ownerClientId,
230
+ canvasSessionId: session.id,
231
+ event: "canvas_patch_requested",
232
+ payload: {
233
+ targetId: session.designTabTargetId,
234
+ documentId: session.document.documentId,
235
+ baseRevision: message.baseRevision,
236
+ patches: message.patches,
237
+ selection: session.selection,
238
+ viewport: session.viewport
239
+ }
240
+ });
241
+ return;
242
+ }
243
+ if (message.type === "canvas-page-history-request") {
244
+ this.sendEvent({
245
+ type: "canvas_event",
246
+ clientId: session.ownerClientId,
247
+ canvasSessionId: session.id,
248
+ event: "canvas_history_requested",
249
+ payload: {
250
+ direction: message.direction
251
+ }
252
+ });
253
+ }
254
+ }
255
+ async handleRequest(message) {
256
+ switch (message.command) {
257
+ case "canvas.tab.open":
258
+ this.sendResponse(message, await this.openTab(message));
259
+ return;
260
+ case "canvas.tab.close":
261
+ this.sendResponse(message, await this.closeTab(message));
262
+ return;
263
+ case "canvas.tab.sync":
264
+ this.sendResponse(message, await this.syncTab(message));
265
+ return;
266
+ case "canvas.overlay.mount":
267
+ this.sendResponse(message, await this.mountOverlay(message));
268
+ return;
269
+ case "canvas.overlay.unmount":
270
+ this.sendResponse(message, await this.unmountOverlay(message));
271
+ return;
272
+ case "canvas.overlay.select":
273
+ this.sendResponse(message, await this.selectOverlay(message));
274
+ return;
275
+ case "canvas.overlay.sync":
276
+ this.sendResponse(message, await this.syncOverlay(message));
277
+ return;
278
+ default:
279
+ this.sendError(message, {
280
+ code: "not_supported",
281
+ message: `Unsupported canvas command: ${message.command}`,
282
+ retryable: false
283
+ });
284
+ }
285
+ }
286
+ async openTab(message) {
287
+ const record = requireRecord(message.payload, "payload");
288
+ const document = requireCanvasDocument(record.document);
289
+ const previewMode = requireEnum(record.previewMode, "previewMode", ["focused", "pinned", "background"]);
290
+ const tab = await this.createTab(chrome.runtime.getURL("canvas.html"), previewMode);
291
+ const tabId = requireTabId(tab);
292
+ const session = this.createOrReplaceSession(message, tabId, document, previewMode, record);
293
+ await this.syncOpsTargetRegistration(session).catch((error) => {
294
+ logError("canvas.sync_ops_target_registration", error, {
295
+ code: "canvas_ops_target_registration_failed",
296
+ extra: { canvasSessionId: session.id, targetId: session.designTabTargetId }
297
+ });
298
+ });
299
+ this.broadcastCanvasState(tabId, "canvas-page:init");
300
+ this.sendEvent({
301
+ type: "canvas_event",
302
+ clientId: message.clientId,
303
+ canvasSessionId: session.id,
304
+ event: "canvas_session_created",
305
+ payload: { tabId, targetId: session.designTabTargetId }
306
+ });
307
+ return {
308
+ targetId: session.designTabTargetId,
309
+ previewState: session.previewState
310
+ };
311
+ }
312
+ async closeTab(message) {
313
+ const record = requireRecord(message.payload, "payload");
314
+ const tabId = parseTargetId(requireString(record.targetId, "targetId"));
315
+ const targetId = formatTargetId(tabId);
316
+ let session = null;
317
+ try {
318
+ session = this.requireSessionForMessage(message, record);
319
+ }
320
+ catch (error) {
321
+ if (!isIgnorableCanvasCloseLookupError(error)) {
322
+ throw error;
323
+ }
324
+ }
325
+ if (!session) {
326
+ const browserSessionId = optionalString(record.browserSessionId)
327
+ ?? optionalString(isRecord(record.summary) ? record.summary.browserSessionId : undefined);
328
+ if (browserSessionId && this.unregisterOpsCanvasTarget) {
329
+ await Promise.resolve(this.unregisterOpsCanvasTarget(browserSessionId, targetId)).catch((error) => {
330
+ logError("canvas.unregister_ops_target", error, {
331
+ code: "canvas_ops_target_unregister_failed",
332
+ extra: { browserSessionId, targetId }
333
+ });
334
+ });
335
+ }
336
+ this.broadcastCanvasState(tabId, "canvas-page:closed", { reason: "target_closed" });
337
+ this.pagePorts.delete(tabId);
338
+ await this.tabs.closeTab(tabId).catch(() => undefined);
339
+ return {
340
+ ok: true,
341
+ targetId,
342
+ targetIds: [],
343
+ releasedTargetIds: [targetId],
344
+ previewState: "background"
345
+ };
346
+ }
347
+ this.broadcastCanvasState(tabId, "canvas-page:closed", { reason: "target_closed" });
348
+ session.designTabTargetId = null;
349
+ session.pendingMutation = false;
350
+ this.pagePorts.delete(tabId);
351
+ this.sessions.removeTarget(session.id, targetId);
352
+ const browserSessionId = readBrowserSessionId(session.summary);
353
+ if (browserSessionId && this.unregisterOpsCanvasTarget) {
354
+ await Promise.resolve(this.unregisterOpsCanvasTarget(browserSessionId, targetId)).catch((error) => {
355
+ logError("canvas.unregister_ops_target", error, {
356
+ code: "canvas_ops_target_unregister_failed",
357
+ extra: { browserSessionId, targetId }
358
+ });
359
+ });
360
+ }
361
+ await this.tabs.closeTab(tabId);
362
+ this.sendEvent({
363
+ type: "canvas_event",
364
+ clientId: session.ownerClientId,
365
+ canvasSessionId: session.id,
366
+ event: "canvas_target_closed",
367
+ payload: { targetId, tabId }
368
+ });
369
+ return {
370
+ ok: true,
371
+ targetId,
372
+ targetIds: [...session.targets.keys()],
373
+ releasedTargetIds: [targetId],
374
+ previewState: "background"
375
+ };
376
+ }
377
+ async syncTab(message) {
378
+ const session = this.requireSessionForMessage(message);
379
+ const record = requireRecord(message.payload, "payload");
380
+ const tabId = parseTargetId(requireString(record.targetId, "targetId"));
381
+ const existingTab = await this.tabs.getTab(tabId);
382
+ if (!existingTab) {
383
+ throw new Error(`Canvas target is unavailable: ${tabId}`);
384
+ }
385
+ const summary = normalizeCanvasSessionSummary(record.summary);
386
+ session.document = requireCanvasDocument(record.document);
387
+ session.documentRevision = optionalNumber(record.documentRevision);
388
+ session.html = requireRenderedHtml(record);
389
+ session.summary = summary;
390
+ session.previewTargets = normalizeCanvasTargetStateSummaries(record.targets ?? summary.targets);
391
+ session.overlayMounts = parseOverlayMounts(record.overlayMounts ?? summary.overlayMounts);
392
+ session.feedback = parseFeedbackEvents(record.feedback);
393
+ session.feedbackCursor = optionalString(record.feedbackCursor) ?? lastFeedbackCursor(session.feedback);
394
+ session.pendingMutation = false;
395
+ this.mergeEditorState(session, normalizeViewport(record.viewport), normalizeSelection(record.selection));
396
+ session.previewState = normalizePreviewState(record.previewState) ?? session.previewState;
397
+ session.previewMode = normalizePreviewState(record.previewMode) ?? session.previewMode;
398
+ this.broadcastCanvasState(tabId, "canvas-page:update");
399
+ return {
400
+ ok: true,
401
+ targetId: formatTargetId(tabId),
402
+ previewState: session.previewState
403
+ };
404
+ }
405
+ async mountOverlay(message) {
406
+ const record = requireRecord(message.payload, "payload");
407
+ const session = this.requireOverlaySession(message, record, true);
408
+ const tabId = parseTargetId(requireString(record.targetId, "targetId"));
409
+ const prototypeId = optionalString(record.prototypeId) ?? "default";
410
+ if (this.isDesignTabTarget(session, tabId)) {
411
+ const mountId = `mount_${crypto.randomUUID()}`;
412
+ const mount = {
413
+ mountId,
414
+ targetId: formatTargetId(tabId),
415
+ mountedAt: new Date().toISOString()
416
+ };
417
+ session.overlayMounts = dedupeOverlayMounts([...session.overlayMounts, mount]);
418
+ this.broadcastIfDesignTab(session);
419
+ return {
420
+ mountId,
421
+ targetId: formatTargetId(tabId),
422
+ previewState: session.previewState,
423
+ overlayState: "mounted",
424
+ capabilities: { selection: true, guides: true }
425
+ };
426
+ }
427
+ await insertCss(tabId, OVERLAY_STYLE);
428
+ const mountId = `mount_${crypto.randomUUID()}`;
429
+ const result = await executeInTab(tabId, mountOverlayScript, [{
430
+ mountId,
431
+ cssText: OVERLAY_STYLE,
432
+ title: session.document.title,
433
+ prototypeId,
434
+ selection: session.selection
435
+ }]);
436
+ const mount = {
437
+ mountId,
438
+ targetId: formatTargetId(tabId),
439
+ mountedAt: new Date().toISOString()
440
+ };
441
+ session.overlayMounts = dedupeOverlayMounts([...session.overlayMounts, mount]);
442
+ this.broadcastIfDesignTab(session);
443
+ return {
444
+ mountId,
445
+ targetId: formatTargetId(tabId),
446
+ previewState: "background",
447
+ overlayState: result?.previewState ?? "mounted",
448
+ capabilities: { selection: true, guides: true }
449
+ };
450
+ }
451
+ async unmountOverlay(message) {
452
+ const record = requireRecord(message.payload, "payload");
453
+ const session = this.requireOverlaySession(message, record);
454
+ const mountId = requireString(record.mountId, "mountId");
455
+ const tabId = parseTargetId(requireString(record.targetId, "targetId"));
456
+ if (this.isDesignTabTarget(session, tabId)) {
457
+ session.overlayMounts = session.overlayMounts.filter((mount) => mount.mountId !== mountId);
458
+ this.broadcastIfDesignTab(session);
459
+ return {
460
+ ok: true,
461
+ mountId,
462
+ previewState: session.previewState,
463
+ overlayState: "idle"
464
+ };
465
+ }
466
+ await executeInTab(tabId, unmountOverlayScript, [mountId]);
467
+ session.overlayMounts = session.overlayMounts.filter((mount) => mount.mountId !== mountId);
468
+ this.broadcastIfDesignTab(session);
469
+ return {
470
+ ok: true,
471
+ mountId,
472
+ previewState: "background",
473
+ overlayState: "idle"
474
+ };
475
+ }
476
+ async selectOverlay(message) {
477
+ const record = requireRecord(message.payload, "payload");
478
+ const session = this.requireOverlaySession(message, record);
479
+ const tabId = parseTargetId(requireString(record.targetId, "targetId"));
480
+ const selectionHint = isRecord(record.selectionHint) ? record.selectionHint : {};
481
+ const nodeId = optionalString(record.nodeId);
482
+ const selection = this.isDesignTabTarget(session, tabId)
483
+ ? resolveDesignTabOverlaySelection(session.document, nodeId, selectionHint)
484
+ : await executeInTab(tabId, selectOverlayScript, [{ selectionHint, nodeId }]);
485
+ const resolvedNodeId = typeof selection.nodeId === "string" ? selection.nodeId : nodeId;
486
+ if (typeof resolvedNodeId === "string") {
487
+ session.selection = {
488
+ pageId: session.document.pages[0]?.id ?? null,
489
+ nodeId: resolvedNodeId,
490
+ targetId: formatTargetId(tabId),
491
+ updatedAt: new Date().toISOString()
492
+ };
493
+ this.broadcastIfDesignTab(session);
494
+ }
495
+ return {
496
+ targetId: formatTargetId(tabId),
497
+ selection
498
+ };
499
+ }
500
+ async syncOverlay(message) {
501
+ const record = requireRecord(message.payload, "payload");
502
+ const session = this.requireOverlaySession(message, record);
503
+ const tabId = parseTargetId(requireString(record.targetId, "targetId"));
504
+ const mountId = requireString(record.mountId, "mountId");
505
+ if (this.isDesignTabTarget(session, tabId)) {
506
+ this.broadcastIfDesignTab(session);
507
+ return {
508
+ ok: true,
509
+ mountId,
510
+ targetId: formatTargetId(tabId),
511
+ overlayState: "mounted"
512
+ };
513
+ }
514
+ await insertCss(tabId, OVERLAY_STYLE);
515
+ const result = await executeInTab(tabId, syncOverlayScript, [{
516
+ mountId,
517
+ title: session.document.title,
518
+ selection: session.selection
519
+ }]);
520
+ return {
521
+ ok: true,
522
+ mountId,
523
+ targetId: formatTargetId(tabId),
524
+ overlayState: result?.overlayState ?? "mounted"
525
+ };
526
+ }
527
+ createOrReplaceSession(message, tabId, document, previewMode, record) {
528
+ const canvasSessionId = resolveCanvasSessionId(message, record);
529
+ const clientId = requireString(message.clientId, "clientId");
530
+ const requestedLeaseId = optionalString(message.leaseId);
531
+ const summary = normalizeCanvasSessionSummary(record.summary);
532
+ const existing = this.sessions.get(canvasSessionId);
533
+ if (existing) {
534
+ this.overlaySessions.delete(existing.id);
535
+ if (existing.ownerClientId !== clientId || (requestedLeaseId && existing.leaseId !== requestedLeaseId)) {
536
+ throw new Error("Canvas session ownership mismatch.");
537
+ }
538
+ if (existing.designTabTargetId && existing.designTabTargetId !== formatTargetId(tabId)) {
539
+ void this.tabs.closeTab(parseTargetId(existing.designTabTargetId)).catch(() => undefined);
540
+ }
541
+ existing.designTabTargetId = formatTargetId(tabId);
542
+ existing.document = document;
543
+ existing.documentRevision = optionalNumber(record.documentRevision);
544
+ existing.html = requireRenderedHtml(record);
545
+ existing.summary = summary;
546
+ existing.previewTargets = normalizeCanvasTargetStateSummaries(record.targets ?? summary.targets);
547
+ existing.overlayMounts = parseOverlayMounts(record.overlayMounts ?? summary.overlayMounts);
548
+ existing.feedback = parseFeedbackEvents(record.feedback);
549
+ existing.feedbackCursor = optionalString(record.feedbackCursor) ?? lastFeedbackCursor(existing.feedback);
550
+ existing.previewMode = previewMode;
551
+ existing.previewState = previewMode;
552
+ existing.pendingMutation = false;
553
+ this.mergeEditorState(existing, normalizeViewport(record.viewport), normalizeSelection(record.selection));
554
+ this.sessions.addTarget(existing.id, tabId, { title: document.title, url: chrome.runtime.getURL("canvas.html") });
555
+ this.sessions.setActiveTarget(existing.id, formatTargetId(tabId));
556
+ return existing;
557
+ }
558
+ const leaseId = requestedLeaseId ?? createCoordinatorId();
559
+ const viewport = normalizeViewportState(record.viewport);
560
+ const session = this.sessions.createSession(clientId, tabId, leaseId, {
561
+ title: document.title,
562
+ url: chrome.runtime.getURL("canvas.html")
563
+ }, {
564
+ designTabTargetId: formatTargetId(tabId),
565
+ document,
566
+ documentRevision: optionalNumber(record.documentRevision),
567
+ html: requireRenderedHtml(record),
568
+ summary,
569
+ previewMode,
570
+ previewState: previewMode,
571
+ previewTargets: normalizeCanvasTargetStateSummaries(record.targets ?? summary.targets),
572
+ overlayMounts: parseOverlayMounts(record.overlayMounts ?? summary.overlayMounts),
573
+ feedback: parseFeedbackEvents(record.feedback),
574
+ feedbackCursor: optionalString(record.feedbackCursor) ?? lastFeedbackCursor(parseFeedbackEvents(record.feedback)),
575
+ selection: normalizeSelectionState(record.selection, document.pages[0]?.id ?? null),
576
+ viewport,
577
+ pendingMutation: false
578
+ }, canvasSessionId);
579
+ this.overlaySessions.delete(session.id);
580
+ return session;
581
+ }
582
+ requireOverlaySession(message, record, createIfMissing = false) {
583
+ try {
584
+ return this.requireSessionForMessage(message, record);
585
+ }
586
+ catch (error) {
587
+ if (!isIgnorableCanvasCloseLookupError(error)) {
588
+ throw error;
589
+ }
590
+ }
591
+ const sessionId = optionalString(message.canvasSessionId)
592
+ ?? optionalString(record.canvasSessionId)
593
+ ?? optionalString(isRecord(record.summary) ? record.summary.canvasSessionId : undefined);
594
+ if (!sessionId) {
595
+ throw missingCanvasSession();
596
+ }
597
+ const clientId = requireString(message.clientId, "clientId");
598
+ const requestedLeaseId = optionalString(message.leaseId);
599
+ const existing = this.overlaySessions.get(sessionId);
600
+ if (existing) {
601
+ if (existing.ownerClientId !== clientId || (requestedLeaseId && existing.leaseId !== requestedLeaseId)) {
602
+ throw new Error("Canvas session ownership mismatch.");
603
+ }
604
+ if (record.document !== undefined) {
605
+ existing.document = requireCanvasDocument(record.document);
606
+ }
607
+ if (record.selection !== undefined) {
608
+ existing.selection = normalizeSelectionState(record.selection, existing.document.pages[0]?.id ?? null);
609
+ }
610
+ existing.previewState = normalizePreviewState(record.previewState) ?? existing.previewState;
611
+ return existing;
612
+ }
613
+ if (!createIfMissing) {
614
+ throw new Error(`Unknown sessionId: ${sessionId}`);
615
+ }
616
+ const document = requireCanvasDocument(record.document);
617
+ const session = {
618
+ id: sessionId,
619
+ ownerClientId: clientId,
620
+ leaseId: requestedLeaseId ?? createCoordinatorId(),
621
+ designTabTargetId: null,
622
+ document,
623
+ previewState: normalizePreviewState(record.previewState) ?? "background",
624
+ overlayMounts: parseOverlayMounts(record.overlayMounts),
625
+ selection: normalizeSelectionState(record.selection, document.pages[0]?.id ?? null)
626
+ };
627
+ this.overlaySessions.set(sessionId, session);
628
+ return session;
629
+ }
630
+ requireSessionForMessage(message, record) {
631
+ const payload = record ?? (isRecord(message.payload) ? message.payload : {});
632
+ const session = resolveSessionForMessage(this.sessions, message, payload);
633
+ const clientId = requireString(message.clientId, "clientId");
634
+ const leaseId = optionalString(message.leaseId);
635
+ if (session.ownerClientId !== clientId || (leaseId && session.leaseId !== leaseId)) {
636
+ throw new Error("Canvas session ownership mismatch.");
637
+ }
638
+ return session;
639
+ }
640
+ mergeEditorState(session, viewport, selection) {
641
+ if (viewport) {
642
+ session.viewport = {
643
+ x: typeof viewport.x === "number" ? viewport.x : session.viewport.x,
644
+ y: typeof viewport.y === "number" ? viewport.y : session.viewport.y,
645
+ zoom: typeof viewport.zoom === "number" && Number.isFinite(viewport.zoom) ? viewport.zoom : session.viewport.zoom
646
+ };
647
+ }
648
+ if (selection) {
649
+ session.selection = {
650
+ pageId: typeof selection.pageId === "string" ? selection.pageId : session.selection.pageId,
651
+ nodeId: typeof selection.nodeId === "string" || selection.nodeId === null ? selection.nodeId : session.selection.nodeId,
652
+ targetId: typeof selection.targetId === "string" || selection.targetId === null ? selection.targetId : session.selection.targetId,
653
+ updatedAt: new Date().toISOString()
654
+ };
655
+ }
656
+ }
657
+ getPageStateByTabId(tabId) {
658
+ const session = this.sessions.getByTabId(tabId);
659
+ if (!session || !session.designTabTargetId) {
660
+ return null;
661
+ }
662
+ return buildPageState(session, tabId);
663
+ }
664
+ async waitForPagePort(tabId, timeoutMs) {
665
+ const existing = this.firstConnectedPagePort(tabId);
666
+ if (existing) {
667
+ return existing;
668
+ }
669
+ const startedAt = Date.now();
670
+ while (Date.now() - startedAt < timeoutMs) {
671
+ await delay(50);
672
+ const next = this.firstConnectedPagePort(tabId);
673
+ if (next) {
674
+ return next;
675
+ }
676
+ }
677
+ throw new Error("Canvas page port unavailable.");
678
+ }
679
+ firstConnectedPagePort(tabId) {
680
+ const ports = this.pagePorts.get(tabId);
681
+ if (!ports || ports.size === 0) {
682
+ return null;
683
+ }
684
+ return ports.values().next().value ?? null;
685
+ }
686
+ isDesignTabTarget(session, tabId) {
687
+ return session.designTabTargetId === formatTargetId(tabId);
688
+ }
689
+ sendResponse(message, payload) {
690
+ const response = {
691
+ type: "canvas_response",
692
+ requestId: message.requestId,
693
+ clientId: message.clientId,
694
+ canvasSessionId: message.canvasSessionId,
695
+ payload
696
+ };
697
+ const serialized = JSON.stringify(payload ?? null);
698
+ if (this.encoder.encode(serialized).length <= MAX_CANVAS_PAYLOAD_BYTES) {
699
+ this.sendEnvelope(response);
700
+ return;
701
+ }
702
+ const payloadId = crypto.randomUUID();
703
+ const chunkSize = Math.max(1024, MAX_CANVAS_PAYLOAD_BYTES - 1024);
704
+ const chunks = [];
705
+ for (let i = 0; i < serialized.length; i += chunkSize) {
706
+ chunks.push(serialized.slice(i, i + chunkSize));
707
+ }
708
+ this.sendEnvelope({
709
+ type: "canvas_response",
710
+ requestId: message.requestId,
711
+ clientId: message.clientId,
712
+ canvasSessionId: message.canvasSessionId,
713
+ chunked: true,
714
+ payloadId,
715
+ totalChunks: chunks.length
716
+ });
717
+ chunks.forEach((data, index) => {
718
+ const chunk = {
719
+ type: "canvas_chunk",
720
+ requestId: message.requestId,
721
+ clientId: message.clientId,
722
+ canvasSessionId: message.canvasSessionId,
723
+ payloadId,
724
+ chunkIndex: index,
725
+ totalChunks: chunks.length,
726
+ data
727
+ };
728
+ this.sendEnvelope(chunk);
729
+ });
730
+ }
731
+ sendError(message, error) {
732
+ this.sendEnvelope({
733
+ type: "canvas_error",
734
+ requestId: message.requestId,
735
+ clientId: message.clientId,
736
+ canvasSessionId: message.canvasSessionId,
737
+ error
738
+ });
739
+ }
740
+ sendEvent(event) {
741
+ this.sendEnvelope(event);
742
+ }
743
+ postCanvasState(port, state, type, extra = {}) {
744
+ try {
745
+ port.postMessage({
746
+ type,
747
+ state,
748
+ ...extra
749
+ });
750
+ }
751
+ catch {
752
+ // ignore disconnected page ports
753
+ }
754
+ }
755
+ broadcastCanvasState(tabId, type, extra = {}) {
756
+ const ports = this.pagePorts.get(tabId);
757
+ if (!ports || ports.size === 0) {
758
+ return;
759
+ }
760
+ const state = this.getPageStateByTabId(tabId);
761
+ for (const port of ports) {
762
+ this.postCanvasState(port, state, type, extra);
763
+ }
764
+ }
765
+ broadcastIfDesignTab(session) {
766
+ if (!session.designTabTargetId) {
767
+ return;
768
+ }
769
+ this.broadcastCanvasState(parseTargetId(session.designTabTargetId), "canvas-page:update");
770
+ }
771
+ async closeRuntimeSession(session, reason) {
772
+ this.overlaySessions.delete(session.id);
773
+ const released = [...session.targets.values()];
774
+ for (const target of released) {
775
+ this.broadcastCanvasState(target.tabId, "canvas-page:closed", { reason });
776
+ await this.tabs.closeTab(target.tabId).catch(() => undefined);
777
+ this.pagePorts.delete(target.tabId);
778
+ }
779
+ this.sessions.delete(session.id);
780
+ this.sendEvent({
781
+ type: "canvas_event",
782
+ clientId: session.ownerClientId,
783
+ canvasSessionId: session.id,
784
+ event: "canvas_session_expired",
785
+ payload: { reason }
786
+ });
787
+ }
788
+ async createTab(url, previewMode) {
789
+ return await new Promise((resolve, reject) => {
790
+ chrome.tabs.create({ url, active: previewMode === "focused", pinned: previewMode === "pinned" }, (tab) => {
791
+ const lastError = chrome.runtime.lastError;
792
+ if (lastError) {
793
+ reject(new Error(lastError.message));
794
+ return;
795
+ }
796
+ if (!tab || typeof tab.id !== "number") {
797
+ reject(new Error("Canvas tab creation failed"));
798
+ return;
799
+ }
800
+ resolve(tab);
801
+ });
802
+ });
803
+ }
804
+ async syncOpsTargetRegistration(session) {
805
+ const browserSessionId = readBrowserSessionId(session.summary);
806
+ if (!browserSessionId || !session.designTabTargetId || !this.registerOpsCanvasTarget) {
807
+ return;
808
+ }
809
+ const registered = await this.registerOpsCanvasTarget(browserSessionId, session.designTabTargetId);
810
+ if (registered?.targetId) {
811
+ session.designTabTargetId = registered.targetId;
812
+ }
813
+ }
814
+ }
815
+ function buildPageState(session, tabId) {
816
+ return {
817
+ tabId,
818
+ targetId: formatTargetId(tabId),
819
+ canvasSessionId: session.id,
820
+ documentId: session.document.documentId,
821
+ documentRevision: session.documentRevision,
822
+ title: session.document.title,
823
+ document: session.document,
824
+ html: session.html,
825
+ previewMode: session.previewMode,
826
+ previewState: session.previewState,
827
+ updatedAt: new Date().toISOString(),
828
+ summary: session.summary,
829
+ targets: session.previewTargets,
830
+ overlayMounts: session.overlayMounts,
831
+ feedback: session.feedback,
832
+ feedbackCursor: session.feedbackCursor,
833
+ selection: session.selection,
834
+ viewport: session.viewport,
835
+ pendingMutation: session.pendingMutation
836
+ };
837
+ }
838
+ function defaultSelection(pageId) {
839
+ return {
840
+ pageId,
841
+ nodeId: null,
842
+ targetId: null,
843
+ updatedAt: new Date().toISOString()
844
+ };
845
+ }
846
+ function normalizeViewport(value) {
847
+ if (!isRecord(value)) {
848
+ return null;
849
+ }
850
+ return {
851
+ x: typeof value.x === "number" ? value.x : undefined,
852
+ y: typeof value.y === "number" ? value.y : undefined,
853
+ zoom: typeof value.zoom === "number" ? value.zoom : undefined
854
+ };
855
+ }
856
+ function normalizeSelection(value) {
857
+ if (!isRecord(value)) {
858
+ return null;
859
+ }
860
+ return {
861
+ pageId: typeof value.pageId === "string" || value.pageId === null ? value.pageId : undefined,
862
+ nodeId: typeof value.nodeId === "string" || value.nodeId === null ? value.nodeId : undefined,
863
+ targetId: typeof value.targetId === "string" || value.targetId === null ? value.targetId : undefined
864
+ };
865
+ }
866
+ function normalizeViewportState(value) {
867
+ if (!isRecord(value)) {
868
+ return { ...DEFAULT_EDITOR_VIEWPORT };
869
+ }
870
+ return {
871
+ x: typeof value.x === "number" ? value.x : DEFAULT_EDITOR_VIEWPORT.x,
872
+ y: typeof value.y === "number" ? value.y : DEFAULT_EDITOR_VIEWPORT.y,
873
+ zoom: typeof value.zoom === "number" ? value.zoom : DEFAULT_EDITOR_VIEWPORT.zoom
874
+ };
875
+ }
876
+ function normalizeSelectionState(value, defaultPageId) {
877
+ if (!isRecord(value)) {
878
+ return defaultSelection(defaultPageId);
879
+ }
880
+ return {
881
+ pageId: typeof value.pageId === "string" || value.pageId === null ? value.pageId : defaultPageId,
882
+ nodeId: typeof value.nodeId === "string" || value.nodeId === null ? value.nodeId : null,
883
+ targetId: typeof value.targetId === "string" || value.targetId === null ? value.targetId : null,
884
+ updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : new Date().toISOString()
885
+ };
886
+ }
887
+ function requireCanvasDocument(value) {
888
+ const document = requireRecord(value, "document");
889
+ const pagesValue = Array.isArray(document.pages) ? document.pages : [];
890
+ return {
891
+ documentId: requireString(document.documentId, "documentId"),
892
+ title: optionalString(document.title) ?? "OpenDevBrowser Canvas",
893
+ updatedAt: optionalString(document.updatedAt) ?? undefined,
894
+ bindings: Array.isArray(document.bindings)
895
+ ? document.bindings.flatMap((bindingValue) => {
896
+ const binding = isRecord(bindingValue) ? bindingValue : null;
897
+ if (!binding || typeof binding.id !== "string" || typeof binding.nodeId !== "string") {
898
+ return [];
899
+ }
900
+ return [{
901
+ id: binding.id,
902
+ nodeId: binding.nodeId,
903
+ kind: optionalString(binding.kind) ?? "component",
904
+ componentName: optionalString(binding.componentName) ?? undefined,
905
+ metadata: isRecord(binding.metadata) ? binding.metadata : {}
906
+ }];
907
+ })
908
+ : [],
909
+ assets: Array.isArray(document.assets)
910
+ ? document.assets.flatMap((assetValue) => {
911
+ const asset = isRecord(assetValue) ? assetValue : null;
912
+ if (!asset || typeof asset.id !== "string") {
913
+ return [];
914
+ }
915
+ return [{
916
+ id: asset.id,
917
+ sourceType: optionalString(asset.sourceType) ?? undefined,
918
+ kind: optionalString(asset.kind) ?? undefined,
919
+ repoPath: optionalString(asset.repoPath),
920
+ url: optionalString(asset.url),
921
+ mime: optionalString(asset.mime) ?? undefined,
922
+ metadata: isRecord(asset.metadata) ? asset.metadata : {}
923
+ }];
924
+ })
925
+ : [],
926
+ componentInventory: Array.isArray(document.componentInventory)
927
+ ? document.componentInventory.flatMap((entry, index) => normalizeComponentInventoryItem(entry, index))
928
+ : [],
929
+ tokens: normalizeTokenStore(document.tokens),
930
+ meta: normalizeDocumentMeta(document.meta),
931
+ pages: pagesValue.flatMap((pageValue) => normalizePage(pageValue))
932
+ };
933
+ }
934
+ function normalizePage(value) {
935
+ if (!isRecord(value) || typeof value.id !== "string") {
936
+ return [];
937
+ }
938
+ const pageId = value.id;
939
+ return [{
940
+ id: pageId,
941
+ name: typeof value.name === "string" ? value.name : pageId,
942
+ path: typeof value.path === "string" ? value.path : "/",
943
+ rootNodeId: typeof value.rootNodeId === "string" ? value.rootNodeId : null,
944
+ prototypeIds: Array.isArray(value.prototypeIds) ? value.prototypeIds.filter((entry) => typeof entry === "string") : [],
945
+ nodes: Array.isArray(value.nodes) ? value.nodes.flatMap((entry) => normalizeNode(entry, pageId)) : [],
946
+ metadata: isRecord(value.metadata) ? value.metadata : {}
947
+ }];
948
+ }
949
+ function normalizeNode(value, pageId) {
950
+ if (!isRecord(value) || typeof value.id !== "string") {
951
+ return [];
952
+ }
953
+ return [{
954
+ id: value.id,
955
+ kind: typeof value.kind === "string" ? value.kind : "frame",
956
+ name: typeof value.name === "string" ? value.name : value.id,
957
+ pageId,
958
+ parentId: typeof value.parentId === "string" ? value.parentId : null,
959
+ childIds: Array.isArray(value.childIds) ? value.childIds.filter((entry) => typeof entry === "string") : [],
960
+ rect: isRecord(value.rect) ? {
961
+ x: typeof value.rect.x === "number" ? value.rect.x : 0,
962
+ y: typeof value.rect.y === "number" ? value.rect.y : 0,
963
+ width: typeof value.rect.width === "number" ? value.rect.width : 240,
964
+ height: typeof value.rect.height === "number" ? value.rect.height : 120
965
+ } : { x: 0, y: 0, width: 240, height: 120 },
966
+ props: isRecord(value.props) ? value.props : {},
967
+ style: isRecord(value.style) ? value.style : {},
968
+ tokenRefs: isRecord(value.tokenRefs) ? value.tokenRefs : {},
969
+ bindingRefs: isRecord(value.bindingRefs) ? value.bindingRefs : {},
970
+ variantPatches: Array.isArray(value.variantPatches) ? value.variantPatches.filter(isRecord) : [],
971
+ metadata: isRecord(value.metadata) ? value.metadata : {}
972
+ }];
973
+ }
974
+ function normalizeComponentInventoryItem(value, index) {
975
+ if (!isRecord(value)) {
976
+ return [];
977
+ }
978
+ const id = optionalString(value.id) ?? `inventory_${index + 1}`;
979
+ const name = optionalString(value.name) ?? optionalString(value.componentName) ?? id;
980
+ return [{
981
+ id,
982
+ name,
983
+ componentName: optionalString(value.componentName),
984
+ sourceKind: optionalString(value.sourceKind),
985
+ sourceFamily: optionalString(value.sourceFamily) ?? undefined,
986
+ origin: optionalString(value.origin) ?? undefined,
987
+ framework: normalizeComponentRef(value.framework),
988
+ adapter: normalizeComponentRef(value.adapter),
989
+ plugin: normalizeComponentRef(value.plugin),
990
+ variants: Array.isArray(value.variants) ? value.variants.filter(isRecord) : [],
991
+ props: Array.isArray(value.props) ? value.props.filter(isRecord) : [],
992
+ slots: Array.isArray(value.slots) ? value.slots.filter(isRecord) : [],
993
+ events: Array.isArray(value.events) ? value.events.filter(isRecord) : [],
994
+ content: isRecord(value.content) ? value.content : {},
995
+ metadata: isRecord(value.metadata) ? value.metadata : {}
996
+ }];
997
+ }
998
+ function normalizeComponentRef(value) {
999
+ if (!isRecord(value)) {
1000
+ return null;
1001
+ }
1002
+ const id = optionalString(value.id);
1003
+ if (!id) {
1004
+ return null;
1005
+ }
1006
+ return {
1007
+ id,
1008
+ label: optionalString(value.label) ?? optionalString(value.name),
1009
+ packageName: optionalString(value.packageName) ?? undefined,
1010
+ version: optionalString(value.version) ?? undefined,
1011
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1012
+ };
1013
+ }
1014
+ function normalizeTokenStore(value) {
1015
+ if (!isRecord(value)) {
1016
+ return { values: {}, collections: [], aliases: [], bindings: [], metadata: {} };
1017
+ }
1018
+ const structured = "values" in value || "collections" in value || "aliases" in value || "bindings" in value || "metadata" in value;
1019
+ return {
1020
+ values: structured && isRecord(value.values) ? value.values : structured ? {} : value,
1021
+ collections: Array.isArray(value.collections) ? value.collections.flatMap((entry) => normalizeTokenCollection(entry)) : [],
1022
+ aliases: Array.isArray(value.aliases) ? value.aliases.flatMap((entry) => normalizeTokenAlias(entry)) : [],
1023
+ bindings: Array.isArray(value.bindings) ? value.bindings.flatMap((entry) => normalizeTokenBinding(entry)) : [],
1024
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1025
+ };
1026
+ }
1027
+ function normalizeTokenCollection(value) {
1028
+ if (!isRecord(value) || typeof value.id !== "string") {
1029
+ return [];
1030
+ }
1031
+ return [{
1032
+ id: value.id,
1033
+ name: typeof value.name === "string" ? value.name : value.id,
1034
+ items: Array.isArray(value.items) ? value.items.flatMap((entry) => normalizeTokenItem(entry)) : [],
1035
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1036
+ }];
1037
+ }
1038
+ function normalizeTokenItem(value) {
1039
+ if (!isRecord(value) || typeof value.id !== "string" || typeof value.path !== "string") {
1040
+ return [];
1041
+ }
1042
+ return [{
1043
+ id: value.id,
1044
+ path: normalizeTokenPath(value.path),
1045
+ value: value.value,
1046
+ type: typeof value.type === "string" ? value.type : undefined,
1047
+ description: typeof value.description === "string" ? value.description : undefined,
1048
+ modes: Array.isArray(value.modes) ? value.modes.flatMap((entry) => normalizeTokenMode(entry)) : [],
1049
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1050
+ }];
1051
+ }
1052
+ function normalizeTokenMode(value) {
1053
+ if (!isRecord(value) || typeof value.id !== "string" || typeof value.name !== "string") {
1054
+ return [];
1055
+ }
1056
+ return [{
1057
+ id: value.id,
1058
+ name: value.name,
1059
+ value: value.value,
1060
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1061
+ }];
1062
+ }
1063
+ function normalizeTokenAlias(value) {
1064
+ if (!isRecord(value) || typeof value.path !== "string" || typeof value.targetPath !== "string") {
1065
+ return [];
1066
+ }
1067
+ return [{
1068
+ path: normalizeTokenPath(value.path),
1069
+ targetPath: normalizeTokenPath(value.targetPath),
1070
+ modeId: typeof value.modeId === "string" ? value.modeId : null,
1071
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1072
+ }];
1073
+ }
1074
+ function normalizeTokenBinding(value) {
1075
+ if (!isRecord(value) || typeof value.path !== "string") {
1076
+ return [];
1077
+ }
1078
+ return [{
1079
+ path: normalizeTokenPath(value.path),
1080
+ nodeId: typeof value.nodeId === "string" ? value.nodeId : null,
1081
+ bindingId: typeof value.bindingId === "string" ? value.bindingId : null,
1082
+ property: typeof value.property === "string" ? value.property : null,
1083
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1084
+ }];
1085
+ }
1086
+ function normalizeTokenPath(path) {
1087
+ return path.trim().replace(/^tokens\./, "");
1088
+ }
1089
+ function normalizeDocumentMeta(value) {
1090
+ if (!isRecord(value)) {
1091
+ return { imports: [], starter: null, adapterPlugins: [], pluginErrors: [], metadata: {} };
1092
+ }
1093
+ return {
1094
+ imports: Array.isArray(value.imports) ? value.imports.filter(isRecord) : [],
1095
+ starter: isRecord(value.starter) ? value.starter : null,
1096
+ adapterPlugins: Array.isArray(value.adapterPlugins) ? value.adapterPlugins.filter(isRecord) : [],
1097
+ pluginErrors: Array.isArray(value.pluginErrors)
1098
+ ? value.pluginErrors.flatMap((entry) => normalizePluginError(entry))
1099
+ : [],
1100
+ metadata: isRecord(value.metadata) ? value.metadata : {}
1101
+ };
1102
+ }
1103
+ function normalizePluginError(value) {
1104
+ if (!isRecord(value)) {
1105
+ return [];
1106
+ }
1107
+ const code = optionalString(value.code);
1108
+ const message = optionalString(value.message);
1109
+ if (!code || !message) {
1110
+ return [];
1111
+ }
1112
+ return [{
1113
+ pluginId: optionalString(value.pluginId),
1114
+ code,
1115
+ message,
1116
+ details: isRecord(value.details) ? value.details : {}
1117
+ }];
1118
+ }
1119
+ function requireRenderedHtml(record) {
1120
+ return requireString(record.html, "html");
1121
+ }
1122
+ function normalizeRect(value) {
1123
+ if (!isRecord(value)) {
1124
+ return { x: 0, y: 0, width: 320, height: 180 };
1125
+ }
1126
+ return {
1127
+ x: typeof value.x === "number" ? value.x : 0,
1128
+ y: typeof value.y === "number" ? value.y : 0,
1129
+ width: typeof value.width === "number" ? value.width : 320,
1130
+ height: typeof value.height === "number" ? value.height : 180
1131
+ };
1132
+ }
1133
+ function parseOverlayMounts(value) {
1134
+ if (!Array.isArray(value)) {
1135
+ return [];
1136
+ }
1137
+ return value.flatMap((entry) => {
1138
+ if (!isRecord(entry)) {
1139
+ return [];
1140
+ }
1141
+ const mountId = optionalString(entry.mountId);
1142
+ const targetId = optionalString(entry.targetId);
1143
+ const mountedAt = optionalString(entry.mountedAt);
1144
+ return mountId && targetId && mountedAt
1145
+ ? [{ mountId, targetId, mountedAt }]
1146
+ : [];
1147
+ });
1148
+ }
1149
+ function parseFeedbackEvents(value) {
1150
+ if (!Array.isArray(value)) {
1151
+ return [];
1152
+ }
1153
+ const events = [];
1154
+ for (const entry of value) {
1155
+ if (!isRecord(entry)) {
1156
+ continue;
1157
+ }
1158
+ if (entry.eventType === "feedback.item" && isRecord(entry.item)) {
1159
+ const item = entry.item;
1160
+ const id = optionalString(item.id);
1161
+ const cursor = optionalString(item.cursor);
1162
+ const documentId = optionalString(item.documentId);
1163
+ if (!id || !cursor || !documentId) {
1164
+ continue;
1165
+ }
1166
+ events.push({
1167
+ eventType: "feedback.item",
1168
+ item: {
1169
+ id,
1170
+ cursor,
1171
+ category: optionalString(item.category) ?? "validation",
1172
+ class: optionalString(item.class) ?? "feedback",
1173
+ severity: optionalString(item.severity) ?? "info",
1174
+ message: optionalString(item.message) ?? "",
1175
+ documentId,
1176
+ documentRevision: typeof item.documentRevision === "number" ? item.documentRevision : 0,
1177
+ pageId: optionalString(item.pageId),
1178
+ prototypeId: optionalString(item.prototypeId),
1179
+ targetId: optionalString(item.targetId),
1180
+ evidenceRefs: Array.isArray(item.evidenceRefs) ? item.evidenceRefs.filter((ref) => typeof ref === "string") : [],
1181
+ details: isRecord(item.details) ? item.details : {}
1182
+ }
1183
+ });
1184
+ continue;
1185
+ }
1186
+ if (entry.eventType === "feedback.heartbeat") {
1187
+ events.push({
1188
+ eventType: "feedback.heartbeat",
1189
+ cursor: optionalString(entry.cursor),
1190
+ ts: optionalString(entry.ts) ?? new Date().toISOString(),
1191
+ activeTargetIds: Array.isArray(entry.activeTargetIds) ? entry.activeTargetIds.filter((id) => typeof id === "string") : []
1192
+ });
1193
+ continue;
1194
+ }
1195
+ if (entry.eventType === "feedback.complete") {
1196
+ const reason = optionalString(entry.reason);
1197
+ if (!reason) {
1198
+ continue;
1199
+ }
1200
+ events.push({
1201
+ eventType: "feedback.complete",
1202
+ cursor: optionalString(entry.cursor),
1203
+ ts: optionalString(entry.ts) ?? new Date().toISOString(),
1204
+ reason: reason
1205
+ });
1206
+ continue;
1207
+ }
1208
+ }
1209
+ return events;
1210
+ }
1211
+ function lastFeedbackCursor(events) {
1212
+ for (let index = events.length - 1; index >= 0; index -= 1) {
1213
+ const entry = events[index];
1214
+ if (entry?.eventType === "feedback.item") {
1215
+ return entry.item.cursor;
1216
+ }
1217
+ if (entry?.eventType === "feedback.heartbeat" || entry?.eventType === "feedback.complete") {
1218
+ return entry.cursor;
1219
+ }
1220
+ }
1221
+ return null;
1222
+ }
1223
+ function dedupeOverlayMounts(mounts) {
1224
+ const byId = new Map();
1225
+ for (const mount of mounts) {
1226
+ byId.set(mount.mountId, mount);
1227
+ }
1228
+ return [...byId.values()];
1229
+ }
1230
+ function resolveDesignTabOverlaySelection(document, nodeId, selectionHint) {
1231
+ const selector = typeof selectionHint.selector === "string" && selectionHint.selector.trim().length > 0
1232
+ ? selectionHint.selector.trim()
1233
+ : null;
1234
+ const resolvedNodeId = nodeId
1235
+ ?? readNodeIdFromSelector(selector)
1236
+ ?? null;
1237
+ if (!resolvedNodeId) {
1238
+ return { matched: false, selector };
1239
+ }
1240
+ const node = findDocumentNode(document, resolvedNodeId);
1241
+ if (!node) {
1242
+ return { matched: false, selector: selector ?? `[data-node-id="${resolvedNodeId}"]` };
1243
+ }
1244
+ const text = typeof node.props.text === "string" ? node.props.text : null;
1245
+ return {
1246
+ matched: true,
1247
+ selector: selector ?? `[data-node-id="${resolvedNodeId}"]`,
1248
+ nodeId: resolvedNodeId,
1249
+ tagName: "div",
1250
+ text: text ? text.slice(0, 160) : "",
1251
+ id: null,
1252
+ className: "canvas-stage-node"
1253
+ };
1254
+ }
1255
+ function readNodeIdFromSelector(selector) {
1256
+ if (!selector) {
1257
+ return null;
1258
+ }
1259
+ const match = selector.match(/^\[data-node-id=["']([^"'\\]]+)["']\]$/);
1260
+ return match?.[1] ?? null;
1261
+ }
1262
+ function findDocumentNode(document, nodeId) {
1263
+ for (const page of document.pages) {
1264
+ const node = page.nodes.find((entry) => entry.id === nodeId);
1265
+ if (node) {
1266
+ return node;
1267
+ }
1268
+ }
1269
+ return null;
1270
+ }
1271
+ function requireRecord(value, label) {
1272
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1273
+ throw new Error(`Invalid ${label}`);
1274
+ }
1275
+ return value;
1276
+ }
1277
+ function resolveCanvasSessionId(message, payload) {
1278
+ return optionalString(message.canvasSessionId)
1279
+ ?? optionalString(payload.canvasSessionId)
1280
+ ?? optionalString(isRecord(payload.summary) ? payload.summary.canvasSessionId : undefined)
1281
+ ?? createCoordinatorId();
1282
+ }
1283
+ function readBrowserSessionId(summary) {
1284
+ if (!summary) {
1285
+ return null;
1286
+ }
1287
+ return optionalString(summary.browserSessionId);
1288
+ }
1289
+ function resolveSessionForMessage(sessions, message, payload) {
1290
+ const directId = optionalString(message.canvasSessionId)
1291
+ ?? optionalString(payload.canvasSessionId)
1292
+ ?? optionalString(isRecord(payload.summary) ? payload.summary.canvasSessionId : undefined);
1293
+ if (directId) {
1294
+ return sessions.requireSession(directId);
1295
+ }
1296
+ const targetId = optionalString(payload.targetId);
1297
+ if (targetId) {
1298
+ const session = sessions.getByTabId(parseTargetId(targetId));
1299
+ if (session) {
1300
+ return session;
1301
+ }
1302
+ }
1303
+ throw missingCanvasSession();
1304
+ }
1305
+ function missingCanvasSession() {
1306
+ return new Error("Missing canvasSessionId");
1307
+ }
1308
+ function isIgnorableCanvasCloseLookupError(error) {
1309
+ const message = error instanceof Error ? error.message : String(error ?? "");
1310
+ return message.includes("Unknown sessionId:") || message === "Missing canvasSessionId";
1311
+ }
1312
+ function isRecord(value) {
1313
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1314
+ }
1315
+ function requireString(value, label) {
1316
+ if (typeof value !== "string" || value.trim().length === 0) {
1317
+ throw new Error(`Missing ${label}`);
1318
+ }
1319
+ return value;
1320
+ }
1321
+ function optionalString(value) {
1322
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
1323
+ }
1324
+ function optionalNumber(value) {
1325
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
1326
+ }
1327
+ function requireEnum(value, label, allowed) {
1328
+ if (typeof value !== "string" || !allowed.includes(value)) {
1329
+ throw new Error(`Invalid ${label}`);
1330
+ }
1331
+ return value;
1332
+ }
1333
+ function normalizePreviewState(value) {
1334
+ return value === "focused" || value === "pinned" || value === "background" || value === "degraded"
1335
+ ? value
1336
+ : null;
1337
+ }
1338
+ function parseTargetId(targetId) {
1339
+ const raw = targetId.startsWith("tab-") ? targetId.slice(4) : targetId;
1340
+ const tabId = Number(raw);
1341
+ if (!Number.isInteger(tabId) || tabId <= 0) {
1342
+ throw new Error(`Invalid targetId: ${targetId}`);
1343
+ }
1344
+ return tabId;
1345
+ }
1346
+ function formatTargetId(tabId) {
1347
+ if (!Number.isInteger(tabId)) {
1348
+ throw new Error("Tab id unavailable");
1349
+ }
1350
+ return `tab-${tabId}`;
1351
+ }
1352
+ function requireTabId(tab) {
1353
+ const tabId = tab.id;
1354
+ if (typeof tabId !== "number" || !Number.isInteger(tabId)) {
1355
+ throw new Error("Canvas tab creation failed");
1356
+ }
1357
+ return tabId;
1358
+ }
1359
+ async function insertCss(tabId, css) {
1360
+ await new Promise((resolve, reject) => {
1361
+ chrome.scripting.insertCSS({ target: { tabId }, css }, () => {
1362
+ const lastError = chrome.runtime.lastError;
1363
+ if (lastError) {
1364
+ reject(new Error(lastError.message));
1365
+ return;
1366
+ }
1367
+ resolve();
1368
+ });
1369
+ });
1370
+ }
1371
+ async function executeInTab(tabId, func, args) {
1372
+ return await new Promise((resolve, reject) => {
1373
+ chrome.scripting.executeScript({ target: { tabId }, func: func, args }, (results) => {
1374
+ const lastError = chrome.runtime.lastError;
1375
+ if (lastError) {
1376
+ reject(new Error(lastError.message));
1377
+ return;
1378
+ }
1379
+ const [first] = results ?? [];
1380
+ resolve((first?.result ?? null));
1381
+ });
1382
+ });
1383
+ }
1384
+ function mountOverlayScript(input) {
1385
+ const styleId = "opendevbrowser-canvas-style";
1386
+ if (!document.getElementById(styleId)) {
1387
+ const style = document.createElement("style");
1388
+ style.id = styleId;
1389
+ style.textContent = input.cssText;
1390
+ document.head.append(style);
1391
+ }
1392
+ document.getElementById(input.mountId)?.remove();
1393
+ const root = document.createElement("div");
1394
+ root.id = input.mountId;
1395
+ root.className = "opendevbrowser-canvas-overlay";
1396
+ const heading = document.createElement("strong");
1397
+ heading.textContent = input.title;
1398
+ const detail = document.createElement("div");
1399
+ detail.textContent = input.selection.nodeId ? `Selected ${input.selection.nodeId}` : input.prototypeId;
1400
+ root.append(heading, detail);
1401
+ document.body.append(root);
1402
+ if (input.selection.nodeId) {
1403
+ const element = document.querySelector(`[data-node-id="${input.selection.nodeId}"]`);
1404
+ if (element instanceof HTMLElement) {
1405
+ element.classList.add("opendevbrowser-canvas-highlight");
1406
+ }
1407
+ }
1408
+ return { previewState: "overlay_mounted" };
1409
+ }
1410
+ function unmountOverlayScript(mountId) {
1411
+ document.getElementById(mountId)?.remove();
1412
+ document.querySelectorAll(".opendevbrowser-canvas-highlight").forEach((element) => {
1413
+ element.classList.remove("opendevbrowser-canvas-highlight");
1414
+ });
1415
+ return true;
1416
+ }
1417
+ function selectOverlayScript(input) {
1418
+ document.querySelectorAll(".opendevbrowser-canvas-highlight").forEach((element) => {
1419
+ element.classList.remove("opendevbrowser-canvas-highlight");
1420
+ });
1421
+ const selector = typeof input.selectionHint.selector === "string"
1422
+ ? input.selectionHint.selector
1423
+ : (input.nodeId ? `[data-node-id="${input.nodeId}"]` : null);
1424
+ const element = selector ? document.querySelector(selector) : null;
1425
+ if (!(element instanceof HTMLElement)) {
1426
+ return { matched: false };
1427
+ }
1428
+ element.classList.add("opendevbrowser-canvas-highlight");
1429
+ return {
1430
+ matched: true,
1431
+ selector,
1432
+ tagName: element.tagName.toLowerCase(),
1433
+ text: element.innerText.slice(0, 160),
1434
+ id: element.id || null,
1435
+ className: element.className || null
1436
+ };
1437
+ }
1438
+ function syncOverlayScript(input) {
1439
+ let root = document.getElementById(input.mountId);
1440
+ if (!(root instanceof HTMLElement)) {
1441
+ root = document.createElement("div");
1442
+ root.id = input.mountId;
1443
+ root.className = "opendevbrowser-canvas-overlay";
1444
+ const heading = document.createElement("strong");
1445
+ heading.textContent = input.title;
1446
+ const detail = document.createElement("div");
1447
+ detail.textContent = input.selection.nodeId ? `Selected ${input.selection.nodeId}` : "Canvas overlay synced";
1448
+ root.append(heading, detail);
1449
+ document.body.append(root);
1450
+ }
1451
+ const strong = root.querySelector("strong");
1452
+ if (strong) {
1453
+ strong.textContent = input.title;
1454
+ }
1455
+ const detail = root.querySelector("div");
1456
+ if (detail) {
1457
+ detail.textContent = input.selection.nodeId ? `Selected ${input.selection.nodeId}` : "Canvas overlay synced";
1458
+ }
1459
+ document.querySelectorAll(".opendevbrowser-canvas-highlight").forEach((element) => {
1460
+ element.classList.remove("opendevbrowser-canvas-highlight");
1461
+ });
1462
+ if (input.selection.nodeId) {
1463
+ const element = document.querySelector(`[data-node-id="${input.selection.nodeId}"]`);
1464
+ if (element instanceof HTMLElement) {
1465
+ element.classList.add("opendevbrowser-canvas-highlight");
1466
+ }
1467
+ }
1468
+ return { overlayState: "mounted" };
1469
+ }
1470
+ function normalizeCanvasError(error) {
1471
+ if (error instanceof Error) {
1472
+ const message = error.message;
1473
+ const restricted = message.includes("Cannot access") || message.includes("chrome://") || message.includes("restricted");
1474
+ return {
1475
+ code: restricted ? "restricted_url" : "execution_failed",
1476
+ message,
1477
+ retryable: false
1478
+ };
1479
+ }
1480
+ return {
1481
+ code: "execution_failed",
1482
+ message: "Canvas request failed",
1483
+ retryable: false
1484
+ };
1485
+ }
1486
+ function delay(ms) {
1487
+ return new Promise((resolve) => {
1488
+ setTimeout(resolve, ms);
1489
+ });
1490
+ }