opendevbrowser 0.0.16 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +51 -27
  2. package/dist/browser/annotation-manager.d.ts +3 -0
  3. package/dist/browser/annotation-manager.d.ts.map +1 -1
  4. package/dist/browser/browser-manager.d.ts +6 -1
  5. package/dist/browser/browser-manager.d.ts.map +1 -1
  6. package/dist/browser/canvas-client.d.ts +53 -0
  7. package/dist/browser/canvas-client.d.ts.map +1 -0
  8. package/dist/browser/canvas-code-sync-manager.d.ts +79 -0
  9. package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -0
  10. package/dist/browser/canvas-manager.d.ts +94 -0
  11. package/dist/browser/canvas-manager.d.ts.map +1 -0
  12. package/dist/browser/canvas-runtime-preview-bridge.d.ts +20 -0
  13. package/dist/browser/canvas-runtime-preview-bridge.d.ts.map +1 -0
  14. package/dist/browser/canvas-session-sync-manager.d.ts +21 -0
  15. package/dist/browser/canvas-session-sync-manager.d.ts.map +1 -0
  16. package/dist/browser/manager-types.d.ts +13 -1
  17. package/dist/browser/manager-types.d.ts.map +1 -1
  18. package/dist/browser/ops-browser-manager.d.ts +11 -1
  19. package/dist/browser/ops-browser-manager.d.ts.map +1 -1
  20. package/dist/canvas/code-sync/apply-tsx.d.ts +23 -0
  21. package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -0
  22. package/dist/canvas/code-sync/graph.d.ts +5 -0
  23. package/dist/canvas/code-sync/graph.d.ts.map +1 -0
  24. package/dist/canvas/code-sync/hash.d.ts +3 -0
  25. package/dist/canvas/code-sync/hash.d.ts.map +1 -0
  26. package/dist/canvas/code-sync/import.d.ts +18 -0
  27. package/dist/canvas/code-sync/import.d.ts.map +1 -0
  28. package/dist/canvas/code-sync/manifest.d.ts +5 -0
  29. package/dist/canvas/code-sync/manifest.d.ts.map +1 -0
  30. package/dist/canvas/code-sync/tsx-adapter.d.ts +8 -0
  31. package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -0
  32. package/dist/canvas/code-sync/types.d.ts +152 -0
  33. package/dist/canvas/code-sync/types.d.ts.map +1 -0
  34. package/dist/canvas/code-sync/write.d.ts +9 -0
  35. package/dist/canvas/code-sync/write.d.ts.map +1 -0
  36. package/dist/canvas/document-store.d.ts +81 -0
  37. package/dist/canvas/document-store.d.ts.map +1 -0
  38. package/dist/canvas/export.d.ts +12 -0
  39. package/dist/canvas/export.d.ts.map +1 -0
  40. package/dist/canvas/repo-store.d.ts +10 -0
  41. package/dist/canvas/repo-store.d.ts.map +1 -0
  42. package/dist/canvas/surface-palette.d.ts +15 -0
  43. package/dist/canvas/surface-palette.d.ts.map +1 -0
  44. package/dist/canvas/types.d.ts +255 -0
  45. package/dist/canvas/types.d.ts.map +1 -0
  46. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js +7 -0
  47. package/dist/canvas-runtime-preview-bridge-HBEHXM4T.js.map +1 -0
  48. package/dist/{chunk-ST7CO5FA.js → chunk-5J3IFL3X.js} +11577 -13539
  49. package/dist/chunk-5J3IFL3X.js.map +1 -0
  50. package/dist/chunk-D633UO34.js +8149 -0
  51. package/dist/chunk-D633UO34.js.map +1 -0
  52. package/dist/{chunk-7W3SPXIB.js → chunk-FUSXMW3G.js} +4 -1
  53. package/dist/chunk-TBUCZX4A.js +34 -0
  54. package/dist/chunk-TBUCZX4A.js.map +1 -0
  55. package/dist/chunk-V7KUDHDG.js +276 -0
  56. package/dist/chunk-V7KUDHDG.js.map +1 -0
  57. package/dist/chunk-Y2KL55OG.js +59 -0
  58. package/dist/chunk-Y2KL55OG.js.map +1 -0
  59. package/dist/cli/args.d.ts +3 -3
  60. package/dist/cli/args.d.ts.map +1 -1
  61. package/dist/cli/commands/annotate.d.ts +11 -0
  62. package/dist/cli/commands/annotate.d.ts.map +1 -1
  63. package/dist/cli/commands/canvas.d.ts +45 -0
  64. package/dist/cli/commands/canvas.d.ts.map +1 -0
  65. package/dist/cli/commands/devtools/perf.d.ts.map +1 -1
  66. package/dist/cli/commands/devtools/screenshot.d.ts +1 -0
  67. package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -1
  68. package/dist/cli/commands/dom/attr.d.ts.map +1 -1
  69. package/dist/cli/commands/dom/checked.d.ts.map +1 -1
  70. package/dist/cli/commands/dom/enabled.d.ts.map +1 -1
  71. package/dist/cli/commands/dom/html.d.ts.map +1 -1
  72. package/dist/cli/commands/dom/text.d.ts.map +1 -1
  73. package/dist/cli/commands/dom/value.d.ts.map +1 -1
  74. package/dist/cli/commands/dom/visible.d.ts.map +1 -1
  75. package/dist/cli/commands/export/clone-component.d.ts +9 -0
  76. package/dist/cli/commands/export/clone-component.d.ts.map +1 -1
  77. package/dist/cli/commands/export/clone-page.d.ts +8 -0
  78. package/dist/cli/commands/export/clone-page.d.ts.map +1 -1
  79. package/dist/cli/commands/interact/check.d.ts.map +1 -1
  80. package/dist/cli/commands/interact/click.d.ts.map +1 -1
  81. package/dist/cli/commands/interact/hover.d.ts.map +1 -1
  82. package/dist/cli/commands/interact/press.d.ts.map +1 -1
  83. package/dist/cli/commands/interact/scroll-into-view.d.ts.map +1 -1
  84. package/dist/cli/commands/interact/scroll.d.ts.map +1 -1
  85. package/dist/cli/commands/interact/select.d.ts.map +1 -1
  86. package/dist/cli/commands/interact/type.d.ts.map +1 -1
  87. package/dist/cli/commands/interact/uncheck.d.ts.map +1 -1
  88. package/dist/cli/commands/native.d.ts +12 -1
  89. package/dist/cli/commands/native.d.ts.map +1 -1
  90. package/dist/cli/commands/nav/goto.d.ts.map +1 -1
  91. package/dist/cli/commands/nav/snapshot.d.ts.map +1 -1
  92. package/dist/cli/commands/nav/wait.d.ts.map +1 -1
  93. package/dist/cli/commands/serve.d.ts +5 -0
  94. package/dist/cli/commands/serve.d.ts.map +1 -1
  95. package/dist/cli/commands/session/connect.d.ts.map +1 -1
  96. package/dist/cli/commands/status.d.ts +5 -0
  97. package/dist/cli/commands/status.d.ts.map +1 -1
  98. package/dist/cli/daemon-commands.d.ts.map +1 -1
  99. package/dist/cli/help.d.ts +5 -0
  100. package/dist/cli/help.d.ts.map +1 -1
  101. package/dist/cli/index.js +724 -163
  102. package/dist/cli/index.js.map +1 -1
  103. package/dist/cli/remote-canvas-manager.d.ts +8 -0
  104. package/dist/cli/remote-canvas-manager.d.ts.map +1 -0
  105. package/dist/cli/remote-manager.d.ts +3 -1
  106. package/dist/cli/remote-manager.d.ts.map +1 -1
  107. package/dist/cli/remote-relay.d.ts +2 -0
  108. package/dist/cli/remote-relay.d.ts.map +1 -1
  109. package/dist/cli/utils/parse.d.ts +1 -0
  110. package/dist/cli/utils/parse.d.ts.map +1 -1
  111. package/dist/core/bootstrap.d.ts.map +1 -1
  112. package/dist/core/types.d.ts +2 -0
  113. package/dist/core/types.d.ts.map +1 -1
  114. package/dist/fs-UMRKOBNN.js +7 -0
  115. package/dist/fs-UMRKOBNN.js.map +1 -0
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +192 -67
  118. package/dist/index.js.map +1 -1
  119. package/dist/{macros-NUBRM44Y.js → macros-ND2M7LWU.js} +2 -2
  120. package/dist/opendevbrowser.d.ts.map +1 -1
  121. package/dist/opendevbrowser.js +192 -67
  122. package/dist/opendevbrowser.js.map +1 -1
  123. package/dist/providers/index.d.ts.map +1 -1
  124. package/dist/providers/shopping/index.d.ts.map +1 -1
  125. package/dist/providers-G3LRHQXX.js +121 -0
  126. package/dist/providers-G3LRHQXX.js.map +1 -0
  127. package/dist/relay/protocol.d.ts +85 -3
  128. package/dist/relay/protocol.d.ts.map +1 -1
  129. package/dist/relay/relay-server.d.ts +14 -1
  130. package/dist/relay/relay-server.d.ts.map +1 -1
  131. package/dist/relay/relay-types.d.ts +3 -0
  132. package/dist/relay/relay-types.d.ts.map +1 -1
  133. package/dist/runtime-factory-BICHDPE7.js +13 -0
  134. package/dist/runtime-factory-BICHDPE7.js.map +1 -0
  135. package/dist/tools/annotate.d.ts.map +1 -1
  136. package/dist/tools/canvas.d.ts +4 -0
  137. package/dist/tools/canvas.d.ts.map +1 -0
  138. package/dist/tools/check.d.ts.map +1 -1
  139. package/dist/tools/click.d.ts.map +1 -1
  140. package/dist/tools/clone_component.d.ts.map +1 -1
  141. package/dist/tools/clone_page.d.ts.map +1 -1
  142. package/dist/tools/connect.d.ts.map +1 -1
  143. package/dist/tools/deps.d.ts +2 -0
  144. package/dist/tools/deps.d.ts.map +1 -1
  145. package/dist/tools/dom_get_html.d.ts.map +1 -1
  146. package/dist/tools/dom_get_text.d.ts.map +1 -1
  147. package/dist/tools/get_attr.d.ts.map +1 -1
  148. package/dist/tools/get_value.d.ts.map +1 -1
  149. package/dist/tools/goto.d.ts.map +1 -1
  150. package/dist/tools/hover.d.ts.map +1 -1
  151. package/dist/tools/index.d.ts.map +1 -1
  152. package/dist/tools/is_checked.d.ts.map +1 -1
  153. package/dist/tools/is_enabled.d.ts.map +1 -1
  154. package/dist/tools/is_visible.d.ts.map +1 -1
  155. package/dist/tools/launch.d.ts.map +1 -1
  156. package/dist/tools/macro_resolve.d.ts.map +1 -1
  157. package/dist/tools/perf.d.ts.map +1 -1
  158. package/dist/tools/press.d.ts.map +1 -1
  159. package/dist/tools/product_video_run.d.ts.map +1 -1
  160. package/dist/tools/research_run.d.ts.map +1 -1
  161. package/dist/tools/response.d.ts +4 -1
  162. package/dist/tools/response.d.ts.map +1 -1
  163. package/dist/tools/screenshot.d.ts.map +1 -1
  164. package/dist/tools/scroll.d.ts.map +1 -1
  165. package/dist/tools/scroll_into_view.d.ts.map +1 -1
  166. package/dist/tools/select.d.ts.map +1 -1
  167. package/dist/tools/shopping_run.d.ts.map +1 -1
  168. package/dist/tools/snapshot.d.ts.map +1 -1
  169. package/dist/tools/type.d.ts.map +1 -1
  170. package/dist/tools/uncheck.d.ts.map +1 -1
  171. package/dist/tools/wait.d.ts.map +1 -1
  172. package/dist/tools/workflow-runtime.d.ts +1 -2
  173. package/dist/tools/workflow-runtime.d.ts.map +1 -1
  174. package/extension/canvas.html +636 -0
  175. package/extension/dist/annotate-content.css +15 -6
  176. package/extension/dist/annotate-content.js +119 -9
  177. package/extension/dist/annotation-payload.js +163 -0
  178. package/extension/dist/background.js +148 -18
  179. package/extension/dist/canvas/canvas-runtime.js +1061 -0
  180. package/extension/dist/canvas/model.js +213 -0
  181. package/extension/dist/canvas/viewport-fit.js +67 -0
  182. package/extension/dist/canvas-page.js +1801 -0
  183. package/extension/dist/ops/dom-bridge.js +116 -3
  184. package/extension/dist/ops/ops-runtime.js +508 -44
  185. package/extension/dist/ops/ops-session-store.js +21 -114
  186. package/extension/dist/ops/target-session-coordinator.js +157 -0
  187. package/extension/dist/popup.js +155 -31
  188. package/extension/dist/services/ConnectionManager.js +17 -0
  189. package/extension/dist/services/RelayClient.js +9 -0
  190. package/extension/dist/services/TabManager.js +35 -12
  191. package/extension/dist/types.js +2 -0
  192. package/extension/manifest.json +1 -1
  193. package/extension/popup.html +52 -0
  194. package/package.json +6 -4
  195. package/skills/AGENTS.md +5 -2
  196. package/skills/opendevbrowser-best-practices/SKILL.md +71 -3
  197. package/skills/opendevbrowser-best-practices/artifacts/canvas-governance-playbook.md +141 -0
  198. package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +113 -17
  199. package/skills/opendevbrowser-best-practices/assets/templates/canvas-blocker-checklist.json +70 -0
  200. package/skills/opendevbrowser-best-practices/assets/templates/canvas-feedback-eval.json +73 -0
  201. package/skills/opendevbrowser-best-practices/assets/templates/canvas-generation-plan.v1.json +67 -0
  202. package/skills/opendevbrowser-best-practices/assets/templates/canvas-handshake-example.json +126 -0
  203. package/skills/opendevbrowser-best-practices/assets/templates/robustness-checklist.json +57 -0
  204. package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +7 -3
  205. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +26 -0
  206. package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +82 -1
  207. package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +225 -84
  208. package/dist/chunk-ST7CO5FA.js.map +0 -1
  209. /package/dist/{chunk-7W3SPXIB.js.map → chunk-FUSXMW3G.js.map} +0 -0
  210. /package/dist/{macros-NUBRM44Y.js.map → macros-ND2M7LWU.js.map} +0 -0
