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