package/dist/cli/index.js CHANGED
@@ -6,7 +6,6 @@ import {
6
6
  EXIT_USAGE,
7
7
  buildAnnotateResult,
8
8
  callDaemon,
9
- cleanupExpiredArtifacts,
10
9
  createOpenDevBrowserCore,
11
10
  createUsageError,
12
11
  extractExtension,
@@ -20,10 +19,17 @@ import {
20
19
  readDaemonMetadata,
21
20
  resolveExitCode,
22
21
  startDaemon,
23
- toCliError,
22
+ toCliError
23
+ } from "../chunk-5J3IFL3X.js";
24
+ import "../chunk-Y2KL55OG.js";
25
+ import {
24
26
  writeFileAtomic
25
- } from "../chunk-ST7CO5FA.js";
26
- import "../chunk-7W3SPXIB.js";
27
+ } from "../chunk-TBUCZX4A.js";
28
+ import "../chunk-V7KUDHDG.js";
29
+ import {
30
+ cleanupExpiredArtifacts
31
+ } from "../chunk-D633UO34.js";
32
+ import "../chunk-FUSXMW3G.js";
27
33
 
28
34
  // src/cli/args.ts
29
35
  var CLI_COMMANDS = [
@@ -81,6 +87,7 @@ var CLI_COMMANDS = [
81
87
  "cookie-list",
82
88
  "macro-resolve",
83
89
  "annotate",
90
+ "canvas",
84
91
  "rpc"
85
92
  ];
86
93
  var CLI_COMMAND_SET = new Set(CLI_COMMANDS);
@@ -207,6 +214,7 @@ var VALID_FLAGS = [
207
214
  "--expression",
208
215
  "--default-provider",
209
216
  "--include-catalog",
217
+ "--command",
210
218
  "--execute",
211
219
  "--params",
212
220
  "--params-file",
@@ -224,6 +232,7 @@ var VALID_FLAGS = [
224
232
  "--screenshot-mode",
225
233
  "--debug",
226
234
  "--context",
235
+ "--stored",
227
236
  "--topic",
228
237
  "--days",
229
238
  "--from",
@@ -269,6 +278,7 @@ var VALID_EQUALS_FLAGS = [
269
278
  "--persist-profile",
270
279
  "--expression",
271
280
  "--default-provider",
281
+ "--command",
272
282
  "--request-id",
273
283
  "--strict",
274
284
  "--params",
@@ -441,7 +451,7 @@ function listCommands() {
441
451
 
442
452
  // src/cli/help.ts
443
453
  var LABEL_WIDTH = 42;
444
- var EXPECTED_TOOL_COUNT = 48;
454
+ var EXPECTED_TOOL_COUNT = 49;
445
455
  var COMMAND_SET = new Set(CLI_COMMANDS);
446
456
  var FLAG_SET = new Set(VALID_FLAGS);
447
457
  var HELP_COMMAND_GROUPS = [
@@ -465,6 +475,11 @@ var HELP_COMMAND_GROUPS = [
465
475
  summary: "Run research/shopping/media workflows and macro plans.",
466
476
  commands: ["research", "shopping", "product-video", "artifacts", "macro-resolve"]
467
477
  },
478
+ {
479
+ title: "Design Canvas",
480
+ summary: "Execute design-canvas session, document, overlay, and preview commands.",
481
+ commands: ["canvas"]
482
+ },
468
483
  {
469
484
  title: "Navigation",
470
485
  summary: "Move through pages and capture fresh refs.",
@@ -522,7 +537,7 @@ var HELP_FLAG_GROUPS = [
522
537
  { flag: "--help", alias: "-h", description: "Show CLI help output." },
523
538
  { flag: "--version", alias: "-v", description: "Show CLI version." },
524
539
  { flag: "--output-format", description: "Output mode: text, json, stream-json." },
525
- { flag: "--transport", description: "Annotation transport: relay (default) or native." }
540
+ { flag: "--transport", description: "Transport selector for transport-aware commands. `status` uses relay/native; `annotate` uses auto/direct/relay." }
526
541
  ]
527
542
  },
528
543
  {
@@ -543,7 +558,7 @@ var HELP_FLAG_GROUPS = [
543
558
  { flag: "--profile", description: "Use a named browser profile directory." },
544
559
  { flag: "--persist-profile", description: "Keep generated profile directory after exit." },
545
560
  { flag: "--chrome-path", description: "Use a specific Chrome/Chromium binary." },
546
- { flag: "--start-url", description: "Open this URL immediately after launch." },
561
+ { flag: "--start-url", description: "Open this URL immediately after launch or connect." },
547
562
  { flag: "--flag", description: "Pass one or more extra Chrome CLI flags." },
548
563
  { flag: "--no-extension", description: "Force managed mode without extension relay." },
549
564
  { flag: "--extension-only", description: "Fail unless extension relay is connected." },
@@ -558,7 +573,7 @@ var HELP_FLAG_GROUPS = [
558
573
  flags: [
559
574
  { flag: "--url", description: "Target URL for navigation, connect, or workflow commands." },
560
575
  { flag: "--wait-until", description: "Navigation wait strategy (load, domcontentloaded, etc.)." },
561
- { flag: "--timeout-ms", description: "Operation timeout in milliseconds (for example goto, wait, screenshot, annotate, rpc, and macro-resolve)." },
576
+ { flag: "--timeout-ms", description: "Operation timeout in milliseconds (for example goto, wait, screenshot, annotate, canvas, rpc, and macro-resolve)." },
562
577
  { flag: "--ref", description: "Snapshot ref id for element-targeted commands." },
563
578
  { flag: "--state", description: "Wait state selector for wait-style commands." },
564
579
  { flag: "--until", description: "Wait condition selector for wait-style commands." },
@@ -586,9 +601,10 @@ var HELP_FLAG_GROUPS = [
586
601
  { flag: "--cookies", description: "Inline cookie payload for cookie-import command." },
587
602
  { flag: "--cookies-file", description: "File path containing cookies for cookie-import." },
588
603
  { flag: "--strict", description: "Fail cookie import on invalid entries." },
589
- { flag: "--screenshot-mode", description: "Annotation screenshot mode: crop, full, or none." },
604
+ { flag: "--screenshot-mode", description: "Annotation screenshot mode: visible, full, or none." },
590
605
  { flag: "--debug", description: "Enable debug-level annotation capture extras." },
591
- { flag: "--context", description: "Free-form annotation context for reviewers/agents." }
606
+ { flag: "--context", description: "Free-form annotation context for reviewers/agents." },
607
+ { flag: "--stored", description: "Return the last stored annotation payload instead of starting a new capture." }
592
608
  ]
593
609
  },
594
610
  {
@@ -599,8 +615,9 @@ var HELP_FLAG_GROUPS = [
599
615
  { flag: "--default-provider", description: "Provider fallback for shorthand macro expressions." },
600
616
  { flag: "--include-catalog", description: "Include macro catalog metadata in response." },
601
617
  { flag: "--execute", description: "Execute resolved macro action after planning (pair with --timeout-ms on slow runs)." },
602
- { flag: "--params", description: "Inline JSON params for rpc command." },
603
- { flag: "--params-file", description: "Path to JSON params file for rpc command." },
618
+ { flag: "--command", description: "Canvas command name for the canvas CLI command." },
619
+ { flag: "--params", description: "Inline JSON params for canvas or rpc commands." },
620
+ { flag: "--params-file", description: "Path to JSON params file for canvas or rpc commands." },
604
621
  { flag: "--unsafe-internal", description: "Required safety gate for rpc command." },
605
622
  { flag: "--topic", description: "Research topic input." },
606
623
  { flag: "--days", description: "Lookback window in days for research commands." },
@@ -618,7 +635,7 @@ var HELP_FLAG_GROUPS = [
618
635
  { flag: "--product-url", description: "Target product URL for product-video/artifacts workflows." },
619
636
  { flag: "--product-name", description: "Product name override for media workflows." },
620
637
  { flag: "--provider-hint", description: "Provider hint override for product workflows." },
621
- { flag: "--include-screenshots", description: "Include screenshots in product presentation output." },
638
+ { flag: "--include-screenshots", description: "Include screenshots in product presentation output, or prefer screenshots when fetching stored annotations." },
622
639
  { flag: "--include-all-images", description: "Include all discovered product images." },
623
640
  { flag: "--include-copy", description: "Include product marketing copy metadata." },
624
641
  { flag: "--output-dir", description: "Directory where generated artifacts are written." },
@@ -669,6 +686,7 @@ var HELP_TOOL_ENTRIES = [
669
686
  { name: "opendevbrowser_research_run", description: "Run research workflow directly." },
670
687
  { name: "opendevbrowser_shopping_run", description: "Run shopping workflow directly." },
671
688
  { name: "opendevbrowser_product_video_run", description: "Run product-video asset workflow directly." },
689
+ { name: "opendevbrowser_canvas", description: "Execute a design-canvas command surface call." },
672
690
  { name: "opendevbrowser_clone_page", description: "Export active page into React code." },
673
691
  { name: "opendevbrowser_clone_component", description: "Export component by ref into React code." },
674
692
  { name: "opendevbrowser_perf", description: "Collect browser performance metrics." },
@@ -681,7 +699,8 @@ var HELP_REFERENCE_ENTRIES = [
681
699
  { label: "docs/CLI.md", description: "Full command docs, flag matrix, and examples." },
682
700
  { label: "docs/SURFACE_REFERENCE.md", description: "Canonical CLI/tool/channel inventory matrix." },
683
701
  { label: "src/tools/index.ts", description: "Code-level tool registry (source of truth)." },
684
- { label: "opendevbrowser --help", description: "Always safe first command for quick discovery." }
702
+ { label: "opendevbrowser --help", description: "Primary full help invocation for quick discovery." },
703
+ { label: "opendevbrowser help", description: "Alias that prints the same full help inventory." }
685
704
  ];
686
705
  function formatRows(rows) {
687
706
  return rows.map((row) => ` ${row.label.padEnd(LABEL_WIDTH)} ${row.description}`).join("\n");
@@ -1379,6 +1398,26 @@ function parseNumberFlag(value, flag, options = {}) {
1379
1398
  }
1380
1399
  return parsed;
1381
1400
  }
1401
+ function parseOptionalStringFlag(rawArgs, flag) {
1402
+ for (let i = 0; i < rawArgs.length; i += 1) {
1403
+ const arg = rawArgs[i];
1404
+ if (arg === flag) {
1405
+ const value = rawArgs[i + 1];
1406
+ if (!value) {
1407
+ throw createUsageError(`Missing value for ${flag}`);
1408
+ }
1409
+ return value;
1410
+ }
1411
+ if (arg?.startsWith(`${flag}=`)) {
1412
+ const value = arg.split("=", 2)[1];
1413
+ if (!value) {
1414
+ throw createUsageError(`Missing value for ${flag}`);
1415
+ }
1416
+ return value;
1417
+ }
1418
+ }
1419
+ return void 0;
1420
+ }
1382
1421
 
1383
1422
  // src/cli/commands/native.ts
1384
1423
  import * as fs9 from "fs";
@@ -1620,39 +1659,6 @@ var getExtensionPathCandidates = () => {
1620
1659
  }
1621
1660
  return [...candidates];
1622
1661
  };
1623
- var getNativeStatusSnapshot = () => {
1624
- const hostScript = getHostScriptPath();
1625
- const manifestPath = getManifestPath();
1626
- const wrapperPath = getWrapperPath();
1627
- const registryPath = readRegistryPath();
1628
- let installed = false;
1629
- let manifestExists = false;
1630
- let wrapperExists = false;
1631
- let extensionIdValue = null;
1632
- if (fs9.existsSync(manifestPath)) {
1633
- manifestExists = true;
1634
- installed = true;
1635
- const manifest = readManifest(manifestPath);
1636
- extensionIdValue = manifest.extensionId;
1637
- }
1638
- if (fs9.existsSync(wrapperPath)) {
1639
- wrapperExists = true;
1640
- }
1641
- if (!manifestExists || !wrapperExists) {
1642
- installed = false;
1643
- }
1644
- if (process.platform === "win32" && !registryPath) {
1645
- installed = false;
1646
- }
1647
- return {
1648
- installed,
1649
- manifestPath: manifestExists ? manifestPath : null,
1650
- wrapperPath: wrapperExists ? wrapperPath : null,
1651
- hostScriptPath: hostScript,
1652
- extensionId: extensionIdValue,
1653
- registryPath
1654
- };
1655
- };
1656
1662
  function discoverExtensionId() {
1657
1663
  const extensionPaths = getExtensionPathCandidates();
1658
1664
  const roots = getChromeUserDataRoots();
@@ -1687,6 +1693,81 @@ function discoverExtensionId() {
1687
1693
  }
1688
1694
  return { extensionId: null };
1689
1695
  }
1696
+ var resolveExpectedExtension = () => {
1697
+ let configuredExtensionId = null;
1698
+ try {
1699
+ configuredExtensionId = normalizeExtensionId(loadGlobalConfig().nativeExtensionId);
1700
+ } catch {
1701
+ configuredExtensionId = null;
1702
+ }
1703
+ const discovered = discoverExtensionId();
1704
+ const discoveredExtensionId = discovered.extensionId ?? null;
1705
+ const discoveredMatchedBy = discovered.matchedBy ?? null;
1706
+ if (discoveredExtensionId) {
1707
+ return {
1708
+ discoveredExtensionId,
1709
+ discoveredMatchedBy,
1710
+ expectedExtensionId: discoveredExtensionId,
1711
+ expectedExtensionSource: discoveredMatchedBy
1712
+ };
1713
+ }
1714
+ if (configuredExtensionId) {
1715
+ return {
1716
+ discoveredExtensionId,
1717
+ discoveredMatchedBy,
1718
+ expectedExtensionId: configuredExtensionId,
1719
+ expectedExtensionSource: "config"
1720
+ };
1721
+ }
1722
+ return {
1723
+ discoveredExtensionId,
1724
+ discoveredMatchedBy,
1725
+ expectedExtensionId: null,
1726
+ expectedExtensionSource: null
1727
+ };
1728
+ };
1729
+ var getNativeStatusSnapshot = () => {
1730
+ const expectation = resolveExpectedExtension();
1731
+ const hostScript = getHostScriptPath();
1732
+ const manifestPath = getManifestPath();
1733
+ const wrapperPath = getWrapperPath();
1734
+ const registryPath = readRegistryPath();
1735
+ let installed = false;
1736
+ let manifestExists = false;
1737
+ let wrapperExists = false;
1738
+ let extensionIdValue = null;
1739
+ if (fs9.existsSync(manifestPath)) {
1740
+ manifestExists = true;
1741
+ installed = true;
1742
+ const manifest = readManifest(manifestPath);
1743
+ extensionIdValue = manifest.extensionId;
1744
+ }
1745
+ if (fs9.existsSync(wrapperPath)) {
1746
+ wrapperExists = true;
1747
+ }
1748
+ if (!manifestExists || !wrapperExists) {
1749
+ installed = false;
1750
+ }
1751
+ if (process.platform === "win32" && !registryPath) {
1752
+ installed = false;
1753
+ }
1754
+ const mismatch = Boolean(
1755
+ installed && extensionIdValue && expectation.expectedExtensionId && extensionIdValue !== expectation.expectedExtensionId
1756
+ );
1757
+ return {
1758
+ installed,
1759
+ manifestPath: manifestExists ? manifestPath : null,
1760
+ wrapperPath: wrapperExists ? wrapperPath : null,
1761
+ hostScriptPath: hostScript,
1762
+ extensionId: extensionIdValue,
1763
+ registryPath,
1764
+ discoveredExtensionId: expectation.discoveredExtensionId,
1765
+ discoveredMatchedBy: expectation.discoveredMatchedBy,
1766
+ expectedExtensionId: expectation.expectedExtensionId,
1767
+ expectedExtensionSource: expectation.expectedExtensionSource,
1768
+ mismatch
1769
+ };
1770
+ };
1690
1771
  function installNativeHost(extensionId) {
1691
1772
  const normalized = normalizeExtensionId(extensionId);
1692
1773
  if (!normalized) {
@@ -1748,6 +1829,14 @@ async function runNativeCommand(args) {
1748
1829
  exitCode: EXIT_DISCONNECTED
1749
1830
  };
1750
1831
  }
1832
+ if (data.mismatch && data.extensionId && data.expectedExtensionId) {
1833
+ return {
1834
+ success: false,
1835
+ message: `Native host targets ${data.extensionId}, but the current extension is ${data.expectedExtensionId}. Reinstall with \`opendevbrowser native install ${data.expectedExtensionId}\` or rerun \`opendevbrowser serve\`.`,
1836
+ data,
1837
+ exitCode: EXIT_DISCONNECTED
1838
+ };
1839
+ }
1751
1840
  const message = data.extensionId ? `Native host installed for extension ${data.extensionId}.` : "Native host installed (extension id missing).";
1752
1841
  return { success: true, message, data };
1753
1842
  }
@@ -1917,19 +2006,22 @@ async function runServe(args) {
1917
2006
  }
1918
2007
  let nativeStatus = getNativeStatusSnapshot();
1919
2008
  let nativeMessage = null;
1920
- if (!nativeStatus.installed) {
2009
+ if (!nativeStatus.installed || nativeStatus.mismatch) {
1921
2010
  const discovered = discoverExtensionId();
1922
- const extensionId = config.nativeExtensionId ?? discovered.extensionId ?? null;
1923
- const usedDiscovery = !config.nativeExtensionId && Boolean(discovered.extensionId);
2011
+ const extensionId = nativeStatus.expectedExtensionId ?? config.nativeExtensionId ?? discovered.extensionId ?? null;
2012
+ const usedDiscovery = nativeStatus.expectedExtensionSource !== "config" && Boolean(extensionId);
2013
+ const previousExtensionId = nativeStatus.extensionId;
1924
2014
  if (extensionId) {
1925
2015
  const installResult = installNativeHost(extensionId);
1926
2016
  if (installResult.success) {
1927
2017
  const suffix = usedDiscovery && discovered.matchedBy ? ` (auto-detected by ${discovered.matchedBy})` : "";
1928
- nativeMessage = `${installResult.message ?? "Native host installed."}${suffix}`;
2018
+ nativeMessage = nativeStatus.mismatch && previousExtensionId ? `Native host reinstalled for extension ${extensionId} (replacing stale ${previousExtensionId}).${suffix}` : `${installResult.message ?? "Native host installed."}${suffix}`;
1929
2019
  nativeStatus = getNativeStatusSnapshot();
1930
2020
  } else {
1931
- nativeMessage = `Native host install skipped: ${installResult.message ?? "unknown error"}`;
2021
+ nativeMessage = nativeStatus.mismatch ? `Native host reinstall skipped: ${installResult.message ?? "unknown error"}` : `Native host install skipped: ${installResult.message ?? "unknown error"}`;
1932
2022
  }
2023
+ } else if (nativeStatus.mismatch && previousExtensionId) {
2024
+ nativeMessage = `Native host targets stale extension ${previousExtensionId}, but no current extension id could be resolved for reinstall.`;
1933
2025
  } else {
1934
2026
  nativeMessage = "Native host not installed. Set nativeExtensionId in opendevbrowser.jsonc to auto-install.";
1935
2027
  }
@@ -2778,6 +2870,19 @@ function parseConnectArgs(rawArgs) {
2778
2870
  parsed.port = parseNumberFlag(value, "--cdp-port", { min: 1, max: 65535 });
2779
2871
  continue;
2780
2872
  }
2873
+ if (arg === "--start-url") {
2874
+ const value = rawArgs[i + 1];
2875
+ if (!value) throw createUsageError("Missing value for --start-url");
2876
+ parsed.startUrl = value;
2877
+ i += 1;
2878
+ continue;
2879
+ }
2880
+ if (arg?.startsWith("--start-url=")) {
2881
+ const value = arg.split("=", 2)[1];
2882
+ if (!value) throw createUsageError("Missing value for --start-url");
2883
+ parsed.startUrl = value;
2884
+ continue;
2885
+ }
2781
2886
  if (arg === "--extension-legacy") {
2782
2887
  parsed.extensionLegacy = true;
2783
2888
  continue;
@@ -2900,6 +3005,14 @@ async function runStatus(args) {
2900
3005
  exitCode: EXIT_DISCONNECTED
2901
3006
  };
2902
3007
  }
3008
+ if (nativeStatus2.mismatch && nativeStatus2.extensionId && nativeStatus2.expectedExtensionId) {
3009
+ return {
3010
+ success: false,
3011
+ message: `Native host targets ${nativeStatus2.extensionId}, but the current extension is ${nativeStatus2.expectedExtensionId}.`,
3012
+ data: nativeStatus2,
3013
+ exitCode: EXIT_DISCONNECTED
3014
+ };
3015
+ }
2903
3016
  return {
2904
3017
  success: true,
2905
3018
  message: nativeStatus2.extensionId ? `Native host installed for extension ${nativeStatus2.extensionId}.` : "Native host installed.",
@@ -2911,12 +3024,13 @@ async function runStatus(args) {
2911
3024
  throw createUsageError("Daemon not running. Start with `opendevbrowser serve`.");
2912
3025
  }
2913
3026
  const nativeStatus = getNativeStatusSnapshot();
3027
+ const nativeSummary = !nativeStatus.installed ? "not installed" : nativeStatus.mismatch && nativeStatus.extensionId && nativeStatus.expectedExtensionId ? `mismatch (${nativeStatus.extensionId} != ${nativeStatus.expectedExtensionId})` : `installed${nativeStatus.extensionId ? ` (${nativeStatus.extensionId})` : ""}`;
2914
3028
  const baseMessage = [
2915
3029
  `Daemon OK (pid=${daemonStatus.pid})`,
2916
- `Relay: port=${daemonStatus.relay.port ?? "n/a"} ext=${daemonStatus.relay.extensionConnected ? "on" : "off"} handshake=${daemonStatus.relay.extensionHandshakeComplete ? "on" : "off"} cdp=${daemonStatus.relay.cdpConnected ? "on" : "off"} annotate=${daemonStatus.relay.annotationConnected ? "on" : "off"} ops=${daemonStatus.relay.opsConnected ? "on" : "off"} pairing=${daemonStatus.relay.pairingRequired ? "on" : "off"} health=${daemonStatus.relay.health?.reason ?? "n/a"}`,
2917
- `Native: ${nativeStatus.installed ? "installed" : "not installed"}${nativeStatus.extensionId ? ` (${nativeStatus.extensionId})` : ""}`,
3030
+ `Relay: port=${daemonStatus.relay.port ?? "n/a"} ext=${daemonStatus.relay.extensionConnected ? "on" : "off"} handshake=${daemonStatus.relay.extensionHandshakeComplete ? "on" : "off"} cdp=${daemonStatus.relay.cdpConnected ? "on" : "off"} annotate=${daemonStatus.relay.annotationConnected ? "on" : "off"} ops=${daemonStatus.relay.opsConnected ? "on" : "off"} canvas=${daemonStatus.relay.canvasConnected ? "on" : "off"} pairing=${daemonStatus.relay.pairingRequired ? "on" : "off"} health=${daemonStatus.relay.health?.reason ?? "n/a"}`,
3031
+ `Native: ${nativeSummary}`,
2918
3032
  daemonStatus.relay.lastHandshakeError ? `Relay last handshake error: ${daemonStatus.relay.lastHandshakeError.code} (${daemonStatus.relay.lastHandshakeError.message})` : "Relay last handshake error: none",
2919
- "Legend: ext=extension websocket, handshake=extension handshake, cdp=active /cdp client, annotate=annotation channel, ops=ops clients, pairing=token required, health=relay status"
3033
+ "Legend: ext=extension websocket, handshake=extension handshake, cdp=active /cdp client, annotate=annotation channel, ops=ops clients, canvas=canvas clients, pairing=token required, health=relay status"
2920
3034
  ].join("\n");
2921
3035
  const message = daemon || args.outputFormat !== "text" ? baseMessage : [
2922
3036
  "Warning: `status` defaults to daemon status. Use --daemon explicitly or --session-id for session status.",
@@ -2985,9 +3099,16 @@ function parseGotoArgs(rawArgs) {
2985
3099
  }
2986
3100
  async function runGoto(args) {
2987
3101
  const { sessionId, url, waitUntil, timeoutMs } = parseGotoArgs(args.rawArgs);
3102
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
2988
3103
  if (!sessionId) throw createUsageError("Missing --session-id");
2989
3104
  if (!url) throw createUsageError("Missing --url");
2990
- const result = await callDaemon("nav.goto", { sessionId, url, waitUntil, timeoutMs });
3105
+ const result = await callDaemon("nav.goto", {
3106
+ sessionId,
3107
+ url,
3108
+ waitUntil,
3109
+ timeoutMs,
3110
+ ...typeof targetId === "string" ? { targetId } : {}
3111
+ });
2991
3112
  return { success: true, message: `Navigated: ${url}`, data: result };
2992
3113
  }
2993
3114
 
@@ -3058,8 +3179,16 @@ function parseWaitArgs(rawArgs) {
3058
3179
  }
3059
3180
  async function runWait(args) {
3060
3181
  const { sessionId, ref, state, until, timeoutMs } = parseWaitArgs(args.rawArgs);
3182
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3061
3183
  if (!sessionId) throw createUsageError("Missing --session-id");
3062
- const result = await callDaemon("nav.wait", { sessionId, ref, state, until, timeoutMs });
3184
+ const result = await callDaemon("nav.wait", {
3185
+ sessionId,
3186
+ ref,
3187
+ state,
3188
+ until,
3189
+ timeoutMs,
3190
+ ...typeof targetId === "string" ? { targetId } : {}
3191
+ });
3063
3192
  return { success: true, message: "Wait complete.", data: result };
3064
3193
  }
3065
3194
 
@@ -3117,8 +3246,15 @@ function parseSnapshotArgs(rawArgs) {
3117
3246
  }
3118
3247
  async function runSnapshot(args) {
3119
3248
  const { sessionId, mode, maxChars, cursor } = parseSnapshotArgs(args.rawArgs);
3249
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3120
3250
  if (!sessionId) throw createUsageError("Missing --session-id");
3121
- const result = await callDaemon("nav.snapshot", { sessionId, mode, maxChars, cursor });
3251
+ const result = await callDaemon("nav.snapshot", {
3252
+ sessionId,
3253
+ mode,
3254
+ maxChars,
3255
+ cursor,
3256
+ ...typeof targetId === "string" ? { targetId } : {}
3257
+ });
3122
3258
  return { success: true, message: "Snapshot captured.", data: result };
3123
3259
  }
3124
3260
 
@@ -3154,6 +3290,14 @@ var parseAnnotateArgs = (rawArgs) => {
3154
3290
  parsed.sessionId = value;
3155
3291
  continue;
3156
3292
  }
3293
+ if (arg === "--stored") {
3294
+ parsed.stored = true;
3295
+ continue;
3296
+ }
3297
+ if (arg === "--include-screenshots") {
3298
+ parsed.includeScreenshots = true;
3299
+ continue;
3300
+ }
3157
3301
  if (arg === "--url") {
3158
3302
  const value = requireValue2(rawArgs[i + 1], "--url");
3159
3303
  parsed.url = value;
@@ -3239,13 +3383,27 @@ var parseAnnotateArgs = (rawArgs) => {
3239
3383
  return parsed;
3240
3384
  };
3241
3385
  async function runAnnotate(args) {
3242
- const { sessionId, url, screenshotMode, debug, context, timeoutMs, transport, targetId, tabId } = parseAnnotateArgs(args.rawArgs);
3386
+ const {
3387
+ sessionId,
3388
+ stored,
3389
+ includeScreenshots,
3390
+ url,
3391
+ screenshotMode,
3392
+ debug,
3393
+ context,
3394
+ timeoutMs,
3395
+ transport,
3396
+ targetId,
3397
+ tabId
3398
+ } = parseAnnotateArgs(args.rawArgs);
3243
3399
  if (!sessionId) throw createUsageError("Missing --session-id");
3244
3400
  const client = new DaemonClient({ autoRenew: true });
3245
3401
  const callTimeoutMs = typeof timeoutMs === "number" ? timeoutMs + 1e4 : void 0;
3246
3402
  try {
3247
3403
  const response = await client.call("annotate", {
3248
3404
  sessionId,
3405
+ stored,
3406
+ includeScreenshots,
3249
3407
  transport,
3250
3408
  targetId,
3251
3409
  tabId,
@@ -3255,6 +3413,13 @@ async function runAnnotate(args) {
3255
3413
  context,
3256
3414
  timeoutMs
3257
3415
  }, { timeoutMs: callTimeoutMs });
3416
+ if (response.status === "cancelled") {
3417
+ return {
3418
+ success: true,
3419
+ message: response.error?.message ?? "Annotation cancelled.",
3420
+ data: { cancelled: true }
3421
+ };
3422
+ }
3258
3423
  if (response.status !== "ok" || !response.payload) {
3259
3424
  const message2 = response.error?.message ?? "Annotation failed.";
3260
3425
  throw new Error(message2);
@@ -3267,8 +3432,130 @@ async function runAnnotate(args) {
3267
3432
  }
3268
3433
  }
3269
3434
 
3270
- // src/cli/commands/rpc.ts
3435
+ // src/cli/commands/canvas.ts
3271
3436
  import { readFileSync as readFileSync5 } from "fs";
3437
+ var DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS = 3e4;
3438
+ var MIN_FEEDBACK_STREAM_POLL_MS = 250;
3439
+ var MAX_FEEDBACK_STREAM_POLL_MS = 1e3;
3440
+ var isRecord = (value) => {
3441
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3442
+ };
3443
+ var asString = (value) => {
3444
+ return typeof value === "string" && value.length > 0 ? value : null;
3445
+ };
3446
+ var asNumber = (value) => {
3447
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
3448
+ };
3449
+ var asRecordArray = (value) => {
3450
+ return Array.isArray(value) ? value.filter(isRecord) : [];
3451
+ };
3452
+ var sleep = async (ms) => {
3453
+ await new Promise((resolve6) => setTimeout(resolve6, ms));
3454
+ };
3455
+ var toFeedbackPollResult = (value) => {
3456
+ if (!isRecord(value)) {
3457
+ return { items: [], nextCursor: null };
3458
+ }
3459
+ const retention = isRecord(value.retention) ? {
3460
+ activeTargetIds: Array.isArray(value.retention.activeTargetIds) ? value.retention.activeTargetIds.filter((entry) => typeof entry === "string") : void 0
3461
+ } : void 0;
3462
+ return {
3463
+ items: asRecordArray(value.items),
3464
+ nextCursor: asString(value.nextCursor),
3465
+ retention
3466
+ };
3467
+ };
3468
+ async function streamFeedbackViaPolling(client, args, canvasArgs, params, initial) {
3469
+ const outputOptions = { format: args.outputFormat, quiet: args.quiet };
3470
+ writeOutput({
3471
+ success: true,
3472
+ message: `Canvas executed: ${canvasArgs.command}`,
3473
+ data: {
3474
+ command: canvasArgs.command,
3475
+ result: initial
3476
+ }
3477
+ }, outputOptions);
3478
+ const heartbeatMs = Math.max(asNumber(initial.heartbeatMs) ?? 15e3, 1e3);
3479
+ const pollIntervalMs = Math.min(
3480
+ MAX_FEEDBACK_STREAM_POLL_MS,
3481
+ Math.max(MIN_FEEDBACK_STREAM_POLL_MS, Math.floor(heartbeatMs / 3))
3482
+ );
3483
+ const streamTimeoutMs = canvasArgs.timeoutMs ?? DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS;
3484
+ const deadline = Date.now() + streamTimeoutMs;
3485
+ let cursor = asString(initial.cursor);
3486
+ let lastHeartbeatAt = Date.now();
3487
+ while (Date.now() < deadline) {
3488
+ await sleep(pollIntervalMs);
3489
+ const remainingMs = deadline - Date.now();
3490
+ if (remainingMs <= 0) {
3491
+ break;
3492
+ }
3493
+ const polled = toFeedbackPollResult(await client.call(
3494
+ "canvas.execute",
3495
+ {
3496
+ command: "canvas.feedback.poll",
3497
+ params: {
3498
+ ...params,
3499
+ afterCursor: cursor
3500
+ }
3501
+ },
3502
+ { timeoutMs: remainingMs }
3503
+ ));
3504
+ if (polled.items.length > 0) {
3505
+ for (const item of polled.items) {
3506
+ const itemCursor = asString(item.cursor);
3507
+ if (itemCursor) {
3508
+ cursor = itemCursor;
3509
+ }
3510
+ writeOutput({
3511
+ success: true,
3512
+ message: `Canvas feedback: ${canvasArgs.command}`,
3513
+ data: {
3514
+ command: canvasArgs.command,
3515
+ streamEvent: {
3516
+ eventType: "feedback.item",
3517
+ item,
3518
+ cursor: cursor ?? null
3519
+ }
3520
+ }
3521
+ }, outputOptions);
3522
+ }
3523
+ lastHeartbeatAt = Date.now();
3524
+ continue;
3525
+ }
3526
+ if (polled.nextCursor) {
3527
+ cursor = polled.nextCursor;
3528
+ }
3529
+ if (Date.now() - lastHeartbeatAt >= heartbeatMs) {
3530
+ writeOutput({
3531
+ success: true,
3532
+ message: `Canvas feedback: ${canvasArgs.command}`,
3533
+ data: {
3534
+ command: canvasArgs.command,
3535
+ streamEvent: {
3536
+ eventType: "feedback.heartbeat",
3537
+ cursor: cursor ?? null,
3538
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
3539
+ activeTargetIds: polled.retention?.activeTargetIds ?? []
3540
+ }
3541
+ }
3542
+ }, outputOptions);
3543
+ lastHeartbeatAt = Date.now();
3544
+ }
3545
+ }
3546
+ writeOutput({
3547
+ success: true,
3548
+ message: `Canvas feedback: ${canvasArgs.command}`,
3549
+ data: {
3550
+ command: canvasArgs.command,
3551
+ streamEvent: {
3552
+ eventType: "feedback.complete",
3553
+ cursor: cursor ?? null,
3554
+ completeReason: "timeout"
3555
+ }
3556
+ }
3557
+ }, outputOptions);
3558
+ }
3272
3559
  var requireValue3 = (value, flag) => {
3273
3560
  if (!value) throw createUsageError(`Missing value for ${flag}`);
3274
3561
  return value;
@@ -3286,6 +3573,138 @@ var parseJsonObject = (raw, source) => {
3286
3573
  }
3287
3574
  return parsed;
3288
3575
  };
3576
+ var parseCanvasArgs = (rawArgs) => {
3577
+ const parsed = {};
3578
+ for (let i = 0; i < rawArgs.length; i += 1) {
3579
+ const arg = rawArgs[i];
3580
+ if (arg === "--command") {
3581
+ parsed.command = requireValue3(rawArgs[i + 1], "--command");
3582
+ i += 1;
3583
+ continue;
3584
+ }
3585
+ if (arg?.startsWith("--command=")) {
3586
+ parsed.command = requireValue3(arg.split("=", 2)[1], "--command");
3587
+ continue;
3588
+ }
3589
+ if (arg === "--params") {
3590
+ parsed.params = requireValue3(rawArgs[i + 1], "--params");
3591
+ i += 1;
3592
+ continue;
3593
+ }
3594
+ if (arg?.startsWith("--params=")) {
3595
+ parsed.params = requireValue3(arg.split("=", 2)[1], "--params");
3596
+ continue;
3597
+ }
3598
+ if (arg === "--params-file") {
3599
+ parsed.paramsFile = requireValue3(rawArgs[i + 1], "--params-file");
3600
+ i += 1;
3601
+ continue;
3602
+ }
3603
+ if (arg?.startsWith("--params-file=")) {
3604
+ parsed.paramsFile = requireValue3(arg.split("=", 2)[1], "--params-file");
3605
+ continue;
3606
+ }
3607
+ if (arg === "--timeout-ms") {
3608
+ parsed.timeoutMs = parseNumberFlag(requireValue3(rawArgs[i + 1], "--timeout-ms"), "--timeout-ms", { min: 1 });
3609
+ i += 1;
3610
+ continue;
3611
+ }
3612
+ if (arg?.startsWith("--timeout-ms=")) {
3613
+ parsed.timeoutMs = parseNumberFlag(requireValue3(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
3614
+ }
3615
+ }
3616
+ return parsed;
3617
+ };
3618
+ var resolveCanvasParams = (canvasArgs) => {
3619
+ const hasParams = typeof canvasArgs.params === "string";
3620
+ const hasParamsFile = typeof canvasArgs.paramsFile === "string";
3621
+ if (Number(hasParams) + Number(hasParamsFile) > 1) {
3622
+ throw createUsageError("Provide only one params source: --params or --params-file.");
3623
+ }
3624
+ if (hasParams) {
3625
+ return parseJsonObject(canvasArgs.params ?? "", "--params");
3626
+ }
3627
+ if (hasParamsFile) {
3628
+ let raw = "";
3629
+ try {
3630
+ raw = readFileSync5(canvasArgs.paramsFile ?? "", "utf8");
3631
+ } catch (error) {
3632
+ const message = error instanceof Error ? error.message : "Unable to read file";
3633
+ throw createUsageError(`Invalid --params-file: ${message}`);
3634
+ }
3635
+ if (!raw.trim()) {
3636
+ throw createUsageError("Invalid JSON from --params-file: empty input");
3637
+ }
3638
+ return parseJsonObject(raw, "--params-file");
3639
+ }
3640
+ return {};
3641
+ };
3642
+ async function runCanvas(args) {
3643
+ const canvasArgs = parseCanvasArgs(args.rawArgs);
3644
+ if (!canvasArgs.command) {
3645
+ throw createUsageError("Usage: opendevbrowser canvas --command <canvas.command> [--params <json> | --params-file <path>]");
3646
+ }
3647
+ if (!canvasArgs.command.startsWith("canvas.")) {
3648
+ throw createUsageError("Canvas command names must start with 'canvas.'.");
3649
+ }
3650
+ const client = new DaemonClient({ autoRenew: true });
3651
+ try {
3652
+ const params = resolveCanvasParams(canvasArgs);
3653
+ const result = await client.call(
3654
+ "canvas.execute",
3655
+ {
3656
+ command: canvasArgs.command,
3657
+ params
3658
+ },
3659
+ { timeoutMs: canvasArgs.timeoutMs }
3660
+ );
3661
+ if (canvasArgs.command === "canvas.feedback.subscribe" && args.outputFormat === "stream-json" && isRecord(result)) {
3662
+ await streamFeedbackViaPolling(client, args, canvasArgs, params, result);
3663
+ return {
3664
+ success: true,
3665
+ message: `Canvas executed: ${canvasArgs.command}`,
3666
+ data: {
3667
+ suppressOutput: true
3668
+ }
3669
+ };
3670
+ }
3671
+ if (args.outputFormat === "text") {
3672
+ const output = typeof result === "string" ? result : JSON.stringify(result, null, 2);
3673
+ return { success: true, message: output };
3674
+ }
3675
+ return {
3676
+ success: true,
3677
+ message: `Canvas executed: ${canvasArgs.command}`,
3678
+ data: {
3679
+ command: canvasArgs.command,
3680
+ result
3681
+ }
3682
+ };
3683
+ } finally {
3684
+ await client.releaseBinding().catch(() => {
3685
+ });
3686
+ }
3687
+ }
3688
+
3689
+ // src/cli/commands/rpc.ts
3690
+ import { readFileSync as readFileSync6 } from "fs";
3691
+ var requireValue4 = (value, flag) => {
3692
+ if (!value) throw createUsageError(`Missing value for ${flag}`);
3693
+ return value;
3694
+ };
3695
+ var parseJsonObject2 = (raw, source) => {
3696
+ let parsed;
3697
+ try {
3698
+ parsed = JSON.parse(raw);
3699
+ } catch (error) {
3700
+ const message = error instanceof Error ? error.message : "Invalid JSON";
3701
+ throw createUsageError(`Invalid JSON from ${source}: ${message}`);
3702
+ }
3703
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3704
+ throw createUsageError(`Invalid JSON from ${source}: expected object`);
3705
+ }
3706
+ return parsed;
3707
+ };
3289
3708
  var parseRpcArgs = (rawArgs) => {
3290
3709
  const parsed = {};
3291
3710
  for (let i = 0; i < rawArgs.length; i += 1) {
@@ -3295,40 +3714,40 @@ var parseRpcArgs = (rawArgs) => {
3295
3714
  continue;
3296
3715
  }
3297
3716
  if (arg === "--name") {
3298
- parsed.name = requireValue3(rawArgs[i + 1], "--name");
3717
+ parsed.name = requireValue4(rawArgs[i + 1], "--name");
3299
3718
  i += 1;
3300
3719
  continue;
3301
3720
  }
3302
3721
  if (arg?.startsWith("--name=")) {
3303
- parsed.name = requireValue3(arg.split("=", 2)[1], "--name");
3722
+ parsed.name = requireValue4(arg.split("=", 2)[1], "--name");
3304
3723
  continue;
3305
3724
  }
3306
3725
  if (arg === "--params") {
3307
- parsed.params = requireValue3(rawArgs[i + 1], "--params");
3726
+ parsed.params = requireValue4(rawArgs[i + 1], "--params");
3308
3727
  i += 1;
3309
3728
  continue;
3310
3729
  }
3311
3730
  if (arg?.startsWith("--params=")) {
3312
- parsed.params = requireValue3(arg.split("=", 2)[1], "--params");
3731
+ parsed.params = requireValue4(arg.split("=", 2)[1], "--params");
3313
3732
  continue;
3314
3733
  }
3315
3734
  if (arg === "--params-file") {
3316
- parsed.paramsFile = requireValue3(rawArgs[i + 1], "--params-file");
3735
+ parsed.paramsFile = requireValue4(rawArgs[i + 1], "--params-file");
3317
3736
  i += 1;
3318
3737
  continue;
3319
3738
  }
3320
3739
  if (arg?.startsWith("--params-file=")) {
3321
- parsed.paramsFile = requireValue3(arg.split("=", 2)[1], "--params-file");
3740
+ parsed.paramsFile = requireValue4(arg.split("=", 2)[1], "--params-file");
3322
3741
  continue;
3323
3742
  }
3324
3743
  if (arg === "--timeout-ms") {
3325
- const value = requireValue3(rawArgs[i + 1], "--timeout-ms");
3744
+ const value = requireValue4(rawArgs[i + 1], "--timeout-ms");
3326
3745
  parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
3327
3746
  i += 1;
3328
3747
  continue;
3329
3748
  }
3330
3749
  if (arg?.startsWith("--timeout-ms=")) {
3331
- const value = requireValue3(arg.split("=", 2)[1], "--timeout-ms");
3750
+ const value = requireValue4(arg.split("=", 2)[1], "--timeout-ms");
3332
3751
  parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
3333
3752
  continue;
3334
3753
  }
@@ -3343,12 +3762,12 @@ var resolveRpcParams = (rpcArgs) => {
3343
3762
  throw createUsageError("Provide only one params source: --params or --params-file.");
3344
3763
  }
3345
3764
  if (hasParamsArg) {
3346
- return parseJsonObject(rpcArgs.params ?? "", "--params");
3765
+ return parseJsonObject2(rpcArgs.params ?? "", "--params");
3347
3766
  }
3348
3767
  if (hasParamsFile) {
3349
3768
  let raw = "";
3350
3769
  try {
3351
- raw = readFileSync5(rpcArgs.paramsFile ?? "", "utf8");
3770
+ raw = readFileSync6(rpcArgs.paramsFile ?? "", "utf8");
3352
3771
  } catch (error) {
3353
3772
  const message = error instanceof Error ? error.message : "Unable to read file";
3354
3773
  throw createUsageError(`Invalid --params-file: ${message}`);
@@ -3356,7 +3775,7 @@ var resolveRpcParams = (rpcArgs) => {
3356
3775
  if (!raw.trim()) {
3357
3776
  throw createUsageError("Invalid JSON from --params-file: empty input");
3358
3777
  }
3359
- return parseJsonObject(raw, "--params-file");
3778
+ return parseJsonObject2(raw, "--params-file");
3360
3779
  }
3361
3780
  return {};
3362
3781
  };
@@ -3424,9 +3843,14 @@ function parseClickArgs(rawArgs) {
3424
3843
  }
3425
3844
  async function runClick(args) {
3426
3845
  const { sessionId, ref } = parseClickArgs(args.rawArgs);
3846
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3427
3847
  if (!sessionId) throw createUsageError("Missing --session-id");
3428
3848
  if (!ref) throw createUsageError("Missing --ref");
3429
- const result = await callDaemon("interact.click", { sessionId, ref });
3849
+ const result = await callDaemon("interact.click", {
3850
+ sessionId,
3851
+ ref,
3852
+ ...typeof targetId === "string" ? { targetId } : {}
3853
+ });
3430
3854
  return { success: true, message: "Click complete.", data: result };
3431
3855
  }
3432
3856
 
@@ -3462,9 +3886,14 @@ function parseHoverArgs(rawArgs) {
3462
3886
  }
3463
3887
  async function runHover(args) {
3464
3888
  const { sessionId, ref } = parseHoverArgs(args.rawArgs);
3889
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3465
3890
  if (!sessionId) throw createUsageError("Missing --session-id");
3466
3891
  if (!ref) throw createUsageError("Missing --ref");
3467
- const result = await callDaemon("interact.hover", { sessionId, ref });
3892
+ const result = await callDaemon("interact.hover", {
3893
+ sessionId,
3894
+ ref,
3895
+ ...typeof targetId === "string" ? { targetId } : {}
3896
+ });
3468
3897
  return { success: true, message: "Hover complete.", data: result };
3469
3898
  }
3470
3899
 
@@ -3511,9 +3940,15 @@ function parsePressArgs(rawArgs) {
3511
3940
  }
3512
3941
  async function runPress(args) {
3513
3942
  const { sessionId, key, ref } = parsePressArgs(args.rawArgs);
3943
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3514
3944
  if (!sessionId) throw createUsageError("Missing --session-id");
3515
3945
  if (!key) throw createUsageError("Missing --key");
3516
- const result = await callDaemon("interact.press", { sessionId, key, ref });
3946
+ const result = await callDaemon("interact.press", {
3947
+ sessionId,
3948
+ key,
3949
+ ref,
3950
+ ...typeof targetId === "string" ? { targetId } : {}
3951
+ });
3517
3952
  return { success: true, message: "Key press complete.", data: result };
3518
3953
  }
3519
3954
 
@@ -3549,9 +3984,14 @@ function parseCheckArgs(rawArgs) {
3549
3984
  }
3550
3985
  async function runCheck(args) {
3551
3986
  const { sessionId, ref } = parseCheckArgs(args.rawArgs);
3987
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3552
3988
  if (!sessionId) throw createUsageError("Missing --session-id");
3553
3989
  if (!ref) throw createUsageError("Missing --ref");
3554
- const result = await callDaemon("interact.check", { sessionId, ref });
3990
+ const result = await callDaemon("interact.check", {
3991
+ sessionId,
3992
+ ref,
3993
+ ...typeof targetId === "string" ? { targetId } : {}
3994
+ });
3555
3995
  return { success: true, message: "Check complete.", data: result };
3556
3996
  }
3557
3997
 
@@ -3587,9 +4027,14 @@ function parseUncheckArgs(rawArgs) {
3587
4027
  }
3588
4028
  async function runUncheck(args) {
3589
4029
  const { sessionId, ref } = parseUncheckArgs(args.rawArgs);
4030
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3590
4031
  if (!sessionId) throw createUsageError("Missing --session-id");
3591
4032
  if (!ref) throw createUsageError("Missing --ref");
3592
- const result = await callDaemon("interact.uncheck", { sessionId, ref });
4033
+ const result = await callDaemon("interact.uncheck", {
4034
+ sessionId,
4035
+ ref,
4036
+ ...typeof targetId === "string" ? { targetId } : {}
4037
+ });
3593
4038
  return { success: true, message: "Uncheck complete.", data: result };
3594
4039
  }
3595
4040
 
@@ -3644,10 +4089,18 @@ function parseTypeArgs(rawArgs) {
3644
4089
  }
3645
4090
  async function runType(args) {
3646
4091
  const { sessionId, ref, text, clear, submit } = parseTypeArgs(args.rawArgs);
4092
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3647
4093
  if (!sessionId) throw createUsageError("Missing --session-id");
3648
4094
  if (!ref) throw createUsageError("Missing --ref");
3649
4095
  if (!text) throw createUsageError("Missing --text");
3650
- const result = await callDaemon("interact.type", { sessionId, ref, text, clear, submit });
4096
+ const result = await callDaemon("interact.type", {
4097
+ sessionId,
4098
+ ref,
4099
+ text,
4100
+ clear,
4101
+ submit,
4102
+ ...typeof targetId === "string" ? { targetId } : {}
4103
+ });
3651
4104
  return { success: true, message: "Type complete.", data: result };
3652
4105
  }
3653
4106
 
@@ -3696,10 +4149,16 @@ function parseSelectArgs(rawArgs) {
3696
4149
  }
3697
4150
  async function runSelect(args) {
3698
4151
  const { sessionId, ref, values } = parseSelectArgs(args.rawArgs);
4152
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3699
4153
  if (!sessionId) throw createUsageError("Missing --session-id");
3700
4154
  if (!ref) throw createUsageError("Missing --ref");
3701
4155
  if (!values || values.length === 0) throw createUsageError("Missing --values");
3702
- const result = await callDaemon("interact.select", { sessionId, ref, values });
4156
+ const result = await callDaemon("interact.select", {
4157
+ sessionId,
4158
+ ref,
4159
+ values,
4160
+ ...typeof targetId === "string" ? { targetId } : {}
4161
+ });
3703
4162
  return { success: true, message: "Select complete.", data: result };
3704
4163
  }
3705
4164
 
@@ -3746,9 +4205,15 @@ function parseScrollArgs(rawArgs) {
3746
4205
  }
3747
4206
  async function runScroll(args) {
3748
4207
  const { sessionId, ref, dy } = parseScrollArgs(args.rawArgs);
4208
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3749
4209
  if (!sessionId) throw createUsageError("Missing --session-id");
3750
4210
  if (typeof dy !== "number" || Number.isNaN(dy)) throw createUsageError("Missing --dy");
3751
- const result = await callDaemon("interact.scroll", { sessionId, ref, dy });
4211
+ const result = await callDaemon("interact.scroll", {
4212
+ sessionId,
4213
+ ref,
4214
+ dy,
4215
+ ...typeof targetId === "string" ? { targetId } : {}
4216
+ });
3752
4217
  return { success: true, message: "Scroll complete.", data: result };
3753
4218
  }
3754
4219
 
@@ -3784,9 +4249,14 @@ function parseScrollIntoViewArgs(rawArgs) {
3784
4249
  }
3785
4250
  async function runScrollIntoView(args) {
3786
4251
  const { sessionId, ref } = parseScrollIntoViewArgs(args.rawArgs);
4252
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
3787
4253
  if (!sessionId) throw createUsageError("Missing --session-id");
3788
4254
  if (!ref) throw createUsageError("Missing --ref");
3789
- const result = await callDaemon("interact.scrollIntoView", { sessionId, ref });
4255
+ const result = await callDaemon("interact.scrollIntoView", {
4256
+ sessionId,
4257
+ ref,
4258
+ ...typeof targetId === "string" ? { targetId } : {}
4259
+ });
3790
4260
  return { success: true, message: "Scroll into view complete.", data: result };
3791
4261
  }
3792
4262
 
@@ -4088,9 +4558,15 @@ function parseDomHtmlArgs(rawArgs) {
4088
4558
  }
4089
4559
  async function runDomHtml(args) {
4090
4560
  const { sessionId, ref, maxChars } = parseDomHtmlArgs(args.rawArgs);
4561
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4091
4562
  if (!sessionId) throw createUsageError("Missing --session-id");
4092
4563
  if (!ref) throw createUsageError("Missing --ref");
4093
- const result = await callDaemon("dom.getHtml", { sessionId, ref, maxChars });
4564
+ const result = await callDaemon("dom.getHtml", {
4565
+ sessionId,
4566
+ ref,
4567
+ maxChars,
4568
+ ...typeof targetId === "string" ? { targetId } : {}
4569
+ });
4094
4570
  return { success: true, message: "DOM HTML captured.", data: result };
4095
4571
  }
4096
4572
 
@@ -4137,9 +4613,15 @@ function parseDomTextArgs(rawArgs) {
4137
4613
  }
4138
4614
  async function runDomText(args) {
4139
4615
  const { sessionId, ref, maxChars } = parseDomTextArgs(args.rawArgs);
4616
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4140
4617
  if (!sessionId) throw createUsageError("Missing --session-id");
4141
4618
  if (!ref) throw createUsageError("Missing --ref");
4142
- const result = await callDaemon("dom.getText", { sessionId, ref, maxChars });
4619
+ const result = await callDaemon("dom.getText", {
4620
+ sessionId,
4621
+ ref,
4622
+ maxChars,
4623
+ ...typeof targetId === "string" ? { targetId } : {}
4624
+ });
4143
4625
  return { success: true, message: "DOM text captured.", data: result };
4144
4626
  }
4145
4627
 
@@ -4186,10 +4668,16 @@ function parseDomAttrArgs(rawArgs) {
4186
4668
  }
4187
4669
  async function runDomAttr(args) {
4188
4670
  const { sessionId, ref, attr } = parseDomAttrArgs(args.rawArgs);
4671
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4189
4672
  if (!sessionId) throw createUsageError("Missing --session-id");
4190
4673
  if (!ref) throw createUsageError("Missing --ref");
4191
4674
  if (!attr) throw createUsageError("Missing --attr");
4192
- const result = await callDaemon("dom.getAttr", { sessionId, ref, name: attr });
4675
+ const result = await callDaemon("dom.getAttr", {
4676
+ sessionId,
4677
+ ref,
4678
+ name: attr,
4679
+ ...typeof targetId === "string" ? { targetId } : {}
4680
+ });
4193
4681
  return { success: true, message: "DOM attribute captured.", data: result };
4194
4682
  }
4195
4683
 
@@ -4225,9 +4713,14 @@ function parseDomValueArgs(rawArgs) {
4225
4713
  }
4226
4714
  async function runDomValue(args) {
4227
4715
  const { sessionId, ref } = parseDomValueArgs(args.rawArgs);
4716
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4228
4717
  if (!sessionId) throw createUsageError("Missing --session-id");
4229
4718
  if (!ref) throw createUsageError("Missing --ref");
4230
- const result = await callDaemon("dom.getValue", { sessionId, ref });
4719
+ const result = await callDaemon("dom.getValue", {
4720
+ sessionId,
4721
+ ref,
4722
+ ...typeof targetId === "string" ? { targetId } : {}
4723
+ });
4231
4724
  return { success: true, message: "DOM value captured.", data: result };
4232
4725
  }
4233
4726
 
@@ -4263,9 +4756,14 @@ function parseDomVisibleArgs(rawArgs) {
4263
4756
  }
4264
4757
  async function runDomVisible(args) {
4265
4758
  const { sessionId, ref } = parseDomVisibleArgs(args.rawArgs);
4759
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4266
4760
  if (!sessionId) throw createUsageError("Missing --session-id");
4267
4761
  if (!ref) throw createUsageError("Missing --ref");
4268
- const result = await callDaemon("dom.isVisible", { sessionId, ref });
4762
+ const result = await callDaemon("dom.isVisible", {
4763
+ sessionId,
4764
+ ref,
4765
+ ...typeof targetId === "string" ? { targetId } : {}
4766
+ });
4269
4767
  return { success: true, message: "Visibility checked.", data: result };
4270
4768
  }
4271
4769
 
@@ -4301,9 +4799,14 @@ function parseDomEnabledArgs(rawArgs) {
4301
4799
  }
4302
4800
  async function runDomEnabled(args) {
4303
4801
  const { sessionId, ref } = parseDomEnabledArgs(args.rawArgs);
4802
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4304
4803
  if (!sessionId) throw createUsageError("Missing --session-id");
4305
4804
  if (!ref) throw createUsageError("Missing --ref");
4306
- const result = await callDaemon("dom.isEnabled", { sessionId, ref });
4805
+ const result = await callDaemon("dom.isEnabled", {
4806
+ sessionId,
4807
+ ref,
4808
+ ...typeof targetId === "string" ? { targetId } : {}
4809
+ });
4307
4810
  return { success: true, message: "Enabled state checked.", data: result };
4308
4811
  }
4309
4812
 
@@ -4339,9 +4842,14 @@ function parseDomCheckedArgs(rawArgs) {
4339
4842
  }
4340
4843
  async function runDomChecked(args) {
4341
4844
  const { sessionId, ref } = parseDomCheckedArgs(args.rawArgs);
4845
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4342
4846
  if (!sessionId) throw createUsageError("Missing --session-id");
4343
4847
  if (!ref) throw createUsageError("Missing --ref");
4344
- const result = await callDaemon("dom.isChecked", { sessionId, ref });
4848
+ const result = await callDaemon("dom.isChecked", {
4849
+ sessionId,
4850
+ ref,
4851
+ ...typeof targetId === "string" ? { targetId } : {}
4852
+ });
4345
4853
  return { success: true, message: "Checked state reported.", data: result };
4346
4854
  }
4347
4855
 
@@ -4361,13 +4869,27 @@ function parseClonePageArgs(rawArgs) {
4361
4869
  parsed.sessionId = arg.split("=", 2)[1];
4362
4870
  continue;
4363
4871
  }
4872
+ if (arg === "--target-id") {
4873
+ const value = rawArgs[i + 1];
4874
+ if (!value) throw createUsageError("Missing value for --target-id");
4875
+ parsed.targetId = value;
4876
+ i += 1;
4877
+ continue;
4878
+ }
4879
+ if (arg?.startsWith("--target-id=")) {
4880
+ parsed.targetId = arg.split("=", 2)[1];
4881
+ continue;
4882
+ }
4364
4883
  }
4365
4884
  return parsed;
4366
4885
  }
4367
4886
  async function runClonePage(args) {
4368
- const { sessionId } = parseClonePageArgs(args.rawArgs);
4887
+ const { sessionId, targetId } = parseClonePageArgs(args.rawArgs);
4369
4888
  if (!sessionId) throw createUsageError("Missing --session-id");
4370
- const result = await callDaemon("export.clonePage", { sessionId });
4889
+ const result = await callDaemon("export.clonePage", {
4890
+ sessionId,
4891
+ ...typeof targetId === "string" ? { targetId } : {}
4892
+ });
4371
4893
  return { success: true, message: "Page cloned.", data: result };
4372
4894
  }
4373
4895
 
@@ -4398,14 +4920,29 @@ function parseCloneComponentArgs(rawArgs) {
4398
4920
  parsed.ref = arg.split("=", 2)[1];
4399
4921
  continue;
4400
4922
  }
4923
+ if (arg === "--target-id") {
4924
+ const value = rawArgs[i + 1];
4925
+ if (!value) throw createUsageError("Missing value for --target-id");
4926
+ parsed.targetId = value;
4927
+ i += 1;
4928
+ continue;
4929
+ }
4930
+ if (arg?.startsWith("--target-id=")) {
4931
+ parsed.targetId = arg.split("=", 2)[1];
4932
+ continue;
4933
+ }
4401
4934
  }
4402
4935
  return parsed;
4403
4936
  }
4404
4937
  async function runCloneComponent(args) {
4405
- const { sessionId, ref } = parseCloneComponentArgs(args.rawArgs);
4938
+ const { sessionId, ref, targetId } = parseCloneComponentArgs(args.rawArgs);
4406
4939
  if (!sessionId) throw createUsageError("Missing --session-id");
4407
4940
  if (!ref) throw createUsageError("Missing --ref");
4408
- const result = await callDaemon("export.cloneComponent", { sessionId, ref });
4941
+ const result = await callDaemon("export.cloneComponent", {
4942
+ sessionId,
4943
+ ref,
4944
+ ...typeof targetId === "string" ? { targetId } : {}
4945
+ });
4409
4946
  return { success: true, message: "Component cloned.", data: result };
4410
4947
  }
4411
4948
 
@@ -4430,13 +4967,17 @@ function parsePerfArgs(rawArgs) {
4430
4967
  }
4431
4968
  async function runPerf(args) {
4432
4969
  const { sessionId } = parsePerfArgs(args.rawArgs);
4970
+ const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
4433
4971
  if (!sessionId) throw createUsageError("Missing --session-id");
4434
- const result = await callDaemon("devtools.perf", { sessionId });
4972
+ const result = await callDaemon("devtools.perf", {
4973
+ sessionId,
4974
+ ...typeof targetId === "string" ? { targetId } : {}
4975
+ });
4435
4976
  return { success: true, message: "Performance metrics captured.", data: result };
4436
4977
  }
4437
4978
 
4438
4979
  // src/cli/commands/devtools/screenshot.ts
4439
- var requireValue4 = (value, flag) => {
4980
+ var requireValue5 = (value, flag) => {
4440
4981
  if (!value) throw createUsageError(`Missing value for ${flag}`);
4441
4982
  return value;
4442
4983
  };
@@ -4445,39 +4986,52 @@ function parseScreenshotArgs(rawArgs) {
4445
4986
  for (let i = 0; i < rawArgs.length; i += 1) {
4446
4987
  const arg = rawArgs[i];
4447
4988
  if (arg === "--session-id") {
4448
- parsed.sessionId = requireValue4(rawArgs[i + 1], "--session-id");
4989
+ parsed.sessionId = requireValue5(rawArgs[i + 1], "--session-id");
4449
4990
  i += 1;
4450
4991
  continue;
4451
4992
  }
4452
4993
  if (arg?.startsWith("--session-id=")) {
4453
- parsed.sessionId = requireValue4(arg.split("=", 2)[1], "--session-id");
4994
+ parsed.sessionId = requireValue5(arg.split("=", 2)[1], "--session-id");
4995
+ continue;
4996
+ }
4997
+ if (arg === "--target-id") {
4998
+ parsed.targetId = requireValue5(rawArgs[i + 1], "--target-id");
4999
+ i += 1;
5000
+ continue;
5001
+ }
5002
+ if (arg?.startsWith("--target-id=")) {
5003
+ parsed.targetId = requireValue5(arg.split("=", 2)[1], "--target-id");
4454
5004
  continue;
4455
5005
  }
4456
5006
  if (arg === "--path") {
4457
- parsed.path = requireValue4(rawArgs[i + 1], "--path");
5007
+ parsed.path = requireValue5(rawArgs[i + 1], "--path");
4458
5008
  i += 1;
4459
5009
  continue;
4460
5010
  }
4461
5011
  if (arg?.startsWith("--path=")) {
4462
- parsed.path = requireValue4(arg.split("=", 2)[1], "--path");
5012
+ parsed.path = requireValue5(arg.split("=", 2)[1], "--path");
4463
5013
  continue;
4464
5014
  }
4465
5015
  if (arg === "--timeout-ms") {
4466
- parsed.timeoutMs = parseNumberFlag(requireValue4(rawArgs[i + 1], "--timeout-ms"), "--timeout-ms", { min: 1 });
5016
+ parsed.timeoutMs = parseNumberFlag(requireValue5(rawArgs[i + 1], "--timeout-ms"), "--timeout-ms", { min: 1 });
4467
5017
  i += 1;
4468
5018
  continue;
4469
5019
  }
4470
5020
  if (arg?.startsWith("--timeout-ms=")) {
4471
- parsed.timeoutMs = parseNumberFlag(requireValue4(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
5021
+ parsed.timeoutMs = parseNumberFlag(requireValue5(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
4472
5022
  continue;
4473
5023
  }
4474
5024
  }
4475
5025
  return parsed;
4476
5026
  }
4477
5027
  async function runScreenshot(args) {
4478
- const { sessionId, path: path8, timeoutMs } = parseScreenshotArgs(args.rawArgs);
5028
+ const { sessionId, targetId, path: path8, timeoutMs } = parseScreenshotArgs(args.rawArgs);
4479
5029
  if (!sessionId) throw createUsageError("Missing --session-id");
4480
- const params = { sessionId, path: path8 };
5030
+ const params = {
5031
+ sessionId,
5032
+ path: path8,
5033
+ ...typeof targetId === "string" ? { targetId } : {}
5034
+ };
4481
5035
  const result = typeof timeoutMs === "number" ? await callDaemon("page.screenshot", params, { timeoutMs }) : await callDaemon("page.screenshot", params);
4482
5036
  return { success: true, message: "Screenshot captured.", data: result };
4483
5037
  }
@@ -4683,8 +5237,8 @@ async function runDebugTraceSnapshot(args) {
4683
5237
  }
4684
5238
 
4685
5239
  // src/cli/commands/session/cookie-import.ts
4686
- import { readFileSync as readFileSync6 } from "fs";
4687
- var requireValue5 = (value, flag) => {
5240
+ import { readFileSync as readFileSync7 } from "fs";
5241
+ var requireValue6 = (value, flag) => {
4688
5242
  if (!value) {
4689
5243
  throw createUsageError(`Missing value for ${flag}`);
4690
5244
  }
@@ -4701,30 +5255,30 @@ var parseCookieImportArgs = (rawArgs) => {
4701
5255
  for (let index = 0; index < rawArgs.length; index += 1) {
4702
5256
  const arg = rawArgs[index];
4703
5257
  if (arg === "--session-id") {
4704
- parsed.sessionId = requireValue5(rawArgs[index + 1], "--session-id");
5258
+ parsed.sessionId = requireValue6(rawArgs[index + 1], "--session-id");
4705
5259
  index += 1;
4706
5260
  continue;
4707
5261
  }
4708
5262
  if (arg?.startsWith("--session-id=")) {
4709
- parsed.sessionId = requireValue5(arg.split("=", 2)[1], "--session-id");
5263
+ parsed.sessionId = requireValue6(arg.split("=", 2)[1], "--session-id");
4710
5264
  continue;
4711
5265
  }
4712
5266
  if (arg === "--cookies") {
4713
- parsed.cookies = requireValue5(rawArgs[index + 1], "--cookies");
5267
+ parsed.cookies = requireValue6(rawArgs[index + 1], "--cookies");
4714
5268
  index += 1;
4715
5269
  continue;
4716
5270
  }
4717
5271
  if (arg?.startsWith("--cookies=")) {
4718
- parsed.cookies = requireValue5(arg.split("=", 2)[1], "--cookies");
5272
+ parsed.cookies = requireValue6(arg.split("=", 2)[1], "--cookies");
4719
5273
  continue;
4720
5274
  }
4721
5275
  if (arg === "--cookies-file") {
4722
- parsed.cookiesFile = requireValue5(rawArgs[index + 1], "--cookies-file");
5276
+ parsed.cookiesFile = requireValue6(rawArgs[index + 1], "--cookies-file");
4723
5277
  index += 1;
4724
5278
  continue;
4725
5279
  }
4726
5280
  if (arg?.startsWith("--cookies-file=")) {
4727
- parsed.cookiesFile = requireValue5(arg.split("=", 2)[1], "--cookies-file");
5281
+ parsed.cookiesFile = requireValue6(arg.split("=", 2)[1], "--cookies-file");
4728
5282
  continue;
4729
5283
  }
4730
5284
  if (arg === "--strict") {
@@ -4732,16 +5286,16 @@ var parseCookieImportArgs = (rawArgs) => {
4732
5286
  continue;
4733
5287
  }
4734
5288
  if (arg?.startsWith("--strict=")) {
4735
- parsed.strict = parseStrictValue(requireValue5(arg.split("=", 2)[1], "--strict"), "--strict");
5289
+ parsed.strict = parseStrictValue(requireValue6(arg.split("=", 2)[1], "--strict"), "--strict");
4736
5290
  continue;
4737
5291
  }
4738
5292
  if (arg === "--request-id") {
4739
- parsed.requestId = requireValue5(rawArgs[index + 1], "--request-id");
5293
+ parsed.requestId = requireValue6(rawArgs[index + 1], "--request-id");
4740
5294
  index += 1;
4741
5295
  continue;
4742
5296
  }
4743
5297
  if (arg?.startsWith("--request-id=")) {
4744
- parsed.requestId = requireValue5(arg.split("=", 2)[1], "--request-id");
5298
+ parsed.requestId = requireValue6(arg.split("=", 2)[1], "--request-id");
4745
5299
  continue;
4746
5300
  }
4747
5301
  }
@@ -4798,7 +5352,7 @@ var resolveCookies = (parsed) => {
4798
5352
  }
4799
5353
  let raw = "";
4800
5354
  try {
4801
- raw = readFileSync6(parsed.cookiesFile ?? "", "utf8");
5355
+ raw = readFileSync7(parsed.cookiesFile ?? "", "utf8");
4802
5356
  } catch (error) {
4803
5357
  const message = error instanceof Error ? error.message : "Unable to read file";
4804
5358
  throw createUsageError(`Invalid --cookies-file: ${message}`);
@@ -4829,7 +5383,7 @@ async function runCookieImport(args) {
4829
5383
  }
4830
5384
 
4831
5385
  // src/cli/commands/session/cookie-list.ts
4832
- var requireValue6 = (value, flag) => {
5386
+ var requireValue7 = (value, flag) => {
4833
5387
  if (!value) {
4834
5388
  throw createUsageError(`Missing value for ${flag}`);
4835
5389
  }
@@ -4866,31 +5420,31 @@ var parseCookieListArgs = (rawArgs) => {
4866
5420
  for (let index = 0; index < rawArgs.length; index += 1) {
4867
5421
  const arg = rawArgs[index];
4868
5422
  if (arg === "--session-id") {
4869
- parsed.sessionId = requireValue6(rawArgs[index + 1], "--session-id");
5423
+ parsed.sessionId = requireValue7(rawArgs[index + 1], "--session-id");
4870
5424
  index += 1;
4871
5425
  continue;
4872
5426
  }
4873
5427
  if (arg?.startsWith("--session-id=")) {
4874
- parsed.sessionId = requireValue6(arg.split("=", 2)[1], "--session-id");
5428
+ parsed.sessionId = requireValue7(arg.split("=", 2)[1], "--session-id");
4875
5429
  continue;
4876
5430
  }
4877
5431
  if (arg === "--url") {
4878
- const rawValue = requireValue6(rawArgs[index + 1], "--url");
5432
+ const rawValue = requireValue7(rawArgs[index + 1], "--url");
4879
5433
  parsed.urls.push(...rawValue.split(","));
4880
5434
  index += 1;
4881
5435
  continue;
4882
5436
  }
4883
5437
  if (arg?.startsWith("--url=")) {
4884
- parsed.urls.push(...requireValue6(arg.split("=", 2)[1], "--url").split(","));
5438
+ parsed.urls.push(...requireValue7(arg.split("=", 2)[1], "--url").split(","));
4885
5439
  continue;
4886
5440
  }
4887
5441
  if (arg === "--request-id") {
4888
- parsed.requestId = requireValue6(rawArgs[index + 1], "--request-id");
5442
+ parsed.requestId = requireValue7(rawArgs[index + 1], "--request-id");
4889
5443
  index += 1;
4890
5444
  continue;
4891
5445
  }
4892
5446
  if (arg?.startsWith("--request-id=")) {
4893
- parsed.requestId = requireValue6(arg.split("=", 2)[1], "--request-id");
5447
+ parsed.requestId = requireValue7(arg.split("=", 2)[1], "--request-id");
4894
5448
  continue;
4895
5449
  }
4896
5450
  }
@@ -4916,7 +5470,7 @@ async function runCookieList(args) {
4916
5470
  }
4917
5471
 
4918
5472
  // src/cli/commands/macro-resolve.ts
4919
- var requireValue7 = (value, flag) => {
5473
+ var requireValue8 = (value, flag) => {
4920
5474
  if (!value) {
4921
5475
  throw createUsageError(`Missing value for ${flag}`);
4922
5476
  }
@@ -4927,21 +5481,21 @@ var parseMacroResolveArgs = (rawArgs) => {
4927
5481
  for (let index = 0; index < rawArgs.length; index += 1) {
4928
5482
  const arg = rawArgs[index];
4929
5483
  if (arg === "--expression") {
4930
- parsed.expression = requireValue7(rawArgs[index + 1], "--expression");
5484
+ parsed.expression = requireValue8(rawArgs[index + 1], "--expression");
4931
5485
  index += 1;
4932
5486
  continue;
4933
5487
  }
4934
5488
  if (arg?.startsWith("--expression=")) {
4935
- parsed.expression = requireValue7(arg.split("=", 2)[1], "--expression");
5489
+ parsed.expression = requireValue8(arg.split("=", 2)[1], "--expression");
4936
5490
  continue;
4937
5491
  }
4938
5492
  if (arg === "--default-provider") {
4939
- parsed.defaultProvider = requireValue7(rawArgs[index + 1], "--default-provider");
5493
+ parsed.defaultProvider = requireValue8(rawArgs[index + 1], "--default-provider");
4940
5494
  index += 1;
4941
5495
  continue;
4942
5496
  }
4943
5497
  if (arg?.startsWith("--default-provider=")) {
4944
- parsed.defaultProvider = requireValue7(arg.split("=", 2)[1], "--default-provider");
5498
+ parsed.defaultProvider = requireValue8(arg.split("=", 2)[1], "--default-provider");
4945
5499
  continue;
4946
5500
  }
4947
5501
  if (arg === "--include-catalog") {
@@ -4953,13 +5507,13 @@ var parseMacroResolveArgs = (rawArgs) => {
4953
5507
  continue;
4954
5508
  }
4955
5509
  if (arg === "--timeout-ms") {
4956
- const value = requireValue7(rawArgs[index + 1], "--timeout-ms");
5510
+ const value = requireValue8(rawArgs[index + 1], "--timeout-ms");
4957
5511
  parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
4958
5512
  index += 1;
4959
5513
  continue;
4960
5514
  }
4961
5515
  if (arg?.startsWith("--timeout-ms=")) {
4962
- parsed.timeoutMs = parseNumberFlag(requireValue7(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
5516
+ parsed.timeoutMs = parseNumberFlag(requireValue8(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
4963
5517
  continue;
4964
5518
  }
4965
5519
  }
@@ -4989,7 +5543,7 @@ var SOURCE_VALUES = /* @__PURE__ */ new Set(["web", "community", "social", "shop
4989
5543
  var SOURCE_SELECTION_VALUES = /* @__PURE__ */ new Set(["auto", "web", "community", "social", "shopping", "all"]);
4990
5544
  var MODE_VALUES = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
4991
5545
  var COOKIE_POLICY_VALUES = /* @__PURE__ */ new Set(["off", "auto", "required"]);
4992
- var requireValue8 = (rawArgs, index, flag) => {
5546
+ var requireValue9 = (rawArgs, index, flag) => {
4993
5547
  const value = rawArgs[index + 1];
4994
5548
  if (!value) {
4995
5549
  throw createUsageError(`Missing value for ${flag}`);
@@ -5019,7 +5573,7 @@ var parseResearchRunArgs = (rawArgs) => {
5019
5573
  for (let index = 0; index < rawArgs.length; index += 1) {
5020
5574
  const arg = rawArgs[index];
5021
5575
  if (arg === "--topic") {
5022
- parsed.topic = requireValue8(rawArgs, index, "--topic");
5576
+ parsed.topic = requireValue9(rawArgs, index, "--topic");
5023
5577
  index += 1;
5024
5578
  continue;
5025
5579
  }
@@ -5028,7 +5582,7 @@ var parseResearchRunArgs = (rawArgs) => {
5028
5582
  continue;
5029
5583
  }
5030
5584
  if (arg === "--days") {
5031
- parsed.days = parseNumberFlag(requireValue8(rawArgs, index, "--days"), "--days", { min: 1, max: 365 });
5585
+ parsed.days = parseNumberFlag(requireValue9(rawArgs, index, "--days"), "--days", { min: 1, max: 365 });
5032
5586
  index += 1;
5033
5587
  continue;
5034
5588
  }
@@ -5037,7 +5591,7 @@ var parseResearchRunArgs = (rawArgs) => {
5037
5591
  continue;
5038
5592
  }
5039
5593
  if (arg === "--from") {
5040
- parsed.from = requireValue8(rawArgs, index, "--from");
5594
+ parsed.from = requireValue9(rawArgs, index, "--from");
5041
5595
  index += 1;
5042
5596
  continue;
5043
5597
  }
@@ -5046,7 +5600,7 @@ var parseResearchRunArgs = (rawArgs) => {
5046
5600
  continue;
5047
5601
  }
5048
5602
  if (arg === "--to") {
5049
- parsed.to = requireValue8(rawArgs, index, "--to");
5603
+ parsed.to = requireValue9(rawArgs, index, "--to");
5050
5604
  index += 1;
5051
5605
  continue;
5052
5606
  }
@@ -5055,7 +5609,7 @@ var parseResearchRunArgs = (rawArgs) => {
5055
5609
  continue;
5056
5610
  }
5057
5611
  if (arg === "--source-selection") {
5058
- const value = requireValue8(rawArgs, index, "--source-selection").toLowerCase();
5612
+ const value = requireValue9(rawArgs, index, "--source-selection").toLowerCase();
5059
5613
  if (!SOURCE_SELECTION_VALUES.has(value)) {
5060
5614
  throw createUsageError(`Invalid --source-selection: ${value}`);
5061
5615
  }
@@ -5072,7 +5626,7 @@ var parseResearchRunArgs = (rawArgs) => {
5072
5626
  continue;
5073
5627
  }
5074
5628
  if (arg === "--sources") {
5075
- parsed.sources = parseSources(requireValue8(rawArgs, index, "--sources"));
5629
+ parsed.sources = parseSources(requireValue9(rawArgs, index, "--sources"));
5076
5630
  index += 1;
5077
5631
  continue;
5078
5632
  }
@@ -5081,7 +5635,7 @@ var parseResearchRunArgs = (rawArgs) => {
5081
5635
  continue;
5082
5636
  }
5083
5637
  if (arg === "--mode") {
5084
- const value = requireValue8(rawArgs, index, "--mode").toLowerCase();
5638
+ const value = requireValue9(rawArgs, index, "--mode").toLowerCase();
5085
5639
  if (!MODE_VALUES.has(value)) {
5086
5640
  throw createUsageError(`Invalid --mode: ${value}`);
5087
5641
  }
@@ -5102,7 +5656,7 @@ var parseResearchRunArgs = (rawArgs) => {
5102
5656
  continue;
5103
5657
  }
5104
5658
  if (arg === "--limit-per-source") {
5105
- parsed.limitPerSource = parseNumberFlag(requireValue8(rawArgs, index, "--limit-per-source"), "--limit-per-source", { min: 1, max: 100 });
5659
+ parsed.limitPerSource = parseNumberFlag(requireValue9(rawArgs, index, "--limit-per-source"), "--limit-per-source", { min: 1, max: 100 });
5106
5660
  index += 1;
5107
5661
  continue;
5108
5662
  }
@@ -5111,7 +5665,7 @@ var parseResearchRunArgs = (rawArgs) => {
5111
5665
  continue;
5112
5666
  }
5113
5667
  if (arg === "--output-dir") {
5114
- parsed.outputDir = requireValue8(rawArgs, index, "--output-dir");
5668
+ parsed.outputDir = requireValue9(rawArgs, index, "--output-dir");
5115
5669
  index += 1;
5116
5670
  continue;
5117
5671
  }
@@ -5120,7 +5674,7 @@ var parseResearchRunArgs = (rawArgs) => {
5120
5674
  continue;
5121
5675
  }
5122
5676
  if (arg === "--ttl-hours") {
5123
- parsed.ttlHours = parseNumberFlag(requireValue8(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5677
+ parsed.ttlHours = parseNumberFlag(requireValue9(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5124
5678
  index += 1;
5125
5679
  continue;
5126
5680
  }
@@ -5137,7 +5691,7 @@ var parseResearchRunArgs = (rawArgs) => {
5137
5691
  continue;
5138
5692
  }
5139
5693
  if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
5140
- const value = requireValue8(rawArgs, index, arg).toLowerCase();
5694
+ const value = requireValue9(rawArgs, index, arg).toLowerCase();
5141
5695
  if (!COOKIE_POLICY_VALUES.has(value)) {
5142
5696
  throw createUsageError(`Invalid ${arg}: ${value}`);
5143
5697
  }
@@ -5191,7 +5745,7 @@ async function runResearchCommand(args) {
5191
5745
  var SORT_VALUES = /* @__PURE__ */ new Set(["best_deal", "lowest_price", "highest_rating", "fastest_shipping"]);
5192
5746
  var MODE_VALUES2 = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
5193
5747
  var COOKIE_POLICY_VALUES2 = /* @__PURE__ */ new Set(["off", "auto", "required"]);
5194
- var requireValue9 = (rawArgs, index, flag) => {
5748
+ var requireValue10 = (rawArgs, index, flag) => {
5195
5749
  const value = rawArgs[index + 1];
5196
5750
  if (!value) {
5197
5751
  throw createUsageError(`Missing value for ${flag}`);
@@ -5215,7 +5769,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5215
5769
  for (let index = 0; index < rawArgs.length; index += 1) {
5216
5770
  const arg = rawArgs[index];
5217
5771
  if (arg === "--query") {
5218
- parsed.query = requireValue9(rawArgs, index, "--query");
5772
+ parsed.query = requireValue10(rawArgs, index, "--query");
5219
5773
  index += 1;
5220
5774
  continue;
5221
5775
  }
@@ -5224,7 +5778,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5224
5778
  continue;
5225
5779
  }
5226
5780
  if (arg === "--providers") {
5227
- parsed.providers = parseProviders(requireValue9(rawArgs, index, "--providers"));
5781
+ parsed.providers = parseProviders(requireValue10(rawArgs, index, "--providers"));
5228
5782
  index += 1;
5229
5783
  continue;
5230
5784
  }
@@ -5233,7 +5787,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5233
5787
  continue;
5234
5788
  }
5235
5789
  if (arg === "--budget") {
5236
- parsed.budget = parseNumberFlag(requireValue9(rawArgs, index, "--budget"), "--budget", { min: 1, integer: false });
5790
+ parsed.budget = parseNumberFlag(requireValue10(rawArgs, index, "--budget"), "--budget", { min: 1, integer: false });
5237
5791
  index += 1;
5238
5792
  continue;
5239
5793
  }
@@ -5242,7 +5796,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5242
5796
  continue;
5243
5797
  }
5244
5798
  if (arg === "--region") {
5245
- parsed.region = requireValue9(rawArgs, index, "--region");
5799
+ parsed.region = requireValue10(rawArgs, index, "--region");
5246
5800
  index += 1;
5247
5801
  continue;
5248
5802
  }
@@ -5251,7 +5805,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5251
5805
  continue;
5252
5806
  }
5253
5807
  if (arg === "--sort") {
5254
- const value = requireValue9(rawArgs, index, "--sort").toLowerCase();
5808
+ const value = requireValue10(rawArgs, index, "--sort").toLowerCase();
5255
5809
  if (!SORT_VALUES.has(value)) {
5256
5810
  throw createUsageError(`Invalid --sort: ${value}`);
5257
5811
  }
@@ -5268,7 +5822,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5268
5822
  continue;
5269
5823
  }
5270
5824
  if (arg === "--mode") {
5271
- const value = requireValue9(rawArgs, index, "--mode").toLowerCase();
5825
+ const value = requireValue10(rawArgs, index, "--mode").toLowerCase();
5272
5826
  if (!MODE_VALUES2.has(value)) {
5273
5827
  throw createUsageError(`Invalid --mode: ${value}`);
5274
5828
  }
@@ -5285,7 +5839,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5285
5839
  continue;
5286
5840
  }
5287
5841
  if (arg === "--timeout-ms") {
5288
- parsed.timeoutMs = parseNumberFlag(requireValue9(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
5842
+ parsed.timeoutMs = parseNumberFlag(requireValue10(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
5289
5843
  index += 1;
5290
5844
  continue;
5291
5845
  }
@@ -5294,7 +5848,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5294
5848
  continue;
5295
5849
  }
5296
5850
  if (arg === "--output-dir") {
5297
- parsed.outputDir = requireValue9(rawArgs, index, "--output-dir");
5851
+ parsed.outputDir = requireValue10(rawArgs, index, "--output-dir");
5298
5852
  index += 1;
5299
5853
  continue;
5300
5854
  }
@@ -5303,7 +5857,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5303
5857
  continue;
5304
5858
  }
5305
5859
  if (arg === "--ttl-hours") {
5306
- parsed.ttlHours = parseNumberFlag(requireValue9(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5860
+ parsed.ttlHours = parseNumberFlag(requireValue10(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5307
5861
  index += 1;
5308
5862
  continue;
5309
5863
  }
@@ -5320,7 +5874,7 @@ var parseShoppingRunArgs = (rawArgs) => {
5320
5874
  continue;
5321
5875
  }
5322
5876
  if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
5323
- const value = requireValue9(rawArgs, index, arg).toLowerCase();
5877
+ const value = requireValue10(rawArgs, index, arg).toLowerCase();
5324
5878
  if (!COOKIE_POLICY_VALUES2.has(value)) {
5325
5879
  throw createUsageError(`Invalid ${arg}: ${value}`);
5326
5880
  }
@@ -5370,7 +5924,7 @@ async function runShoppingCommand(args) {
5370
5924
  }
5371
5925
 
5372
5926
  // src/cli/commands/product-video.ts
5373
- var requireValue10 = (rawArgs, index, flag) => {
5927
+ var requireValue11 = (rawArgs, index, flag) => {
5374
5928
  const value = rawArgs[index + 1];
5375
5929
  if (!value) {
5376
5930
  throw createUsageError(`Missing value for ${flag}`);
@@ -5388,7 +5942,7 @@ var parseProductVideoArgs = (rawArgs) => {
5388
5942
  for (let index = 0; index < rawArgs.length; index += 1) {
5389
5943
  const arg = rawArgs[index];
5390
5944
  if (arg === "--product-url") {
5391
- parsed.productUrl = requireValue10(rawArgs, index, "--product-url");
5945
+ parsed.productUrl = requireValue11(rawArgs, index, "--product-url");
5392
5946
  index += 1;
5393
5947
  continue;
5394
5948
  }
@@ -5397,7 +5951,7 @@ var parseProductVideoArgs = (rawArgs) => {
5397
5951
  continue;
5398
5952
  }
5399
5953
  if (arg === "--product-name") {
5400
- parsed.productName = requireValue10(rawArgs, index, "--product-name");
5954
+ parsed.productName = requireValue11(rawArgs, index, "--product-name");
5401
5955
  index += 1;
5402
5956
  continue;
5403
5957
  }
@@ -5406,7 +5960,7 @@ var parseProductVideoArgs = (rawArgs) => {
5406
5960
  continue;
5407
5961
  }
5408
5962
  if (arg === "--provider-hint") {
5409
- parsed.providerHint = requireValue10(rawArgs, index, "--provider-hint");
5963
+ parsed.providerHint = requireValue11(rawArgs, index, "--provider-hint");
5410
5964
  index += 1;
5411
5965
  continue;
5412
5966
  }
@@ -5439,7 +5993,7 @@ var parseProductVideoArgs = (rawArgs) => {
5439
5993
  continue;
5440
5994
  }
5441
5995
  if (arg === "--output-dir") {
5442
- parsed.outputDir = requireValue10(rawArgs, index, "--output-dir");
5996
+ parsed.outputDir = requireValue11(rawArgs, index, "--output-dir");
5443
5997
  index += 1;
5444
5998
  continue;
5445
5999
  }
@@ -5448,7 +6002,7 @@ var parseProductVideoArgs = (rawArgs) => {
5448
6002
  continue;
5449
6003
  }
5450
6004
  if (arg === "--ttl-hours") {
5451
- parsed.ttlHours = parseNumberFlag(requireValue10(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
6005
+ parsed.ttlHours = parseNumberFlag(requireValue11(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
5452
6006
  index += 1;
5453
6007
  continue;
5454
6008
  }
@@ -5457,7 +6011,7 @@ var parseProductVideoArgs = (rawArgs) => {
5457
6011
  continue;
5458
6012
  }
5459
6013
  if (arg === "--timeout-ms") {
5460
- parsed.timeoutMs = parseNumberFlag(requireValue10(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
6014
+ parsed.timeoutMs = parseNumberFlag(requireValue11(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
5461
6015
  index += 1;
5462
6016
  continue;
5463
6017
  }
@@ -5474,7 +6028,7 @@ var parseProductVideoArgs = (rawArgs) => {
5474
6028
  continue;
5475
6029
  }
5476
6030
  if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
5477
- const value = requireValue10(rawArgs, index, arg).toLowerCase();
6031
+ const value = requireValue11(rawArgs, index, arg).toLowerCase();
5478
6032
  if (!COOKIE_POLICY_VALUES3.has(value)) {
5479
6033
  throw createUsageError(`Invalid ${arg}: ${value}`);
5480
6034
  }
@@ -5525,7 +6079,7 @@ async function runProductVideoCommand(args) {
5525
6079
  // package.json
5526
6080
  var package_default = {
5527
6081
  name: "opendevbrowser",
5528
- version: "0.0.16",
6082
+ version: "0.0.17",
5529
6083
  description: "OpenCode plugin for browser automation via CDP with snapshot-refs-actions workflow",
5530
6084
  type: "module",
5531
6085
  main: "dist/index.js",
@@ -5537,6 +6091,7 @@ var package_default = {
5537
6091
  "dist",
5538
6092
  "skills",
5539
6093
  "scripts/native",
6094
+ "extension/canvas.html",
5540
6095
  "extension/manifest.json",
5541
6096
  "extension/popup.html",
5542
6097
  "extension/dist",
@@ -5579,7 +6134,7 @@ for (const [src, dst] of pairs) {
5579
6134
  dev: "tsup src/index.ts src/cli/index.ts --format esm --dts --watch",
5580
6135
  lint: 'eslint "src/**/*.ts" "tests/**/*.ts"',
5581
6136
  typecheck: "tsc --noEmit -p tsconfig.json",
5582
- test: "vitest run --coverage",
6137
+ test: `node --input-type=module -e "import { mkdirSync } from 'node:fs'; mkdirSync('coverage/.tmp', { recursive: true });" && vitest run --coverage`,
5583
6138
  "test:release-gate": "node scripts/release-gate-test-groups.mjs",
5584
6139
  "test:release-gate:g1": "node scripts/release-gate-test-groups.mjs --group 1",
5585
6140
  "test:release-gate:g2": "node scripts/release-gate-test-groups.mjs --group 2",
@@ -5588,7 +6143,7 @@ for (const [src, dst] of pairs) {
5588
6143
  "test:release-gate:g5": "node scripts/release-gate-test-groups.mjs --group 5",
5589
6144
  "extension:sync": "node scripts/sync-extension-version.mjs",
5590
6145
  "extension:build": "npm run extension:sync && tsc -p extension/tsconfig.json && node scripts/copy-extension-assets.mjs",
5591
- "extension:pack": "cd extension && zip -r ../opendevbrowser-extension.zip manifest.json popup.html dist/ icons/",
6146
+ "extension:pack": "cd extension && zip -r ../opendevbrowser-extension.zip manifest.json popup.html canvas.html dist/ icons/",
5592
6147
  "extension:store": "node scripts/chrome-store-publish.mjs",
5593
6148
  "version:check": "node scripts/verify-versions.mjs",
5594
6149
  prepack: "npm run version:check && npm run build && npm run extension:build"
@@ -5599,7 +6154,9 @@ for (const [src, dst] of pairs) {
5599
6154
  "async-mutex": "^0.5.0",
5600
6155
  "jsonc-parser": "^3.2.0",
5601
6156
  "playwright-core": "^1.58.2",
6157
+ typescript: "^5.9.3",
5602
6158
  ws: "^8.19.0",
6159
+ yjs: "^13.6.29",
5603
6160
  zod: "^3.25.76"
5604
6161
  },
5605
6162
  devDependencies: {
@@ -5612,7 +6169,6 @@ for (const [src, dst] of pairs) {
5612
6169
  eslint: "^9.39.3",
5613
6170
  "happy-dom": "^20.7.0",
5614
6171
  tsup: "^8.5.1",
5615
- typescript: "^5.9.3",
5616
6172
  vitest: "^4.0.18"
5617
6173
  }
5618
6174
  };
@@ -5936,9 +6492,14 @@ async function main() {
5936
6492
  });
5937
6493
  registerCommand({
5938
6494
  name: "annotate",
5939
- description: "Request interactive annotations (extension relay)",
6495
+ description: "Request interactive annotations via direct or relay transport",
5940
6496
  run: async () => runAnnotate(args)
5941
6497
  });
6498
+ registerCommand({
6499
+ name: "canvas",
6500
+ description: "Execute a design-canvas command",
6501
+ run: async () => runCanvas(args)
6502
+ });
5942
6503
  registerCommand({
5943
6504
  name: "rpc",
5944
6505
  description: "Execute an internal daemon RPC command (power-user)",