opendevbrowser 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -73
- package/dist/annotate/agent-inbox-store.d.ts +58 -0
- package/dist/annotate/agent-inbox-store.d.ts.map +1 -0
- package/dist/annotate/agent-inbox.d.ts +25 -0
- package/dist/annotate/agent-inbox.d.ts.map +1 -0
- package/dist/annotate/direct-annotator.d.ts.map +1 -1
- package/dist/annotate/timeout-messages.d.ts +4 -0
- package/dist/annotate/timeout-messages.d.ts.map +1 -0
- package/dist/automation/coordinator.d.ts +55 -0
- package/dist/automation/coordinator.d.ts.map +1 -0
- package/dist/browser/annotation-manager.d.ts +4 -1
- package/dist/browser/annotation-manager.d.ts.map +1 -1
- package/dist/browser/browser-manager.d.ts +147 -47
- package/dist/browser/browser-manager.d.ts.map +1 -1
- package/dist/browser/canvas-client.d.ts +1 -0
- package/dist/browser/canvas-client.d.ts.map +1 -1
- package/dist/browser/canvas-code-sync-manager.d.ts +9 -1
- package/dist/browser/canvas-code-sync-manager.d.ts.map +1 -1
- package/dist/browser/canvas-manager.d.ts +29 -1
- package/dist/browser/canvas-manager.d.ts.map +1 -1
- package/dist/browser/global-challenge-coordinator.d.ts +27 -0
- package/dist/browser/global-challenge-coordinator.d.ts.map +1 -0
- package/dist/browser/manager-types.d.ts +167 -1
- package/dist/browser/manager-types.d.ts.map +1 -1
- package/dist/browser/ops-browser-manager.d.ts +103 -3
- package/dist/browser/ops-browser-manager.d.ts.map +1 -1
- package/dist/browser/ops-client.d.ts +17 -1
- package/dist/browser/ops-client.d.ts.map +1 -1
- package/dist/browser/playwright-runtime.d.ts +4 -0
- package/dist/browser/playwright-runtime.d.ts.map +1 -0
- package/dist/browser/review-surface.d.ts +9 -0
- package/dist/browser/review-surface.d.ts.map +1 -0
- package/dist/browser/screencast-recorder.d.ts +57 -0
- package/dist/browser/screencast-recorder.d.ts.map +1 -0
- package/dist/browser/session-inspector.d.ts +71 -0
- package/dist/browser/session-inspector.d.ts.map +1 -0
- package/dist/browser/session-store.d.ts +5 -1
- package/dist/browser/session-store.d.ts.map +1 -1
- package/dist/browser/system-chrome-cookies.d.ts +46 -0
- package/dist/browser/system-chrome-cookies.d.ts.map +1 -0
- package/dist/browser/target-manager.d.ts +1 -0
- package/dist/browser/target-manager.d.ts.map +1 -1
- package/dist/cache/chrome-locator.d.ts.map +1 -1
- package/dist/cache/chrome-user-data.d.ts +17 -0
- package/dist/cache/chrome-user-data.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/loader.d.ts +13 -0
- package/dist/canvas/adapter-plugins/loader.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/manifest.d.ts +146 -0
- package/dist/canvas/adapter-plugins/manifest.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/types.d.ts +83 -0
- package/dist/canvas/adapter-plugins/types.d.ts.map +1 -0
- package/dist/canvas/adapter-plugins/validator.d.ts +10 -0
- package/dist/canvas/adapter-plugins/validator.d.ts.map +1 -0
- package/dist/canvas/code-sync/apply-tsx.d.ts +3 -1
- package/dist/canvas/code-sync/apply-tsx.d.ts.map +1 -1
- package/dist/canvas/code-sync/import.d.ts +1 -0
- package/dist/canvas/code-sync/import.d.ts.map +1 -1
- package/dist/canvas/code-sync/manifest.d.ts +2 -1
- package/dist/canvas/code-sync/manifest.d.ts.map +1 -1
- package/dist/canvas/code-sync/tsx-adapter.d.ts.map +1 -1
- package/dist/canvas/code-sync/types.d.ts +102 -10
- package/dist/canvas/code-sync/types.d.ts.map +1 -1
- package/dist/canvas/document-store.d.ts +11 -1
- package/dist/canvas/document-store.d.ts.map +1 -1
- package/dist/canvas/export.d.ts.map +1 -1
- package/dist/canvas/framework-adapters/custom-elements-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/custom-elements-v1.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/html-static-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/html-static-v1.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/markup.d.ts +9 -0
- package/dist/canvas/framework-adapters/markup.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/react-tsx-v2.d.ts +3 -0
- package/dist/canvas/framework-adapters/react-tsx-v2.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/registry.d.ts +12 -0
- package/dist/canvas/framework-adapters/registry.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/svelte-sfc-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/svelte-sfc-v1.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/types.d.ts +57 -0
- package/dist/canvas/framework-adapters/types.d.ts.map +1 -0
- package/dist/canvas/framework-adapters/vue-sfc-v1.d.ts +3 -0
- package/dist/canvas/framework-adapters/vue-sfc-v1.d.ts.map +1 -0
- package/dist/canvas/kits/catalog.d.ts +5 -0
- package/dist/canvas/kits/catalog.d.ts.map +1 -0
- package/dist/canvas/library-adapters/react/index.d.ts +3 -0
- package/dist/canvas/library-adapters/react/index.d.ts.map +1 -0
- package/dist/canvas/library-adapters/registry.d.ts +11 -0
- package/dist/canvas/library-adapters/registry.d.ts.map +1 -0
- package/dist/canvas/library-adapters/types.d.ts +43 -0
- package/dist/canvas/library-adapters/types.d.ts.map +1 -0
- package/dist/canvas/repo-store.d.ts +2 -0
- package/dist/canvas/repo-store.d.ts.map +1 -1
- package/dist/canvas/starters/catalog.d.ts +34 -0
- package/dist/canvas/starters/catalog.d.ts.map +1 -0
- package/dist/canvas/token-references.d.ts +22 -0
- package/dist/canvas/token-references.d.ts.map +1 -0
- package/dist/canvas/types.d.ts +345 -6
- package/dist/canvas/types.d.ts.map +1 -1
- package/dist/challenges/action-loop.d.ts +13 -0
- package/dist/challenges/action-loop.d.ts.map +1 -0
- package/dist/challenges/capability-matrix.d.ts +3 -0
- package/dist/challenges/capability-matrix.d.ts.map +1 -0
- package/dist/challenges/evidence-bundle.d.ts +48 -0
- package/dist/challenges/evidence-bundle.d.ts.map +1 -0
- package/dist/challenges/governed-adapter-gateway.d.ts +4 -0
- package/dist/challenges/governed-adapter-gateway.d.ts.map +1 -0
- package/dist/challenges/human-yield-gate.d.ts +20 -0
- package/dist/challenges/human-yield-gate.d.ts.map +1 -0
- package/dist/challenges/index.d.ts +15 -0
- package/dist/challenges/index.d.ts.map +1 -0
- package/dist/challenges/interpreter.d.ts +3 -0
- package/dist/challenges/interpreter.d.ts.map +1 -0
- package/dist/challenges/optional-computer-use-bridge.d.ts +9 -0
- package/dist/challenges/optional-computer-use-bridge.d.ts.map +1 -0
- package/dist/challenges/orchestrator.d.ts +32 -0
- package/dist/challenges/orchestrator.d.ts.map +1 -0
- package/dist/challenges/outcome-recorder.d.ts +8 -0
- package/dist/challenges/outcome-recorder.d.ts.map +1 -0
- package/dist/challenges/owned-environment-lane.d.ts +3 -0
- package/dist/challenges/owned-environment-lane.d.ts.map +1 -0
- package/dist/challenges/policy-gate.d.ts +9 -0
- package/dist/challenges/policy-gate.d.ts.map +1 -0
- package/dist/challenges/sanctioned-identity-lane.d.ts +3 -0
- package/dist/challenges/sanctioned-identity-lane.d.ts.map +1 -0
- package/dist/challenges/service-adapter-lane.d.ts +3 -0
- package/dist/challenges/service-adapter-lane.d.ts.map +1 -0
- package/dist/challenges/strategy-selector.d.ts +10 -0
- package/dist/challenges/strategy-selector.d.ts.map +1 -0
- package/dist/challenges/types.d.ts +277 -0
- package/dist/challenges/types.d.ts.map +1 -0
- package/dist/challenges/verification-gate.d.ts +15 -0
- package/dist/challenges/verification-gate.d.ts.map +1 -0
- package/dist/chunk-5FZQJRBQ.js +15256 -0
- package/dist/chunk-5FZQJRBQ.js.map +1 -0
- package/dist/chunk-L57D35TB.js +33513 -0
- package/dist/chunk-L57D35TB.js.map +1 -0
- package/dist/chunk-YBQECXZX.js +409 -0
- package/dist/chunk-YBQECXZX.js.map +1 -0
- package/dist/cli/args.d.ts +4 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/commands/artifacts.d.ts.map +1 -1
- package/dist/cli/commands/canvas.d.ts +7 -7
- package/dist/cli/commands/canvas.d.ts.map +1 -1
- package/dist/cli/commands/daemon.d.ts +7 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/desktop/accessibility-snapshot.d.ts +3 -0
- package/dist/cli/commands/desktop/accessibility-snapshot.d.ts.map +1 -0
- package/dist/cli/commands/desktop/active-window.d.ts +3 -0
- package/dist/cli/commands/desktop/active-window.d.ts.map +1 -0
- package/dist/cli/commands/desktop/capture-desktop.d.ts +3 -0
- package/dist/cli/commands/desktop/capture-desktop.d.ts.map +1 -0
- package/dist/cli/commands/desktop/capture-window.d.ts +3 -0
- package/dist/cli/commands/desktop/capture-window.d.ts.map +1 -0
- package/dist/cli/commands/desktop/shared.d.ts +19 -0
- package/dist/cli/commands/desktop/shared.d.ts.map +1 -0
- package/dist/cli/commands/desktop/status.d.ts +3 -0
- package/dist/cli/commands/desktop/status.d.ts.map +1 -0
- package/dist/cli/commands/desktop/windows.d.ts +3 -0
- package/dist/cli/commands/desktop/windows.d.ts.map +1 -0
- package/dist/cli/commands/devtools/dialog.d.ts +19 -0
- package/dist/cli/commands/devtools/dialog.d.ts.map +1 -0
- package/dist/cli/commands/devtools/screencast-start.d.ts +20 -0
- package/dist/cli/commands/devtools/screencast-start.d.ts.map +1 -0
- package/dist/cli/commands/devtools/screencast-stop.d.ts +17 -0
- package/dist/cli/commands/devtools/screencast-stop.d.ts.map +1 -0
- package/dist/cli/commands/devtools/screenshot.d.ts +2 -0
- package/dist/cli/commands/devtools/screenshot.d.ts.map +1 -1
- package/dist/cli/commands/interact/click.d.ts.map +1 -1
- package/dist/cli/commands/interact/pointer-down.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-down.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-drag.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-drag.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-move.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-move.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-shared.d.ts +6 -0
- package/dist/cli/commands/interact/pointer-shared.d.ts.map +1 -0
- package/dist/cli/commands/interact/pointer-up.d.ts +7 -0
- package/dist/cli/commands/interact/pointer-up.d.ts.map +1 -0
- package/dist/cli/commands/interact/upload.d.ts +18 -0
- package/dist/cli/commands/interact/upload.d.ts.map +1 -0
- package/dist/cli/commands/macro-resolve.d.ts +2 -0
- package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
- package/dist/cli/commands/native.d.ts +10 -7
- package/dist/cli/commands/native.d.ts.map +1 -1
- package/dist/cli/commands/nav/review.d.ts +7 -0
- package/dist/cli/commands/nav/review.d.ts.map +1 -0
- package/dist/cli/commands/nav/snapshot.d.ts.map +1 -1
- package/dist/cli/commands/pages/open.d.ts.map +1 -1
- package/dist/cli/commands/product-video.d.ts +2 -0
- package/dist/cli/commands/product-video.d.ts.map +1 -1
- package/dist/cli/commands/research.d.ts +3 -0
- package/dist/cli/commands/research.d.ts.map +1 -1
- package/dist/cli/commands/run.d.ts +14 -0
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts +1 -26
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/session/connect.d.ts.map +1 -1
- package/dist/cli/commands/session/disconnect.d.ts.map +1 -1
- package/dist/cli/commands/session/inspector.d.ts +21 -0
- package/dist/cli/commands/session/inspector.d.ts.map +1 -0
- package/dist/cli/commands/session/launch.d.ts.map +1 -1
- package/dist/cli/commands/shopping.d.ts +5 -0
- package/dist/cli/commands/shopping.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts +2 -14
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/targets/new.d.ts.map +1 -1
- package/dist/cli/daemon-autostart.d.ts +11 -0
- package/dist/cli/daemon-autostart.d.ts.map +1 -1
- package/dist/cli/daemon-client.d.ts +3 -0
- package/dist/cli/daemon-client.d.ts.map +1 -1
- package/dist/cli/daemon-commands.d.ts.map +1 -1
- package/dist/cli/daemon-state.d.ts +16 -0
- package/dist/cli/daemon-state.d.ts.map +1 -1
- package/dist/cli/daemon-status.d.ts +7 -2
- package/dist/cli/daemon-status.d.ts.map +1 -1
- package/dist/cli/daemon.d.ts +1 -0
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/help.d.ts +15 -4
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/index.js +2467 -1033
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/install-autostart-output.d.ts +6 -0
- package/dist/cli/install-autostart-output.d.ts.map +1 -0
- package/dist/cli/install-autostart-reconciliation.d.ts +23 -0
- package/dist/cli/install-autostart-reconciliation.d.ts.map +1 -0
- package/dist/cli/installers/skills.d.ts +42 -6
- package/dist/cli/installers/skills.d.ts.map +1 -1
- package/dist/cli/output.d.ts +3 -0
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/remote-desktop-runtime.d.ts +15 -0
- package/dist/cli/remote-desktop-runtime.d.ts.map +1 -0
- package/dist/cli/remote-manager.d.ts +24 -2
- package/dist/cli/remote-manager.d.ts.map +1 -1
- package/dist/cli/transport-timeouts.d.ts +8 -0
- package/dist/cli/transport-timeouts.d.ts.map +1 -0
- package/dist/cli/utils/http.d.ts +9 -0
- package/dist/cli/utils/http.d.ts.map +1 -1
- package/dist/cli/utils/parse.d.ts +2 -0
- package/dist/cli/utils/parse.d.ts.map +1 -1
- package/dist/cli/utils/skills.d.ts +1 -2
- package/dist/cli/utils/skills.d.ts.map +1 -1
- package/dist/cli/utils/workflow-message.d.ts +2 -0
- package/dist/cli/utils/workflow-message.d.ts.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/core/bootstrap.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/logging.d.ts +3 -1
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/runtime-assemblies.d.ts +22 -0
- package/dist/core/runtime-assemblies.d.ts.map +1 -0
- package/dist/core/types.d.ts +15 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/desktop/audit.d.ts +37 -0
- package/dist/desktop/audit.d.ts.map +1 -0
- package/dist/desktop/errors.d.ts +7 -0
- package/dist/desktop/errors.d.ts.map +1 -0
- package/dist/desktop/index.d.ts +6 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/runtime.d.ts +26 -0
- package/dist/desktop/runtime.d.ts.map +1 -0
- package/dist/desktop/types.d.ts +76 -0
- package/dist/desktop/types.d.ts.map +1 -0
- package/dist/extension-extractor.d.ts +6 -0
- package/dist/extension-extractor.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1103 -467
- package/dist/index.js.map +1 -1
- package/dist/integrations/figma/assets.d.ts +13 -0
- package/dist/integrations/figma/assets.d.ts.map +1 -0
- package/dist/integrations/figma/auth.d.ts +3 -0
- package/dist/integrations/figma/auth.d.ts.map +1 -0
- package/dist/integrations/figma/client.d.ts +42 -0
- package/dist/integrations/figma/client.d.ts.map +1 -0
- package/dist/integrations/figma/mappers.d.ts +23 -0
- package/dist/integrations/figma/mappers.d.ts.map +1 -0
- package/dist/integrations/figma/normalize.d.ts +99 -0
- package/dist/integrations/figma/normalize.d.ts.map +1 -0
- package/dist/integrations/figma/url.d.ts +17 -0
- package/dist/integrations/figma/url.d.ts.map +1 -0
- package/dist/integrations/figma/variables.d.ts +21 -0
- package/dist/integrations/figma/variables.d.ts.map +1 -0
- package/dist/macros/execute-runtime.d.ts +19 -0
- package/dist/macros/execute-runtime.d.ts.map +1 -0
- package/dist/macros/execute.d.ts +3 -1
- package/dist/macros/execute.d.ts.map +1 -1
- package/dist/opendevbrowser.d.ts.map +1 -1
- package/dist/opendevbrowser.js +1103 -467
- package/dist/opendevbrowser.js.map +1 -1
- package/dist/providers/blocker.d.ts.map +1 -1
- package/dist/providers/browser-fallback.d.ts +30 -0
- package/dist/providers/browser-fallback.d.ts.map +1 -0
- package/dist/providers/constraint.d.ts +45 -0
- package/dist/providers/constraint.d.ts.map +1 -0
- package/dist/providers/index.d.ts +11 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/policy.d.ts.map +1 -1
- package/dist/providers/product-video-compiler.d.ts +92 -0
- package/dist/providers/product-video-compiler.d.ts.map +1 -0
- package/dist/providers/registry.d.ts +37 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/renderer.d.ts.map +1 -1
- package/dist/providers/research-compiler.d.ts +64 -0
- package/dist/providers/research-compiler.d.ts.map +1 -0
- package/dist/providers/research-executor.d.ts +27 -0
- package/dist/providers/research-executor.d.ts.map +1 -0
- package/dist/providers/runtime-bundle.d.ts +26 -0
- package/dist/providers/runtime-bundle.d.ts.map +1 -0
- package/dist/providers/runtime-factory.d.ts +6 -1
- package/dist/providers/runtime-factory.d.ts.map +1 -1
- package/dist/providers/runtime-policy.d.ts +24 -0
- package/dist/providers/runtime-policy.d.ts.map +1 -0
- package/dist/providers/shared/anti-bot-policy.d.ts +3 -2
- package/dist/providers/shared/anti-bot-policy.d.ts.map +1 -1
- package/dist/providers/shopping/index.d.ts +11 -1
- package/dist/providers/shopping/index.d.ts.map +1 -1
- package/dist/providers/shopping-compiler.d.ts +51 -0
- package/dist/providers/shopping-compiler.d.ts.map +1 -0
- package/dist/providers/shopping-executor.d.ts +18 -0
- package/dist/providers/shopping-executor.d.ts.map +1 -0
- package/dist/providers/shopping-postprocess.d.ts +46 -0
- package/dist/providers/shopping-postprocess.d.ts.map +1 -0
- package/dist/providers/shopping-workflow.d.ts +33 -0
- package/dist/providers/shopping-workflow.d.ts.map +1 -0
- package/dist/providers/social/platform.d.ts +2 -1
- package/dist/providers/social/platform.d.ts.map +1 -1
- package/dist/providers/social/search-quality.d.ts +16 -0
- package/dist/providers/social/search-quality.d.ts.map +1 -0
- package/dist/providers/social/youtube-resolver.d.ts +2 -1
- package/dist/providers/social/youtube-resolver.d.ts.map +1 -1
- package/dist/providers/social/youtube.d.ts.map +1 -1
- package/dist/providers/types.d.ts +116 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/web/crawl-worker.d.ts.map +1 -1
- package/dist/providers/web/extract.d.ts +16 -0
- package/dist/providers/web/extract.d.ts.map +1 -1
- package/dist/providers/web/index.d.ts.map +1 -1
- package/dist/providers/workflow-contracts.d.ts +53 -0
- package/dist/providers/workflow-contracts.d.ts.map +1 -0
- package/dist/providers/workflows.d.ts +30 -6
- package/dist/providers/workflows.d.ts.map +1 -1
- package/dist/{providers-G3LRHQXX.js → providers-G36AM3Z2.js} +2 -2
- package/dist/public-surface/generated-manifest.d.ts +1168 -0
- package/dist/public-surface/generated-manifest.d.ts.map +1 -0
- package/dist/public-surface/source.d.ts +437 -0
- package/dist/public-surface/source.d.ts.map +1 -0
- package/dist/relay/protocol.d.ts +25 -3
- package/dist/relay/protocol.d.ts.map +1 -1
- package/dist/relay/relay-endpoints.d.ts +21 -0
- package/dist/relay/relay-endpoints.d.ts.map +1 -1
- package/dist/relay/relay-server.d.ts +18 -0
- package/dist/relay/relay-server.d.ts.map +1 -1
- package/dist/skills/bundled-skill-directories.d.ts +8 -0
- package/dist/skills/bundled-skill-directories.d.ts.map +1 -0
- package/dist/skills/skill-loader.d.ts +9 -1
- package/dist/skills/skill-loader.d.ts.map +1 -1
- package/dist/skills/skill-loader.js +7 -0
- package/dist/skills/skill-nudge.d.ts.map +1 -1
- package/dist/skills/types.d.ts +31 -0
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/snapshot/ops-snapshot.d.ts +1 -1
- package/dist/snapshot/ops-snapshot.d.ts.map +1 -1
- package/dist/snapshot/refs.d.ts +6 -1
- package/dist/snapshot/refs.d.ts.map +1 -1
- package/dist/snapshot/snapshotter.d.ts.map +1 -1
- package/dist/tools/connect.d.ts.map +1 -1
- package/dist/tools/deps.d.ts +4 -0
- package/dist/tools/deps.d.ts.map +1 -1
- package/dist/tools/desktop-shared.d.ts +6 -0
- package/dist/tools/desktop-shared.d.ts.map +1 -0
- package/dist/tools/desktop_accessibility_snapshot.d.ts +4 -0
- package/dist/tools/desktop_accessibility_snapshot.d.ts.map +1 -0
- package/dist/tools/desktop_active_window.d.ts +4 -0
- package/dist/tools/desktop_active_window.d.ts.map +1 -0
- package/dist/tools/desktop_capture_desktop.d.ts +4 -0
- package/dist/tools/desktop_capture_desktop.d.ts.map +1 -0
- package/dist/tools/desktop_capture_window.d.ts +4 -0
- package/dist/tools/desktop_capture_window.d.ts.map +1 -0
- package/dist/tools/desktop_status.d.ts +4 -0
- package/dist/tools/desktop_status.d.ts.map +1 -0
- package/dist/tools/desktop_windows.d.ts +4 -0
- package/dist/tools/desktop_windows.d.ts.map +1 -0
- package/dist/tools/dialog.d.ts +4 -0
- package/dist/tools/dialog.d.ts.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/launch.d.ts.map +1 -1
- package/dist/tools/macro_resolve.d.ts.map +1 -1
- package/dist/tools/pointer_down.d.ts +4 -0
- package/dist/tools/pointer_down.d.ts.map +1 -0
- package/dist/tools/pointer_drag.d.ts +4 -0
- package/dist/tools/pointer_drag.d.ts.map +1 -0
- package/dist/tools/pointer_move.d.ts +4 -0
- package/dist/tools/pointer_move.d.ts.map +1 -0
- package/dist/tools/pointer_up.d.ts +4 -0
- package/dist/tools/pointer_up.d.ts.map +1 -0
- package/dist/tools/product_video_run.d.ts.map +1 -1
- package/dist/tools/prompting_guide.d.ts.map +1 -1
- package/dist/tools/research_run.d.ts.map +1 -1
- package/dist/tools/review.d.ts +4 -0
- package/dist/tools/review.d.ts.map +1 -0
- package/dist/tools/screencast_start.d.ts +4 -0
- package/dist/tools/screencast_start.d.ts.map +1 -0
- package/dist/tools/screencast_stop.d.ts +4 -0
- package/dist/tools/screencast_stop.d.ts.map +1 -0
- package/dist/tools/screenshot.d.ts.map +1 -1
- package/dist/tools/session_inspector.d.ts +4 -0
- package/dist/tools/session_inspector.d.ts.map +1 -0
- package/dist/tools/shopping_run.d.ts.map +1 -1
- package/dist/tools/skill_list.d.ts.map +1 -1
- package/dist/tools/skill_load.d.ts.map +1 -1
- package/dist/tools/upload.d.ts +4 -0
- package/dist/tools/upload.d.ts.map +1 -0
- package/dist/tools/workflow-runtime.d.ts +4 -1
- package/dist/tools/workflow-runtime.d.ts.map +1 -1
- package/dist/utils/package-assets.d.ts +4 -0
- package/dist/utils/package-assets.d.ts.map +1 -0
- package/extension/canvas.html +379 -9
- package/extension/dist/annotate-content.js +62 -32
- package/extension/dist/annotation-payload.js +57 -21
- package/extension/dist/background.js +406 -61
- package/extension/dist/canvas/canvas-runtime.js +481 -52
- package/extension/dist/canvas/model.js +129 -1
- package/extension/dist/canvas-page.js +1882 -74
- package/extension/dist/ops/dom-bridge.js +139 -0
- package/extension/dist/ops/ops-runtime.js +2854 -295
- package/extension/dist/ops/ops-session-store.js +83 -5
- package/extension/dist/ops/snapshot-builder.js +2 -2
- package/extension/dist/ops/snapshot-shared.js +2 -2
- package/extension/dist/ops/target-session-coordinator.js +5 -3
- package/extension/dist/popup.js +50 -15
- package/extension/dist/services/CDPRouter.js +1567 -63
- package/extension/dist/services/ConnectionManager.js +436 -78
- package/extension/dist/services/RelayClient.js +70 -30
- package/extension/dist/services/TabManager.js +83 -10
- package/extension/dist/services/TargetSessionMap.js +127 -3
- package/extension/dist/services/attach-errors.js +20 -0
- package/extension/dist/services/cdp-router-commands.js +135 -8
- package/extension/dist/services/url-restrictions.js +9 -13
- package/extension/manifest.json +2 -2
- package/extension/popup.html +7 -6
- package/package.json +15 -7
- package/skills/AGENTS.md +9 -8
- package/skills/opendevbrowser-best-practices/SKILL.md +118 -9
- package/skills/opendevbrowser-best-practices/artifacts/browser-agent-known-issues-matrix.md +1 -0
- package/skills/opendevbrowser-best-practices/artifacts/command-channel-reference.md +26 -12
- package/skills/opendevbrowser-best-practices/artifacts/parity-gates.md +9 -2
- package/skills/opendevbrowser-best-practices/artifacts/provider-workflows.md +6 -0
- package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +58 -0
- package/skills/opendevbrowser-best-practices/assets/templates/skill-runtime-pack-matrix.json +674 -0
- package/skills/opendevbrowser-best-practices/assets/templates/surface-audit-checklist.json +9 -4
- package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +89 -20
- package/skills/opendevbrowser-best-practices/scripts/resolve-odb-cli.sh +100 -0
- package/skills/opendevbrowser-best-practices/scripts/run-robustness-audit.sh +1 -0
- package/skills/opendevbrowser-best-practices/scripts/validate-skill-assets.sh +256 -116
- package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +208 -0
- package/skills/opendevbrowser-continuity-ledger/SKILL.md +14 -1
- package/skills/opendevbrowser-continuity-ledger/scripts/validate-skill-assets.sh +61 -0
- package/skills/opendevbrowser-data-extraction/SKILL.md +6 -0
- package/skills/opendevbrowser-data-extraction/scripts/validate-skill-assets.sh +112 -0
- package/skills/opendevbrowser-design-agent/SKILL.md +275 -0
- package/skills/opendevbrowser-design-agent/artifacts/app-shell-and-state-wiring.md +84 -0
- package/skills/opendevbrowser-design-agent/artifacts/async-search-state-ownership.md +58 -0
- package/skills/opendevbrowser-design-agent/artifacts/component-pattern-index.md +130 -0
- package/skills/opendevbrowser-design-agent/artifacts/design-contract-playbook.md +157 -0
- package/skills/opendevbrowser-design-agent/artifacts/design-release-gate.md +40 -0
- package/skills/opendevbrowser-design-agent/artifacts/design-workflows.md +153 -0
- package/skills/opendevbrowser-design-agent/artifacts/existing-surface-adaptation.md +56 -0
- package/skills/opendevbrowser-design-agent/artifacts/external-pattern-synthesis.md +103 -0
- package/skills/opendevbrowser-design-agent/artifacts/frontend-evaluation-rubric.md +61 -0
- package/skills/opendevbrowser-design-agent/artifacts/implementation-anti-patterns.md +163 -0
- package/skills/opendevbrowser-design-agent/artifacts/isolated-preview-validation.md +68 -0
- package/skills/opendevbrowser-design-agent/artifacts/loading-and-feedback-surfaces.md +56 -0
- package/skills/opendevbrowser-design-agent/artifacts/opendevbrowser-ui-example-map.md +44 -0
- package/skills/opendevbrowser-design-agent/artifacts/performance-audit-playbook.md +70 -0
- package/skills/opendevbrowser-design-agent/artifacts/research-harvest-workflow.md +81 -0
- package/skills/opendevbrowser-design-agent/artifacts/scroll-reveal-surface-planning.md +64 -0
- package/skills/opendevbrowser-design-agent/artifacts/state-ownership-matrix.md +36 -0
- package/skills/opendevbrowser-design-agent/artifacts/theming-and-token-ownership.md +43 -0
- package/skills/opendevbrowser-design-agent/assets/templates/canvas-generation-plan.design.v1.json +58 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-audit-report.v1.md +34 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-brief.v1.md +40 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-contract.v1.json +226 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-release-gate.v1.json +35 -0
- package/skills/opendevbrowser-design-agent/assets/templates/design-review-checklist.json +57 -0
- package/skills/opendevbrowser-design-agent/assets/templates/real-surface-design-matrix.json +32 -0
- package/skills/opendevbrowser-design-agent/assets/templates/reference-pattern-board.v1.json +31 -0
- package/skills/opendevbrowser-design-agent/scripts/design-workflow.sh +171 -0
- package/skills/opendevbrowser-design-agent/scripts/extract-canvas-plan.sh +56 -0
- package/skills/opendevbrowser-design-agent/scripts/validate-skill-assets.sh +223 -0
- package/skills/opendevbrowser-form-testing/SKILL.md +19 -3
- package/skills/opendevbrowser-form-testing/artifacts/form-workflows.md +5 -4
- package/skills/opendevbrowser-form-testing/assets/templates/challenge-decision-tree.json +2 -0
- package/skills/opendevbrowser-form-testing/scripts/validate-skill-assets.sh +109 -0
- package/skills/opendevbrowser-login-automation/SKILL.md +21 -3
- package/skills/opendevbrowser-login-automation/artifacts/login-workflows.md +5 -4
- package/skills/opendevbrowser-login-automation/assets/templates/auth-signals.json +5 -0
- package/skills/opendevbrowser-login-automation/assets/templates/login-scenario-matrix.json +3 -2
- package/skills/opendevbrowser-login-automation/scripts/run-login-workflow.sh +17 -1
- package/skills/opendevbrowser-login-automation/scripts/validate-skill-assets.sh +133 -0
- package/skills/opendevbrowser-product-presentation-asset/SKILL.md +23 -11
- package/skills/opendevbrowser-product-presentation-asset/artifacts/asset-pack-assembly.md +5 -3
- package/skills/opendevbrowser-product-presentation-asset/assets/templates/shot-list.md +2 -0
- package/skills/opendevbrowser-product-presentation-asset/assets/templates/video-assembly.md +3 -2
- package/skills/opendevbrowser-product-presentation-asset/scripts/capture-screenshots.sh +5 -1
- package/skills/opendevbrowser-product-presentation-asset/scripts/collect-product.sh +6 -2
- package/skills/opendevbrowser-product-presentation-asset/scripts/download-images.sh +5 -1
- package/skills/opendevbrowser-product-presentation-asset/scripts/render-video-brief.sh +20 -7
- package/skills/opendevbrowser-product-presentation-asset/scripts/validate-skill-assets.sh +39 -0
- package/skills/opendevbrowser-product-presentation-asset/scripts/write-manifest.sh +5 -1
- package/skills/opendevbrowser-research/SKILL.md +14 -6
- package/skills/opendevbrowser-research/scripts/render-output.sh +5 -1
- package/skills/opendevbrowser-research/scripts/run-research.sh +5 -1
- package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +45 -0
- package/skills/opendevbrowser-research/scripts/write-artifacts.sh +5 -1
- package/skills/opendevbrowser-shopping/SKILL.md +20 -1
- package/skills/opendevbrowser-shopping/scripts/normalize-offers.sh +6 -2
- package/skills/opendevbrowser-shopping/scripts/run-deal-hunt.sh +5 -1
- package/skills/opendevbrowser-shopping/scripts/run-shopping.sh +5 -1
- package/skills/opendevbrowser-shopping/scripts/validate-skill-assets.sh +54 -0
- package/dist/chunk-5J3IFL3X.js +0 -16706
- package/dist/chunk-5J3IFL3X.js.map +0 -1
- package/dist/chunk-D633UO34.js +0 -8149
- package/dist/chunk-D633UO34.js.map +0 -1
- package/dist/chunk-V7KUDHDG.js +0 -276
- package/dist/chunk-V7KUDHDG.js.map +0 -1
- package/dist/runtime-factory-BICHDPE7.js +0 -13
- /package/dist/{providers-G3LRHQXX.js.map → providers-G36AM3Z2.js.map} +0 -0
- /package/dist/{runtime-factory-BICHDPE7.js.map → skills/skill-loader.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
CLI_COMMANDS,
|
|
4
|
+
CLI_COMMAND_HELP_DETAILS,
|
|
3
5
|
DaemonClient,
|
|
4
6
|
EXIT_DISCONNECTED,
|
|
5
7
|
EXIT_EXECUTION,
|
|
6
8
|
EXIT_USAGE,
|
|
9
|
+
PUBLIC_CLI_COMMAND_GROUPS,
|
|
10
|
+
TOOL_SURFACE_ENTRIES,
|
|
11
|
+
VALID_EQUALS_FLAGS,
|
|
12
|
+
VALID_FLAGS,
|
|
7
13
|
buildAnnotateResult,
|
|
8
14
|
callDaemon,
|
|
9
15
|
createOpenDevBrowserCore,
|
|
@@ -14,82 +20,35 @@ import {
|
|
|
14
20
|
fetchWithTimeout,
|
|
15
21
|
formatErrorPayload,
|
|
16
22
|
generateSecureToken,
|
|
23
|
+
getChromeUserDataRoots,
|
|
17
24
|
getExtensionPath,
|
|
25
|
+
getProfileDirs,
|
|
18
26
|
loadGlobalConfig,
|
|
27
|
+
onboarding_metadata_default,
|
|
19
28
|
readDaemonMetadata,
|
|
29
|
+
readProfilePreferences,
|
|
20
30
|
resolveExitCode,
|
|
21
31
|
startDaemon,
|
|
22
32
|
toCliError
|
|
23
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-L57D35TB.js";
|
|
34
|
+
import {
|
|
35
|
+
getBundledSkillsDir,
|
|
36
|
+
listBundledSkillDirectories
|
|
37
|
+
} from "../chunk-YBQECXZX.js";
|
|
24
38
|
import "../chunk-Y2KL55OG.js";
|
|
25
39
|
import {
|
|
26
40
|
writeFileAtomic
|
|
27
41
|
} from "../chunk-TBUCZX4A.js";
|
|
28
|
-
import "../chunk-V7KUDHDG.js";
|
|
29
42
|
import {
|
|
30
|
-
cleanupExpiredArtifacts
|
|
31
|
-
|
|
43
|
+
cleanupExpiredArtifacts,
|
|
44
|
+
isChallengeAutomationMode,
|
|
45
|
+
setDefaultLogSink,
|
|
46
|
+
stderrSink,
|
|
47
|
+
summarizePrimaryProviderIssue
|
|
48
|
+
} from "../chunk-5FZQJRBQ.js";
|
|
32
49
|
import "../chunk-FUSXMW3G.js";
|
|
33
50
|
|
|
34
51
|
// 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
52
|
var CLI_COMMAND_SET = new Set(CLI_COMMANDS);
|
|
94
53
|
var SHORT_FLAGS = {
|
|
95
54
|
"-g": "--global",
|
|
@@ -153,158 +112,7 @@ function parseTransport(args) {
|
|
|
153
112
|
}
|
|
154
113
|
throw createUsageError(`Invalid --transport: ${value ?? "missing"}`);
|
|
155
114
|
}
|
|
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
115
|
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
116
|
var VALID_EQUALS_FLAG_SET = new Set(VALID_EQUALS_FLAGS);
|
|
309
117
|
function parseArgs(argv) {
|
|
310
118
|
let args = expandShortFlags(argv.slice(2));
|
|
@@ -451,77 +259,28 @@ function listCommands() {
|
|
|
451
259
|
|
|
452
260
|
// src/cli/help.ts
|
|
453
261
|
var LABEL_WIDTH = 42;
|
|
454
|
-
var
|
|
262
|
+
var DETAIL_LABEL_WIDTH = 9;
|
|
455
263
|
var COMMAND_SET = new Set(CLI_COMMANDS);
|
|
456
264
|
var FLAG_SET = new Set(VALID_FLAGS);
|
|
457
|
-
var
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
-
];
|
|
265
|
+
var TOOL_COUNT = TOOL_SURFACE_ENTRIES.length;
|
|
266
|
+
var formatFlags = (flags) => flags.length > 0 ? flags.join(", ") : "none";
|
|
267
|
+
var HELP_COMMAND_GROUPS = PUBLIC_CLI_COMMAND_GROUPS.map((group) => ({
|
|
268
|
+
title: group.title,
|
|
269
|
+
summary: group.summary,
|
|
270
|
+
commands: group.commands.map((command) => command.name)
|
|
271
|
+
}));
|
|
272
|
+
var COMMAND_HELP_DETAILS = CLI_COMMAND_HELP_DETAILS;
|
|
514
273
|
var HELP_FLAG_GROUPS = [
|
|
515
274
|
{
|
|
516
|
-
title: "Install/Global Flags",
|
|
517
|
-
summary: "Control
|
|
275
|
+
title: "Install / Global Flags",
|
|
276
|
+
summary: "Control install scope, prompting, and bundled skill setup.",
|
|
518
277
|
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." },
|
|
278
|
+
{ flag: "--global", alias: "-g", description: "Install into ~/.config/opencode/opencode.json.", example: "npx opendevbrowser --global --with-config" },
|
|
279
|
+
{ flag: "--local", alias: "-l", description: "Install into ./opencode.json for this project.", example: "npx opendevbrowser --local --skills-local" },
|
|
521
280
|
{ flag: "--update", alias: "-u", description: "Alias for the update command." },
|
|
522
281
|
{ 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." },
|
|
282
|
+
{ flag: "--with-config", description: "Also create opendevbrowser.jsonc defaults.", example: "npx opendevbrowser --global --with-config" },
|
|
283
|
+
{ flag: "--full", alias: "-f", description: "Install config and pre-extract extension assets.", example: "npx opendevbrowser --full" },
|
|
525
284
|
{ flag: "--no-prompt", description: "Run non-interactively using defaults." },
|
|
526
285
|
{ flag: "--no-interactive", description: "Alias of --no-prompt." },
|
|
527
286
|
{ flag: "--quiet", description: "Suppress non-error text output." },
|
|
@@ -531,179 +290,241 @@ var HELP_FLAG_GROUPS = [
|
|
|
531
290
|
]
|
|
532
291
|
},
|
|
533
292
|
{
|
|
534
|
-
title: "Help/Output Flags",
|
|
535
|
-
summary: "Inspect help
|
|
293
|
+
title: "Help / Output Flags",
|
|
294
|
+
summary: "Inspect help or version and control output transport.",
|
|
536
295
|
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." }
|
|
296
|
+
{ flag: "--help", alias: "-h", description: "Show CLI help output.", example: "npx opendevbrowser --help" },
|
|
297
|
+
{ flag: "--version", alias: "-v", description: "Show CLI version.", example: "npx opendevbrowser --version" },
|
|
298
|
+
{ flag: "--output-format", description: "Output mode: text, json, or stream-json.", example: "opendevbrowser status --daemon --output-format json" },
|
|
299
|
+
{ flag: "--transport", description: "Transport selector for transport-aware commands. `status` uses relay/native; `annotate` uses auto/direct/relay.", example: "opendevbrowser status --session-id s1 --transport native" }
|
|
541
300
|
]
|
|
542
301
|
},
|
|
543
302
|
{
|
|
544
|
-
title: "Daemon/Session/Launch Flags",
|
|
545
|
-
summary: "Control daemon binding, connect, and launch behavior.",
|
|
303
|
+
title: "Daemon / Session / Launch Flags",
|
|
304
|
+
summary: "Control daemon binding, browser connect, and launch behavior. If ext=on but handshake=off, reopen the extension popup and click Connect again to re-establish a clean daemon-extension handshake.",
|
|
546
305
|
flags: [
|
|
547
|
-
{ flag: "--port", description: "Daemon or relay port override." },
|
|
548
|
-
{ flag: "--token", description: "Relay
|
|
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." },
|
|
306
|
+
{ flag: "--port", description: "Daemon or relay port override.", example: "opendevbrowser serve --port 8788" },
|
|
307
|
+
{ flag: "--token", description: "Relay or daemon auth token override.", example: "opendevbrowser serve --token local-dev-token" },
|
|
308
|
+
{ flag: "--stop", description: "Stop a running daemon.", example: "opendevbrowser serve --stop" },
|
|
309
|
+
{ flag: "--daemon", description: "Target daemon status mode where supported.", example: "opendevbrowser status --daemon --output-format json" },
|
|
310
|
+
{ flag: "--script", description: "Path to a run-script JSON file.", example: "opendevbrowser run --script ./workflow.json" },
|
|
311
|
+
{ flag: "--session-id", description: "Target an existing browser or daemon session.", example: "opendevbrowser snapshot --session-id s1" },
|
|
312
|
+
{ flag: "--close-browser", description: "Close the managed browser on disconnect." },
|
|
313
|
+
{ flag: "--ws-endpoint", description: "Connect using an explicit CDP WebSocket endpoint.", example: "opendevbrowser connect --ws-endpoint ws://127.0.0.1:9222/devtools/browser/..." },
|
|
314
|
+
{ flag: "--host", description: "CDP host for host/port connect mode.", example: "opendevbrowser connect --host 127.0.0.1 --cdp-port 9222" },
|
|
556
315
|
{ flag: "--cdp-port", description: "CDP port for host/port connect mode." },
|
|
557
|
-
{ flag: "--headless", description: "Launch managed browser in headless mode." },
|
|
316
|
+
{ flag: "--headless", description: "Launch a managed browser in headless mode.", example: "opendevbrowser launch --no-extension --headless" },
|
|
558
317
|
{ 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
|
|
318
|
+
{ flag: "--persist-profile", description: "Keep the generated profile directory after exit. `run` uses a temporary profile by default unless this flag is enabled." },
|
|
319
|
+
{ flag: "--chrome-path", description: "Use a specific Chrome, Chromium, or CfT binary." },
|
|
561
320
|
{ flag: "--start-url", description: "Open this URL immediately after launch or connect." },
|
|
562
321
|
{ flag: "--flag", description: "Pass one or more extra Chrome CLI flags." },
|
|
563
322
|
{ 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." },
|
|
323
|
+
{ flag: "--extension-only", description: "Fail unless the extension relay websocket is connected and the daemon-extension handshake is complete." },
|
|
324
|
+
{ flag: "--extension-legacy", description: "Use the legacy /cdp relay mode instead of /ops." },
|
|
325
|
+
{ flag: "--wait-for-extension", description: "Wait for a clean daemon-extension handshake before returning." },
|
|
567
326
|
{ flag: "--wait-timeout-ms", description: "Handshake wait timeout in milliseconds." }
|
|
568
327
|
]
|
|
569
328
|
},
|
|
570
329
|
{
|
|
571
|
-
title: "Navigation/Interaction/Diagnostics Flags",
|
|
572
|
-
summary: "Command-specific flags for page actions and diagnostics.",
|
|
330
|
+
title: "Navigation / Interaction / Diagnostics Flags",
|
|
331
|
+
summary: "Command-specific flags for page actions, reads, and diagnostics.",
|
|
573
332
|
flags: [
|
|
574
|
-
{ flag: "--url", description: "Target URL for navigation, connect, or workflow commands." },
|
|
575
|
-
{ flag: "--wait-until", description: "Navigation wait strategy
|
|
576
|
-
{ flag: "--timeout-ms", description: "Operation timeout in milliseconds
|
|
577
|
-
{ flag: "--ref", description: "Snapshot ref id for element-targeted commands." },
|
|
333
|
+
{ flag: "--url", description: "Target URL for navigation, connect, or workflow commands.", example: "opendevbrowser goto --session-id s1 --url https://example.com" },
|
|
334
|
+
{ flag: "--wait-until", description: "Navigation wait strategy such as load or domcontentloaded." },
|
|
335
|
+
{ flag: "--timeout-ms", description: "Operation timeout in milliseconds.", example: "opendevbrowser canvas --timeout-ms 120000 --command canvas.session.open ..." },
|
|
336
|
+
{ flag: "--ref", description: "Snapshot ref id for element-targeted commands.", example: "opendevbrowser click --session-id s1 --ref r12" },
|
|
578
337
|
{ flag: "--state", description: "Wait state selector for wait-style commands." },
|
|
579
338
|
{ flag: "--until", description: "Wait condition selector for wait-style commands." },
|
|
580
339
|
{ flag: "--mode", description: "Mode selector for commands that accept variants." },
|
|
581
340
|
{ flag: "--max-chars", description: "Maximum text characters to return for DOM reads." },
|
|
582
341
|
{ flag: "--cursor", description: "Cursor token for paginated list commands." },
|
|
583
342
|
{ 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
|
|
343
|
+
{ flag: "--clear", description: "Clear the existing input value before typing." },
|
|
344
|
+
{ flag: "--submit", description: "Submit the form or input after typing." },
|
|
586
345
|
{ flag: "--values", description: "CSV values for select commands." },
|
|
346
|
+
{ flag: "--files", description: "CSV file paths for upload commands." },
|
|
587
347
|
{ 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
|
|
348
|
+
{ flag: "--key", description: "Keyboard key for the press command." },
|
|
349
|
+
{ flag: "--attr", description: "DOM attribute name for dom-attr." },
|
|
350
|
+
{ flag: "--x", description: "Viewport x coordinate for pointer commands." },
|
|
351
|
+
{ flag: "--y", description: "Viewport y coordinate for pointer commands." },
|
|
352
|
+
{ flag: "--from-x", description: "Pointer drag start x coordinate." },
|
|
353
|
+
{ flag: "--from-y", description: "Pointer drag start y coordinate." },
|
|
354
|
+
{ flag: "--to-x", description: "Pointer drag end x coordinate." },
|
|
355
|
+
{ flag: "--to-y", description: "Pointer drag end y coordinate." },
|
|
356
|
+
{ flag: "--steps", description: "Interpolation step count for pointer move or drag commands." },
|
|
357
|
+
{ flag: "--button", description: "Pointer button selector for pointer down or up." },
|
|
358
|
+
{ flag: "--click-count", description: "Associated click count for pointer down or up." },
|
|
590
359
|
{ flag: "--name", description: "Named page identifier for page commands." },
|
|
591
|
-
{ flag: "--target-id", description: "Browser target id for target commands." },
|
|
592
|
-
{ flag: "--
|
|
360
|
+
{ flag: "--target-id", description: "Browser target id for target commands.", example: "opendevbrowser target-use --session-id s1 --target-id page-2" },
|
|
361
|
+
{ flag: "--window-id", description: "Desktop window id for direct window capture commands." },
|
|
362
|
+
{ flag: "--tab-id", description: "Browser tab id override for extension and annotation commands." },
|
|
593
363
|
{ flag: "--include-urls", description: "Include page URLs in list output where supported." },
|
|
594
|
-
{ flag: "--path", description: "Filesystem path for command output
|
|
595
|
-
{ flag: "--
|
|
596
|
-
{ flag: "--
|
|
597
|
-
{ flag: "--
|
|
598
|
-
{ flag: "--
|
|
599
|
-
{ flag: "--
|
|
600
|
-
{ flag: "--
|
|
601
|
-
{ flag: "--
|
|
364
|
+
{ flag: "--path", description: "Filesystem path for command output or artifacts.", example: "opendevbrowser screenshot --session-id s1 --path ./shot.png" },
|
|
365
|
+
{ flag: "--screencast-id", description: "Recorded screencast id returned by screencast-start for the same session." },
|
|
366
|
+
{ flag: "--reason", description: "Audit reason for desktop observation commands." },
|
|
367
|
+
{ flag: "--full-page", description: "Capture the full scrollable page instead of the current viewport." },
|
|
368
|
+
{ flag: "--action", description: "Dialog action: status, accept, or dismiss." },
|
|
369
|
+
{ flag: "--prompt-text", description: "Prompt text to submit when accepting a prompt dialog." },
|
|
370
|
+
{ flag: "--since-seq", description: "Poll from a sequence id across diagnostics streams." },
|
|
371
|
+
{ flag: "--max", description: "Maximum number of records or items to return." },
|
|
372
|
+
{ flag: "--interval-ms", description: "Frame capture interval for screencast recording." },
|
|
373
|
+
{ flag: "--max-frames", description: "Maximum screencast frame count before auto-stop." },
|
|
374
|
+
{ flag: "--since-console-seq", description: "Console sequence cursor for debug-trace snapshots." },
|
|
375
|
+
{ flag: "--since-network-seq", description: "Network sequence cursor for debug-trace snapshots." },
|
|
376
|
+
{ flag: "--since-exception-seq", description: "Exception sequence cursor for debug-trace snapshots." },
|
|
377
|
+
{ flag: "--request-id", description: "Attach or lookup a request id for correlated output." },
|
|
378
|
+
{ flag: "--cookies", description: "Inline cookie payload for cookie-import." },
|
|
602
379
|
{ flag: "--cookies-file", description: "File path containing cookies for cookie-import." },
|
|
603
380
|
{ flag: "--strict", description: "Fail cookie import on invalid entries." },
|
|
604
381
|
{ flag: "--screenshot-mode", description: "Annotation screenshot mode: visible, full, or none." },
|
|
605
382
|
{ flag: "--debug", description: "Enable debug-level annotation capture extras." },
|
|
606
|
-
{ flag: "--context", description: "Free-form annotation context for reviewers
|
|
383
|
+
{ flag: "--context", description: "Free-form annotation context for reviewers or agents." },
|
|
607
384
|
{ flag: "--stored", description: "Return the last stored annotation payload instead of starting a new capture." }
|
|
608
385
|
]
|
|
609
386
|
},
|
|
610
387
|
{
|
|
611
|
-
title: "Macro/Provider/Power Flags",
|
|
612
|
-
summary: "Workflow filters, provider selectors, and unsafe RPC options.",
|
|
388
|
+
title: "Macro / Provider / Power Flags",
|
|
389
|
+
summary: "Workflow filters, provider selectors, and unsafe RPC or /canvas options.",
|
|
613
390
|
flags: [
|
|
614
|
-
{ flag: "--expression", description: "Macro expression to resolve
|
|
391
|
+
{ flag: "--expression", description: "Macro expression to resolve or execute.", example: `opendevbrowser macro-resolve --expression '@web.search("openai")'` },
|
|
615
392
|
{ flag: "--default-provider", description: "Provider fallback for shorthand macro expressions." },
|
|
616
|
-
{ flag: "--include-catalog", description: "Include macro catalog metadata in response." },
|
|
617
|
-
{ flag: "--
|
|
618
|
-
{ flag: "--
|
|
393
|
+
{ flag: "--include-catalog", description: "Include macro catalog metadata in the response." },
|
|
394
|
+
{ flag: "--command", description: "Canvas command name for the canvas CLI command.", example: "opendevbrowser canvas --command canvas.session.open --params '{...}'" },
|
|
395
|
+
{ flag: "--execute", description: "Execute a resolved macro action after planning." },
|
|
619
396
|
{ 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." },
|
|
397
|
+
{ flag: "--params-file", description: "Path to a JSON params file for canvas or rpc commands.", example: "opendevbrowser canvas --command canvas.plan.set --params-file ./plan.json" },
|
|
398
|
+
{ flag: "--unsafe-internal", description: "Required safety gate for the rpc command." },
|
|
622
399
|
{ flag: "--topic", description: "Research topic input." },
|
|
623
400
|
{ flag: "--days", description: "Lookback window in days for research commands." },
|
|
624
401
|
{ flag: "--from", description: "Start date boundary for research commands." },
|
|
625
402
|
{ 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." },
|
|
403
|
+
{ flag: "--source-selection", description: "Research source-family selector. Use auto for generic topical research; add shopping only for deliberate commercial comparison." },
|
|
404
|
+
{ flag: "--sources", description: "Explicit source selectors within a source family. Use shopping only when commercial intent is explicit." },
|
|
628
405
|
{ flag: "--include-engagement", description: "Include engagement metrics in research output." },
|
|
629
406
|
{ flag: "--limit-per-source", description: "Per-source result cap for research runs." },
|
|
630
407
|
{ flag: "--query", description: "Shopping query input." },
|
|
631
|
-
{ flag: "--providers", description: "Comma-separated provider ids for shopping
|
|
408
|
+
{ flag: "--providers", description: "Comma-separated provider ids for shopping or artifact commands." },
|
|
632
409
|
{ flag: "--budget", description: "Budget filter for shopping workflows." },
|
|
633
|
-
{ flag: "--region", description: "Region
|
|
410
|
+
{ flag: "--region", description: "Region or country hint for provider selection. Treat it as advisory unless output metadata reports `region_authoritative=true`." },
|
|
634
411
|
{ flag: "--sort", description: "Sort mode for shopping results." },
|
|
635
|
-
{ flag: "--product-url", description: "Target product URL for product-video
|
|
636
|
-
{ flag: "--product-name", description: "Product name override for
|
|
412
|
+
{ flag: "--product-url", description: "Target product URL for product-video workflows." },
|
|
413
|
+
{ flag: "--product-name", description: "Product name override for product-video workflows." },
|
|
637
414
|
{ flag: "--provider-hint", description: "Provider hint override for product workflows." },
|
|
638
415
|
{ flag: "--include-screenshots", description: "Include screenshots in product presentation output, or prefer screenshots when fetching stored annotations." },
|
|
639
416
|
{ flag: "--include-all-images", description: "Include all discovered product images." },
|
|
640
417
|
{ flag: "--include-copy", description: "Include product marketing copy metadata." },
|
|
641
|
-
{ flag: "--
|
|
418
|
+
{ flag: "--use-cookies", description: "Enable or disable provider cookie injection for workflow runs; a bare flag means true.", example: "opendevbrowser shopping run --query 'usb hub' --use-cookies" },
|
|
419
|
+
{ flag: "--browser-mode", description: "Shopping browser-recovery preference: auto, extension, or managed. Use managed for deterministic reruns and extension only when relay-backed auth/session state is required.", example: "opendevbrowser shopping run --query 'wireless ergonomic mouse' --providers shopping/bestbuy,shopping/ebay --browser-mode managed" },
|
|
420
|
+
{ flag: "--challenge-automation-mode", description: "Per-run challenge automation mode for workflow runs and macro-resolve execute: off, browser, or browser_with_helper. Precedence is run > session > config, and the helper remains browser-scoped only.", example: `opendevbrowser macro-resolve --expression '@community.search("openai")' --execute --challenge-automation-mode browser_with_helper` },
|
|
421
|
+
{ flag: "--cookie-policy-override", description: "Per-run workflow cookie policy override: off, auto, or required.", example: "opendevbrowser research run --topic 'agent workflows' --cookie-policy-override required" },
|
|
422
|
+
{ flag: "--cookie-policy", description: "Alias of --cookie-policy-override." },
|
|
423
|
+
{ flag: "--output-dir", description: "Directory where generated artifacts are written, including screencast replay output." },
|
|
642
424
|
{ flag: "--ttl-hours", description: "Artifact cache time-to-live in hours." },
|
|
643
425
|
{ flag: "--expired-only", description: "List only expired artifacts in artifacts commands." }
|
|
644
426
|
]
|
|
645
427
|
}
|
|
646
428
|
];
|
|
647
|
-
var HELP_TOOL_ENTRIES =
|
|
648
|
-
|
|
649
|
-
{
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
{
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
{
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
{
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
{
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
{
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
{
|
|
695
|
-
|
|
696
|
-
|
|
429
|
+
var HELP_TOOL_ENTRIES = TOOL_SURFACE_ENTRIES;
|
|
430
|
+
var HELP_CAPABILITY_ENTRIES = [
|
|
431
|
+
{
|
|
432
|
+
label: "screencast / browser replay",
|
|
433
|
+
description: "Use the public browser replay lane when you need temporal browser evidence before or after a fragile flow.",
|
|
434
|
+
details: [
|
|
435
|
+
{ label: "cli:", value: "screencast-start, screencast-stop" },
|
|
436
|
+
{ label: "example:", value: "npx opendevbrowser screencast-start --session-id <id> --output-dir ./artifacts/replay" }
|
|
437
|
+
]
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
label: "desktop observation",
|
|
441
|
+
description: "Use the public read-only desktop observation plane for sibling desktop evidence on macOS; window inventory and accessibility probes use the local swift command, while screenshots use screencapture outside extension relay.",
|
|
442
|
+
details: [
|
|
443
|
+
{
|
|
444
|
+
label: "cli:",
|
|
445
|
+
value: "desktop-status, desktop-windows, desktop-active-window, desktop-capture-desktop, desktop-capture-window, desktop-accessibility-snapshot"
|
|
446
|
+
},
|
|
447
|
+
{ label: "example:", value: "npx opendevbrowser desktop-status --output-format json" }
|
|
448
|
+
]
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
label: "computer use / browser-scoped computer use",
|
|
452
|
+
description: "Control the bounded browser-scoped computer-use challenge lane with --challenge-automation-mode; the optional helper is not a desktop agent.",
|
|
453
|
+
details: [
|
|
454
|
+
{ label: "flag:", value: "--challenge-automation-mode off|browser|browser_with_helper" },
|
|
455
|
+
{ label: "works:", value: "research run, shopping run, product-video run, macro-resolve --execute" },
|
|
456
|
+
{ label: "proof:", value: "review, session-inspector, workflow fallback metadata" }
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
];
|
|
460
|
+
var HELP_ONBOARDING_ENTRIES = [
|
|
461
|
+
{
|
|
462
|
+
label: "prompting_guide",
|
|
463
|
+
description: "Load local best-practice guidance before low-level browser commands.",
|
|
464
|
+
details: [{ label: "tool:", value: onboarding_metadata_default.quickStartCommands.promptingGuide }]
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
label: "skill_load",
|
|
468
|
+
description: `Load ${onboarding_metadata_default.skillName} ${onboarding_metadata_default.skillTopic} directly when you want the canonical quick-start section.`,
|
|
469
|
+
details: [{ label: "tool:", value: onboarding_metadata_default.quickStartCommands.skillLoad }]
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
label: "validated_lanes",
|
|
473
|
+
description: `Load ${onboarding_metadata_default.skillName} ${onboarding_metadata_default.validatedSkillTopic} when you need the current proven transcript, research, and shopping runbook.`,
|
|
474
|
+
details: [{ label: "tool:", value: onboarding_metadata_default.quickStartCommands.validatedLanes }]
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
label: "skill_list",
|
|
478
|
+
description: "Inspect bundled and discovered skill packs when you need a different local lane.",
|
|
479
|
+
details: [{ label: "tool:", value: onboarding_metadata_default.quickStartCommands.skillList }]
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
label: "research_reliable",
|
|
483
|
+
description: "Generic topical research is currently safest with `--source-selection auto`; add shopping only when the task is explicitly commercial.",
|
|
484
|
+
details: [{ label: "cli:", value: onboarding_metadata_default.quickStartCommands.validatedResearch }]
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
label: "shopping_reliable",
|
|
488
|
+
description: "Start deal hunting with explicit providers in managed mode and only trust regional comparisons when the result reports `region_authoritative=true`.",
|
|
489
|
+
details: [{ label: "cli:", value: onboarding_metadata_default.quickStartCommands.validatedShopping }]
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
label: "happy_path",
|
|
493
|
+
description: "After guidance, verify a minimal managed happy path before widening into multi-step automation.",
|
|
494
|
+
details: [{ label: "cli:", value: onboarding_metadata_default.quickStartCommands.happyPath }]
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
label: "docs",
|
|
498
|
+
description: "Use the first-run checklist and canonical skill runbook for proof and deeper operating details.",
|
|
499
|
+
details: [{
|
|
500
|
+
label: "paths:",
|
|
501
|
+
value: `${onboarding_metadata_default.referencePaths.onboardingDoc}, ${onboarding_metadata_default.referencePaths.skillDoc}`
|
|
502
|
+
}]
|
|
503
|
+
}
|
|
697
504
|
];
|
|
698
505
|
var HELP_REFERENCE_ENTRIES = [
|
|
699
|
-
{ label: "
|
|
700
|
-
{ label: "
|
|
701
|
-
{ label: "src/
|
|
506
|
+
{ label: "src/cli/onboarding-metadata.json", description: "Canonical first-contact onboarding metadata shared by help, nudges, and proof lanes." },
|
|
507
|
+
{ label: "src/public-surface/source.ts", description: "Authoritative command, usage, flag, and tool surface metadata." },
|
|
508
|
+
{ label: "src/public-surface/generated-manifest.ts", description: "Checked-in generated public-surface snapshot consumed by help and parity tests." },
|
|
509
|
+
{ label: "src/public-surface/generated-manifest.json", description: "Checked-in generated public-surface snapshot consumed by inventory scripts." },
|
|
510
|
+
{ label: "src/cli/args.ts", description: "CLI argument parsing backed by the public-surface source." },
|
|
511
|
+
{ label: "src/cli/help.ts", description: "Human-facing CLI formatting layered on the public-surface source, including the first-contact Find It Fast lookup block." },
|
|
512
|
+
{ label: "src/tools/index.ts", description: "Code-level tool registry." },
|
|
513
|
+
{ label: "docs/CLI.md", description: "Detailed CLI guide and release-gate runbooks." },
|
|
514
|
+
{ label: onboarding_metadata_default.referencePaths.onboardingDoc, description: "First-run checklist for help-led onboarding and happy-path proof." },
|
|
515
|
+
{ label: onboarding_metadata_default.referencePaths.skillDoc, description: "Canonical bundled best-practices runbook and quick-start guidance." },
|
|
516
|
+
{ label: "docs/SURFACE_REFERENCE.md", description: "Canonical CLI, tool, and relay channel inventory." },
|
|
702
517
|
{ label: "opendevbrowser --help", description: "Primary full help invocation for quick discovery." },
|
|
703
518
|
{ label: "opendevbrowser help", description: "Alias that prints the same full help inventory." }
|
|
704
519
|
];
|
|
705
520
|
function formatRows(rows) {
|
|
706
|
-
return rows.map((row) =>
|
|
521
|
+
return rows.map((row) => {
|
|
522
|
+
const lines = [` ${row.label.padEnd(LABEL_WIDTH)} ${row.description}`];
|
|
523
|
+
for (const detail of row.details ?? []) {
|
|
524
|
+
lines.push(` ${detail.label.padEnd(DETAIL_LABEL_WIDTH)} ${detail.value}`);
|
|
525
|
+
}
|
|
526
|
+
return lines.join("\n");
|
|
527
|
+
}).join("\n");
|
|
707
528
|
}
|
|
708
529
|
function getCommandDescriptions() {
|
|
709
530
|
const descriptions = /* @__PURE__ */ new Map();
|
|
@@ -716,6 +537,7 @@ function assertCommandCoverage(commandDescriptions) {
|
|
|
716
537
|
const seen = /* @__PURE__ */ new Set();
|
|
717
538
|
for (const group of HELP_COMMAND_GROUPS) {
|
|
718
539
|
for (const command of group.commands) {
|
|
540
|
+
const detail = COMMAND_HELP_DETAILS[command];
|
|
719
541
|
if (!COMMAND_SET.has(command)) {
|
|
720
542
|
throw new Error(`Help references unknown CLI command: ${command}`);
|
|
721
543
|
}
|
|
@@ -725,6 +547,14 @@ function assertCommandCoverage(commandDescriptions) {
|
|
|
725
547
|
if (seen.has(command)) {
|
|
726
548
|
throw new Error(`Help command appears multiple times: ${command}`);
|
|
727
549
|
}
|
|
550
|
+
if (!detail || !detail.usage.trim()) {
|
|
551
|
+
throw new Error(`Missing command help metadata: ${command}`);
|
|
552
|
+
}
|
|
553
|
+
for (const flag of detail.flags) {
|
|
554
|
+
if (!FLAG_SET.has(flag)) {
|
|
555
|
+
throw new Error(`Command help metadata references unknown flag ${flag} for ${command}`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
728
558
|
seen.add(command);
|
|
729
559
|
}
|
|
730
560
|
}
|
|
@@ -752,26 +582,39 @@ function assertFlagCoverage() {
|
|
|
752
582
|
}
|
|
753
583
|
}
|
|
754
584
|
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
585
|
const seen = /* @__PURE__ */ new Set();
|
|
759
586
|
for (const entry of HELP_TOOL_ENTRIES) {
|
|
587
|
+
if (!entry.name.startsWith("opendevbrowser_")) {
|
|
588
|
+
throw new Error(`Invalid tool name in help inventory: ${entry.name}`);
|
|
589
|
+
}
|
|
590
|
+
if (!entry.description.trim()) {
|
|
591
|
+
throw new Error(`Help tool is missing a description: ${entry.name}`);
|
|
592
|
+
}
|
|
760
593
|
if (seen.has(entry.name)) {
|
|
761
594
|
throw new Error(`Help tool appears multiple times: ${entry.name}`);
|
|
762
595
|
}
|
|
763
|
-
if (
|
|
764
|
-
throw new Error(`
|
|
596
|
+
if (entry.cliEquivalent && !COMMAND_SET.has(entry.cliEquivalent)) {
|
|
597
|
+
throw new Error(`Tool metadata references unknown CLI command: ${entry.cliEquivalent}`);
|
|
765
598
|
}
|
|
766
599
|
seen.add(entry.name);
|
|
767
600
|
}
|
|
601
|
+
if (HELP_TOOL_ENTRIES.length !== TOOL_COUNT) {
|
|
602
|
+
throw new Error(`Help tool inventory must list ${TOOL_COUNT} tools; got ${HELP_TOOL_ENTRIES.length}`);
|
|
603
|
+
}
|
|
768
604
|
}
|
|
769
605
|
function formatCommandGroups(commandDescriptions) {
|
|
770
606
|
return HELP_COMMAND_GROUPS.map((group) => {
|
|
771
|
-
const rows = group.commands.map((command) =>
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
607
|
+
const rows = group.commands.map((command) => {
|
|
608
|
+
const detail = COMMAND_HELP_DETAILS[command];
|
|
609
|
+
return {
|
|
610
|
+
label: command,
|
|
611
|
+
description: commandDescriptions.get(command) ?? "Missing command description.",
|
|
612
|
+
details: [
|
|
613
|
+
{ label: "usage:", value: detail.usage },
|
|
614
|
+
{ label: "flags:", value: formatFlags(detail.flags) }
|
|
615
|
+
]
|
|
616
|
+
};
|
|
617
|
+
});
|
|
775
618
|
return `${group.title}: ${group.summary}
|
|
776
619
|
${formatRows(rows)}`;
|
|
777
620
|
}).join("\n\n");
|
|
@@ -780,7 +623,8 @@ function formatFlagGroups() {
|
|
|
780
623
|
return HELP_FLAG_GROUPS.map((group) => {
|
|
781
624
|
const rows = group.flags.map((entry) => ({
|
|
782
625
|
label: entry.alias ? `${entry.flag} (${entry.alias})` : entry.flag,
|
|
783
|
-
description: entry.description
|
|
626
|
+
description: entry.description,
|
|
627
|
+
details: entry.example ? [{ label: "example:", value: entry.example }] : []
|
|
784
628
|
}));
|
|
785
629
|
return `${group.title}: ${group.summary}
|
|
786
630
|
${formatRows(rows)}`;
|
|
@@ -789,9 +633,16 @@ ${formatRows(rows)}`;
|
|
|
789
633
|
function formatToolEntries() {
|
|
790
634
|
return formatRows(HELP_TOOL_ENTRIES.map((entry) => ({
|
|
791
635
|
label: entry.name,
|
|
792
|
-
description: entry.description
|
|
636
|
+
description: entry.description,
|
|
637
|
+
details: entry.cliEquivalent ? [{ label: "cli:", value: entry.cliEquivalent }] : [{ label: "scope:", value: "tool-only" }]
|
|
793
638
|
})));
|
|
794
639
|
}
|
|
640
|
+
function formatOnboardingEntries() {
|
|
641
|
+
return formatRows(HELP_ONBOARDING_ENTRIES);
|
|
642
|
+
}
|
|
643
|
+
function formatCapabilityEntries() {
|
|
644
|
+
return formatRows(HELP_CAPABILITY_ENTRIES);
|
|
645
|
+
}
|
|
795
646
|
function formatReferenceEntries() {
|
|
796
647
|
return formatRows(HELP_REFERENCE_ENTRIES.map((entry) => ({
|
|
797
648
|
label: entry.label,
|
|
@@ -809,13 +660,21 @@ function getHelpText() {
|
|
|
809
660
|
"Usage:",
|
|
810
661
|
" npx opendevbrowser <command> [options]",
|
|
811
662
|
"",
|
|
663
|
+
"Find It Fast:",
|
|
664
|
+
" Use these exact lookup terms when you need replay, desktop evidence, or browser-scoped computer use.",
|
|
665
|
+
formatCapabilityEntries(),
|
|
666
|
+
"",
|
|
667
|
+
`${onboarding_metadata_default.sectionTitle}:`,
|
|
668
|
+
` ${onboarding_metadata_default.sectionSummary}`,
|
|
669
|
+
formatOnboardingEntries(),
|
|
670
|
+
"",
|
|
812
671
|
`Command Inventory (all ${CLI_COMMANDS.length} commands):`,
|
|
813
672
|
formatCommandGroups(commandDescriptions),
|
|
814
673
|
"",
|
|
815
674
|
"Flag Inventory (all supported flags):",
|
|
816
675
|
formatFlagGroups(),
|
|
817
676
|
"",
|
|
818
|
-
`Tool Inventory (all ${
|
|
677
|
+
`Tool Inventory (all ${TOOL_COUNT} opendevbrowser_* tools):`,
|
|
819
678
|
formatToolEntries(),
|
|
820
679
|
"",
|
|
821
680
|
"Reference Pointers:",
|
|
@@ -1079,52 +938,15 @@ function installLocal(withConfig = false) {
|
|
|
1079
938
|
}
|
|
1080
939
|
|
|
1081
940
|
// src/cli/installers/skills.ts
|
|
1082
|
-
import * as
|
|
941
|
+
import * as crypto from "crypto";
|
|
942
|
+
import * as fs5 from "fs";
|
|
1083
943
|
import * as path4 from "path";
|
|
1084
944
|
|
|
1085
945
|
// src/cli/utils/skills.ts
|
|
1086
|
-
import * as fs5 from "fs";
|
|
1087
946
|
import * as path3 from "path";
|
|
1088
947
|
import * as os3 from "os";
|
|
1089
|
-
import { fileURLToPath } from "url";
|
|
1090
|
-
var PACKAGE_NAME = "opendevbrowser";
|
|
1091
948
|
var SKILL_DIR_NAME = "skill";
|
|
1092
949
|
var SKILLS_DIR_NAME = "skills";
|
|
1093
|
-
var cachedPackageRoot = null;
|
|
1094
|
-
function findPackageRoot(startDir) {
|
|
1095
|
-
let current = startDir;
|
|
1096
|
-
while (true) {
|
|
1097
|
-
const pkgPath = path3.join(current, "package.json");
|
|
1098
|
-
if (fs5.existsSync(pkgPath)) {
|
|
1099
|
-
try {
|
|
1100
|
-
const parsed = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
|
|
1101
|
-
if (parsed.name === PACKAGE_NAME) {
|
|
1102
|
-
return current;
|
|
1103
|
-
}
|
|
1104
|
-
} catch {
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
const parent = path3.dirname(current);
|
|
1108
|
-
if (parent === current) {
|
|
1109
|
-
break;
|
|
1110
|
-
}
|
|
1111
|
-
current = parent;
|
|
1112
|
-
}
|
|
1113
|
-
throw new Error("Unable to locate opendevbrowser package root for skill installation.");
|
|
1114
|
-
}
|
|
1115
|
-
function getPackageRoot() {
|
|
1116
|
-
if (cachedPackageRoot) return cachedPackageRoot;
|
|
1117
|
-
const moduleDir = path3.dirname(fileURLToPath(import.meta.url));
|
|
1118
|
-
cachedPackageRoot = findPackageRoot(moduleDir);
|
|
1119
|
-
return cachedPackageRoot;
|
|
1120
|
-
}
|
|
1121
|
-
function getBundledSkillsDir() {
|
|
1122
|
-
const skillsDir = path3.join(getPackageRoot(), "skills");
|
|
1123
|
-
if (!fs5.existsSync(skillsDir)) {
|
|
1124
|
-
throw new Error(`Bundled skills directory not found at ${skillsDir}`);
|
|
1125
|
-
}
|
|
1126
|
-
return skillsDir;
|
|
1127
|
-
}
|
|
1128
950
|
function getGlobalSkillDir() {
|
|
1129
951
|
const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os3.homedir(), ".config", "opencode");
|
|
1130
952
|
return path3.join(configDir, SKILL_DIR_NAME);
|
|
@@ -1182,34 +1004,207 @@ function getLocalSkillTargets() {
|
|
|
1182
1004
|
}
|
|
1183
1005
|
|
|
1184
1006
|
// src/cli/installers/skills.ts
|
|
1185
|
-
|
|
1186
|
-
|
|
1007
|
+
var LEGACY_ALIAS_DIRS = [
|
|
1008
|
+
{ name: "research", canonical: "opendevbrowser-research" },
|
|
1009
|
+
{ name: "shopping", canonical: "opendevbrowser-shopping" }
|
|
1010
|
+
];
|
|
1011
|
+
function getTargets(mode) {
|
|
1012
|
+
return mode === "global" ? getGlobalSkillTargets() : getLocalSkillTargets();
|
|
1013
|
+
}
|
|
1014
|
+
function getCanonicalBundledSkillNames() {
|
|
1015
|
+
return listBundledSkillDirectories().map((entry) => entry.name);
|
|
1016
|
+
}
|
|
1017
|
+
function hasCanonicalBundledSkillInTarget(targetDir, packNames) {
|
|
1018
|
+
return packNames.some((packName) => fs5.existsSync(path4.join(targetDir, packName)));
|
|
1019
|
+
}
|
|
1020
|
+
function formatSummary(parts, totalTargets, failures) {
|
|
1021
|
+
const summary = parts.length > 0 ? parts.join(", ") : "no lifecycle changes";
|
|
1022
|
+
const failureSummary = failures > 0 ? `, ${failures} failed` : "";
|
|
1023
|
+
return `${summary} across ${totalTargets} targets${failureSummary}`;
|
|
1024
|
+
}
|
|
1025
|
+
function hashDirectoryTree(dirPath) {
|
|
1026
|
+
const hash = crypto.createHash("sha256");
|
|
1027
|
+
const visit = (currentPath, relativePath) => {
|
|
1028
|
+
const entries = fs5.readdirSync(currentPath, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
1029
|
+
for (const entry of entries) {
|
|
1030
|
+
const absolutePath = path4.join(currentPath, entry.name);
|
|
1031
|
+
const entryRelativePath = relativePath ? path4.posix.join(relativePath, entry.name) : entry.name;
|
|
1032
|
+
if (entry.isDirectory()) {
|
|
1033
|
+
hash.update(`D:${entryRelativePath}\0`);
|
|
1034
|
+
visit(absolutePath, entryRelativePath);
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
if (entry.isFile()) {
|
|
1038
|
+
hash.update(`F:${entryRelativePath}\0`);
|
|
1039
|
+
hash.update(fs5.readFileSync(absolutePath));
|
|
1040
|
+
hash.update("\0");
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
if (entry.isSymbolicLink()) {
|
|
1044
|
+
hash.update(`L:${entryRelativePath}\0${fs5.readlinkSync(absolutePath)}\0`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
visit(dirPath, "");
|
|
1049
|
+
return hash.digest("hex");
|
|
1050
|
+
}
|
|
1051
|
+
function syncSkillDirectory(sourcePath, targetPath, sourceFingerprint) {
|
|
1052
|
+
if (!fs5.existsSync(targetPath)) {
|
|
1053
|
+
fs5.cpSync(sourcePath, targetPath, { recursive: true });
|
|
1054
|
+
return "installed";
|
|
1055
|
+
}
|
|
1056
|
+
const targetFingerprint = hashDirectoryTree(targetPath);
|
|
1057
|
+
if (targetFingerprint === sourceFingerprint) {
|
|
1058
|
+
return "unchanged";
|
|
1059
|
+
}
|
|
1060
|
+
const parentDir = path4.dirname(targetPath);
|
|
1061
|
+
const targetName = path4.basename(targetPath);
|
|
1062
|
+
const stagingRoot = fs5.mkdtempSync(path4.join(parentDir, `.${targetName}-sync-`));
|
|
1063
|
+
const stagedPath = path4.join(stagingRoot, targetName);
|
|
1064
|
+
const backupPath = path4.join(stagingRoot, `${targetName}-backup`);
|
|
1065
|
+
try {
|
|
1066
|
+
fs5.cpSync(sourcePath, stagedPath, { recursive: true });
|
|
1067
|
+
fs5.renameSync(targetPath, backupPath);
|
|
1068
|
+
try {
|
|
1069
|
+
fs5.renameSync(stagedPath, targetPath);
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
if (fs5.existsSync(backupPath) && !fs5.existsSync(targetPath)) {
|
|
1072
|
+
fs5.renameSync(backupPath, targetPath);
|
|
1073
|
+
}
|
|
1074
|
+
throw error;
|
|
1075
|
+
}
|
|
1076
|
+
fs5.rmSync(backupPath, { recursive: true, force: true });
|
|
1077
|
+
return "refreshed";
|
|
1078
|
+
} finally {
|
|
1079
|
+
if (fs5.existsSync(stagedPath)) {
|
|
1080
|
+
fs5.rmSync(stagedPath, { recursive: true, force: true });
|
|
1081
|
+
}
|
|
1082
|
+
if (fs5.existsSync(backupPath)) {
|
|
1083
|
+
fs5.rmSync(backupPath, { recursive: true, force: true });
|
|
1084
|
+
}
|
|
1085
|
+
fs5.rmSync(stagingRoot, { recursive: true, force: true });
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
function cleanupLegacyAlias(targetDir, aliasName) {
|
|
1089
|
+
const aliasPath = path4.join(targetDir, aliasName);
|
|
1090
|
+
if (!fs5.existsSync(aliasPath)) {
|
|
1091
|
+
return { removed: [], preserved: [] };
|
|
1092
|
+
}
|
|
1093
|
+
let stats;
|
|
1094
|
+
try {
|
|
1095
|
+
stats = fs5.statSync(aliasPath);
|
|
1096
|
+
} catch {
|
|
1097
|
+
return {
|
|
1098
|
+
removed: [],
|
|
1099
|
+
preserved: [{ targetDir, name: aliasName, reason: "unknown_layout" }]
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
if (!stats.isDirectory()) {
|
|
1103
|
+
return {
|
|
1104
|
+
removed: [],
|
|
1105
|
+
preserved: [{ targetDir, name: aliasName, reason: "unknown_layout" }]
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
if (fs5.existsSync(path4.join(aliasPath, "SKILL.md"))) {
|
|
1109
|
+
return {
|
|
1110
|
+
removed: [],
|
|
1111
|
+
preserved: [{ targetDir, name: aliasName, reason: "contains_skill_md" }]
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
const entries = fs5.readdirSync(aliasPath);
|
|
1115
|
+
if (entries.length === 0) {
|
|
1116
|
+
fs5.rmSync(aliasPath, { recursive: true, force: true });
|
|
1117
|
+
return { removed: [aliasName], preserved: [] };
|
|
1118
|
+
}
|
|
1119
|
+
return {
|
|
1120
|
+
removed: [],
|
|
1121
|
+
preserved: [{ targetDir, name: aliasName, reason: "non_empty" }]
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
function cleanupLegacyAliases(targetDir) {
|
|
1125
|
+
const removed = [];
|
|
1126
|
+
const preserved = [];
|
|
1127
|
+
for (const alias of LEGACY_ALIAS_DIRS) {
|
|
1128
|
+
const result = cleanupLegacyAlias(targetDir, alias.name);
|
|
1129
|
+
removed.push(...result.removed);
|
|
1130
|
+
preserved.push(...result.preserved);
|
|
1131
|
+
}
|
|
1132
|
+
return { removed, preserved };
|
|
1133
|
+
}
|
|
1134
|
+
function buildSyncMessage(mode, result) {
|
|
1135
|
+
return `Skills ${mode} sync: ${formatSummary(
|
|
1136
|
+
[
|
|
1137
|
+
result.installed.length > 0 ? `${result.installed.length} installed` : "",
|
|
1138
|
+
result.refreshed.length > 0 ? `${result.refreshed.length} refreshed` : "",
|
|
1139
|
+
result.unchanged.length > 0 ? `${result.unchanged.length} unchanged` : "",
|
|
1140
|
+
result.removedLegacyAliases.length > 0 ? `${result.removedLegacyAliases.length} legacy aliases removed` : "",
|
|
1141
|
+
result.preservedLegacyAliases.length > 0 ? `${result.preservedLegacyAliases.length} legacy aliases preserved` : ""
|
|
1142
|
+
].filter(Boolean),
|
|
1143
|
+
result.targets.length,
|
|
1144
|
+
result.targets.filter((entry) => !entry.success).length
|
|
1145
|
+
)}`;
|
|
1146
|
+
}
|
|
1147
|
+
function buildRemovalMessage(mode, result) {
|
|
1148
|
+
return `Skills ${mode} removal: ${formatSummary(
|
|
1149
|
+
[
|
|
1150
|
+
result.removed.length > 0 ? `${result.removed.length} removed` : "",
|
|
1151
|
+
result.missing.length > 0 ? `${result.missing.length} already absent` : "",
|
|
1152
|
+
result.removedLegacyAliases.length > 0 ? `${result.removedLegacyAliases.length} legacy aliases removed` : "",
|
|
1153
|
+
result.preservedLegacyAliases.length > 0 ? `${result.preservedLegacyAliases.length} legacy aliases preserved` : ""
|
|
1154
|
+
].filter(Boolean),
|
|
1155
|
+
result.targets.length,
|
|
1156
|
+
result.targets.filter((entry) => !entry.success).length
|
|
1157
|
+
)}`;
|
|
1158
|
+
}
|
|
1159
|
+
function syncBundledSkills(mode) {
|
|
1160
|
+
const targets = getTargets(mode);
|
|
1187
1161
|
const targetResults = [];
|
|
1188
1162
|
try {
|
|
1189
1163
|
const sourceDir = getBundledSkillsDir();
|
|
1190
|
-
const
|
|
1164
|
+
const packNames = getCanonicalBundledSkillNames();
|
|
1165
|
+
const bundledFingerprints = /* @__PURE__ */ new Map();
|
|
1166
|
+
for (const packName of packNames) {
|
|
1167
|
+
const sourcePath = path4.join(sourceDir, packName);
|
|
1168
|
+
if (!fs5.existsSync(sourcePath)) {
|
|
1169
|
+
throw new Error(`Bundled skill directory missing: ${packName}`);
|
|
1170
|
+
}
|
|
1171
|
+
bundledFingerprints.set(packName, hashDirectoryTree(sourcePath));
|
|
1172
|
+
}
|
|
1191
1173
|
for (const target of targets) {
|
|
1192
|
-
const
|
|
1193
|
-
const
|
|
1174
|
+
const installed = [];
|
|
1175
|
+
const refreshed = [];
|
|
1176
|
+
const unchanged = [];
|
|
1177
|
+
const removedLegacyAliases = [];
|
|
1178
|
+
const preservedLegacyAliases = [];
|
|
1194
1179
|
try {
|
|
1195
1180
|
ensureDir(target.dir);
|
|
1196
|
-
for (const
|
|
1197
|
-
|
|
1198
|
-
const
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1181
|
+
for (const packName of packNames) {
|
|
1182
|
+
const sourcePath = path4.join(sourceDir, packName);
|
|
1183
|
+
const targetPath = path4.join(target.dir, packName);
|
|
1184
|
+
const sourceFingerprint = bundledFingerprints.get(packName);
|
|
1185
|
+
if (!sourceFingerprint) {
|
|
1186
|
+
throw new Error(`Bundled fingerprint missing: ${packName}`);
|
|
1187
|
+
}
|
|
1188
|
+
const outcome = syncSkillDirectory(sourcePath, targetPath, sourceFingerprint);
|
|
1189
|
+
if (outcome === "installed") {
|
|
1190
|
+
installed.push(packName);
|
|
1191
|
+
} else if (outcome === "refreshed") {
|
|
1192
|
+
refreshed.push(packName);
|
|
1193
|
+
} else {
|
|
1194
|
+
unchanged.push(packName);
|
|
1204
1195
|
}
|
|
1205
|
-
fs6.cpSync(sourcePath, targetPath, { recursive: true });
|
|
1206
|
-
installed2.push(skillName);
|
|
1207
1196
|
}
|
|
1197
|
+
const legacyCleanup = cleanupLegacyAliases(target.dir);
|
|
1198
|
+
removedLegacyAliases.push(...legacyCleanup.removed);
|
|
1199
|
+
preservedLegacyAliases.push(...legacyCleanup.preserved);
|
|
1208
1200
|
targetResults.push({
|
|
1209
1201
|
agents: target.agents,
|
|
1210
1202
|
targetDir: target.dir,
|
|
1211
|
-
installed
|
|
1212
|
-
|
|
1203
|
+
installed,
|
|
1204
|
+
refreshed,
|
|
1205
|
+
unchanged,
|
|
1206
|
+
removedLegacyAliases,
|
|
1207
|
+
preservedLegacyAliases,
|
|
1213
1208
|
success: true
|
|
1214
1209
|
});
|
|
1215
1210
|
} catch (error) {
|
|
@@ -1217,41 +1212,112 @@ function installSkills(mode) {
|
|
|
1217
1212
|
targetResults.push({
|
|
1218
1213
|
agents: target.agents,
|
|
1219
1214
|
targetDir: target.dir,
|
|
1220
|
-
installed
|
|
1221
|
-
|
|
1215
|
+
installed,
|
|
1216
|
+
refreshed,
|
|
1217
|
+
unchanged,
|
|
1218
|
+
removedLegacyAliases,
|
|
1219
|
+
preservedLegacyAliases,
|
|
1222
1220
|
success: false,
|
|
1223
1221
|
error: message
|
|
1224
1222
|
});
|
|
1225
1223
|
}
|
|
1226
1224
|
}
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
|
|
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`;
|
|
1232
|
-
return {
|
|
1233
|
-
success: failures.length === 0,
|
|
1234
|
-
message: summary,
|
|
1225
|
+
const result = {
|
|
1226
|
+
success: targetResults.every((entry) => entry.success),
|
|
1227
|
+
message: "",
|
|
1235
1228
|
mode,
|
|
1236
1229
|
targets: targetResults,
|
|
1237
|
-
installed,
|
|
1238
|
-
|
|
1230
|
+
installed: targetResults.flatMap((entry) => entry.installed),
|
|
1231
|
+
refreshed: targetResults.flatMap((entry) => entry.refreshed),
|
|
1232
|
+
unchanged: targetResults.flatMap((entry) => entry.unchanged),
|
|
1233
|
+
removedLegacyAliases: targetResults.flatMap((entry) => entry.removedLegacyAliases),
|
|
1234
|
+
preservedLegacyAliases: targetResults.flatMap((entry) => entry.preservedLegacyAliases)
|
|
1239
1235
|
};
|
|
1236
|
+
result.message = buildSyncMessage(mode, result);
|
|
1237
|
+
return result;
|
|
1240
1238
|
} catch (error) {
|
|
1241
1239
|
const message = error instanceof Error ? error.message : String(error);
|
|
1242
|
-
|
|
1240
|
+
const result = {
|
|
1243
1241
|
success: false,
|
|
1244
|
-
message:
|
|
1242
|
+
message: "",
|
|
1245
1243
|
mode,
|
|
1246
1244
|
targets: targetResults,
|
|
1247
|
-
installed: targetResults.flatMap((
|
|
1248
|
-
|
|
1245
|
+
installed: targetResults.flatMap((entry) => entry.installed),
|
|
1246
|
+
refreshed: targetResults.flatMap((entry) => entry.refreshed),
|
|
1247
|
+
unchanged: targetResults.flatMap((entry) => entry.unchanged),
|
|
1248
|
+
removedLegacyAliases: targetResults.flatMap((entry) => entry.removedLegacyAliases),
|
|
1249
|
+
preservedLegacyAliases: targetResults.flatMap((entry) => entry.preservedLegacyAliases)
|
|
1249
1250
|
};
|
|
1251
|
+
result.message = `Failed to sync skills (${mode}): ${message}`;
|
|
1252
|
+
return result;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
function removeBundledSkills(mode) {
|
|
1256
|
+
const targets = getTargets(mode);
|
|
1257
|
+
const packNames = getCanonicalBundledSkillNames();
|
|
1258
|
+
const targetResults = [];
|
|
1259
|
+
for (const target of targets) {
|
|
1260
|
+
const removed = [];
|
|
1261
|
+
const missing = [];
|
|
1262
|
+
const removedLegacyAliases = [];
|
|
1263
|
+
const preservedLegacyAliases = [];
|
|
1264
|
+
try {
|
|
1265
|
+
for (const packName of packNames) {
|
|
1266
|
+
const targetPath = path4.join(target.dir, packName);
|
|
1267
|
+
if (fs5.existsSync(targetPath)) {
|
|
1268
|
+
fs5.rmSync(targetPath, { recursive: true, force: true });
|
|
1269
|
+
removed.push(packName);
|
|
1270
|
+
} else {
|
|
1271
|
+
missing.push(packName);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
const legacyCleanup = cleanupLegacyAliases(target.dir);
|
|
1275
|
+
removedLegacyAliases.push(...legacyCleanup.removed);
|
|
1276
|
+
preservedLegacyAliases.push(...legacyCleanup.preserved);
|
|
1277
|
+
targetResults.push({
|
|
1278
|
+
agents: target.agents,
|
|
1279
|
+
targetDir: target.dir,
|
|
1280
|
+
removed,
|
|
1281
|
+
missing,
|
|
1282
|
+
removedLegacyAliases,
|
|
1283
|
+
preservedLegacyAliases,
|
|
1284
|
+
success: true
|
|
1285
|
+
});
|
|
1286
|
+
} catch (error) {
|
|
1287
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1288
|
+
targetResults.push({
|
|
1289
|
+
agents: target.agents,
|
|
1290
|
+
targetDir: target.dir,
|
|
1291
|
+
removed,
|
|
1292
|
+
missing,
|
|
1293
|
+
removedLegacyAliases,
|
|
1294
|
+
preservedLegacyAliases,
|
|
1295
|
+
success: false,
|
|
1296
|
+
error: message
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1250
1299
|
}
|
|
1300
|
+
const result = {
|
|
1301
|
+
success: targetResults.every((entry) => entry.success),
|
|
1302
|
+
message: "",
|
|
1303
|
+
mode,
|
|
1304
|
+
targets: targetResults,
|
|
1305
|
+
removed: targetResults.flatMap((entry) => entry.removed),
|
|
1306
|
+
missing: targetResults.flatMap((entry) => entry.missing),
|
|
1307
|
+
removedLegacyAliases: targetResults.flatMap((entry) => entry.removedLegacyAliases),
|
|
1308
|
+
preservedLegacyAliases: targetResults.flatMap((entry) => entry.preservedLegacyAliases)
|
|
1309
|
+
};
|
|
1310
|
+
result.message = buildRemovalMessage(mode, result);
|
|
1311
|
+
return result;
|
|
1312
|
+
}
|
|
1313
|
+
function hasBundledSkillArtifacts(mode) {
|
|
1314
|
+
const packNames = getCanonicalBundledSkillNames();
|
|
1315
|
+
const targets = getTargets(mode);
|
|
1316
|
+
return targets.some((target) => hasCanonicalBundledSkillInTarget(target.dir, packNames));
|
|
1251
1317
|
}
|
|
1252
1318
|
|
|
1253
1319
|
// src/cli/commands/update.ts
|
|
1254
|
-
import * as
|
|
1320
|
+
import * as fs6 from "fs";
|
|
1255
1321
|
import * as path5 from "path";
|
|
1256
1322
|
import * as os4 from "os";
|
|
1257
1323
|
var PLUGIN_NAME2 = "opendevbrowser";
|
|
@@ -1265,8 +1331,8 @@ function rmdir(dirPath) {
|
|
|
1265
1331
|
if (!resolvedPath.startsWith(resolvedCache + path5.sep) || resolvedPath === resolvedCache) {
|
|
1266
1332
|
throw new Error(`Security: refusing to delete path outside cache directory: ${dirPath}`);
|
|
1267
1333
|
}
|
|
1268
|
-
if (
|
|
1269
|
-
|
|
1334
|
+
if (fs6.existsSync(dirPath)) {
|
|
1335
|
+
fs6.rmSync(dirPath, { recursive: true, force: true });
|
|
1270
1336
|
}
|
|
1271
1337
|
}
|
|
1272
1338
|
function runUpdate() {
|
|
@@ -1274,8 +1340,8 @@ function runUpdate() {
|
|
|
1274
1340
|
const nodeModulesDir = path5.join(cacheDir, "node_modules");
|
|
1275
1341
|
const pluginCacheDir = path5.join(nodeModulesDir, PLUGIN_NAME2);
|
|
1276
1342
|
try {
|
|
1277
|
-
if (!
|
|
1278
|
-
if (
|
|
1343
|
+
if (!fs6.existsSync(pluginCacheDir)) {
|
|
1344
|
+
if (fs6.existsSync(nodeModulesDir)) {
|
|
1279
1345
|
rmdir(nodeModulesDir);
|
|
1280
1346
|
return {
|
|
1281
1347
|
success: true,
|
|
@@ -1306,7 +1372,7 @@ function runUpdate() {
|
|
|
1306
1372
|
}
|
|
1307
1373
|
|
|
1308
1374
|
// src/cli/commands/uninstall.ts
|
|
1309
|
-
import * as
|
|
1375
|
+
import * as fs7 from "fs";
|
|
1310
1376
|
import * as path6 from "path";
|
|
1311
1377
|
import * as os5 from "os";
|
|
1312
1378
|
function getPluginConfigPath2(mode) {
|
|
@@ -1318,8 +1384,8 @@ function getPluginConfigPath2(mode) {
|
|
|
1318
1384
|
}
|
|
1319
1385
|
function removePluginConfigFile(mode) {
|
|
1320
1386
|
const configPath = getPluginConfigPath2(mode);
|
|
1321
|
-
if (
|
|
1322
|
-
|
|
1387
|
+
if (fs7.existsSync(configPath)) {
|
|
1388
|
+
fs7.unlinkSync(configPath);
|
|
1323
1389
|
return true;
|
|
1324
1390
|
}
|
|
1325
1391
|
return false;
|
|
@@ -1338,7 +1404,7 @@ function runUninstall(mode, deleteConfigFile = false) {
|
|
|
1338
1404
|
};
|
|
1339
1405
|
}
|
|
1340
1406
|
const newContent = removePluginFromContent(content, "opendevbrowser");
|
|
1341
|
-
|
|
1407
|
+
fs7.writeFileSync(configPath, newContent, "utf-8");
|
|
1342
1408
|
let configFileDeleted = false;
|
|
1343
1409
|
if (deleteConfigFile) {
|
|
1344
1410
|
configFileDeleted = removePluginConfigFile(mode);
|
|
@@ -1398,6 +1464,16 @@ function parseNumberFlag(value, flag, options = {}) {
|
|
|
1398
1464
|
}
|
|
1399
1465
|
return parsed;
|
|
1400
1466
|
}
|
|
1467
|
+
function parseBooleanFlag(value, flag) {
|
|
1468
|
+
const normalized = value.trim().toLowerCase();
|
|
1469
|
+
if (normalized === "true" || normalized === "1") {
|
|
1470
|
+
return true;
|
|
1471
|
+
}
|
|
1472
|
+
if (normalized === "false" || normalized === "0") {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
throw createUsageError(`Invalid ${flag}: ${value}`);
|
|
1476
|
+
}
|
|
1401
1477
|
function parseOptionalStringFlag(rawArgs, flag) {
|
|
1402
1478
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
1403
1479
|
const arg = rawArgs[i];
|
|
@@ -1418,13 +1494,23 @@ function parseOptionalStringFlag(rawArgs, flag) {
|
|
|
1418
1494
|
}
|
|
1419
1495
|
return void 0;
|
|
1420
1496
|
}
|
|
1497
|
+
function parseStringArrayFlag(rawArgs, flag) {
|
|
1498
|
+
const value = parseOptionalStringFlag(rawArgs, flag);
|
|
1499
|
+
if (typeof value !== "string") {
|
|
1500
|
+
return void 0;
|
|
1501
|
+
}
|
|
1502
|
+
const items = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
1503
|
+
if (items.length === 0) {
|
|
1504
|
+
throw createUsageError(`Missing value for ${flag}`);
|
|
1505
|
+
}
|
|
1506
|
+
return items;
|
|
1507
|
+
}
|
|
1421
1508
|
|
|
1422
1509
|
// src/cli/commands/native.ts
|
|
1423
|
-
import * as
|
|
1510
|
+
import * as fs8 from "fs";
|
|
1424
1511
|
import * as path7 from "path";
|
|
1425
|
-
import { homedir as homedir6 } from "os";
|
|
1426
1512
|
import { execFileSync } from "child_process";
|
|
1427
|
-
import { fileURLToPath
|
|
1513
|
+
import { fileURLToPath } from "url";
|
|
1428
1514
|
var EXTENSION_ID_RE = /^[a-p]{32}$/;
|
|
1429
1515
|
var EXTENSION_NAME = "OpenDevBrowser Relay";
|
|
1430
1516
|
var ANNOTATION_COMMAND_NAME = "toggle-annotation";
|
|
@@ -1472,7 +1558,7 @@ var getManifestDir = () => {
|
|
|
1472
1558
|
throw createUsageError(`Native messaging is not supported on ${process.platform}.`);
|
|
1473
1559
|
};
|
|
1474
1560
|
var getScriptsDir = () => {
|
|
1475
|
-
const __filename =
|
|
1561
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
1476
1562
|
const startDir = path7.dirname(__filename);
|
|
1477
1563
|
const rootsToScan = [startDir, process.cwd()];
|
|
1478
1564
|
for (const root of rootsToScan) {
|
|
@@ -1480,7 +1566,7 @@ var getScriptsDir = () => {
|
|
|
1480
1566
|
while (true) {
|
|
1481
1567
|
const scriptsDir = path7.join(current, "scripts", "native");
|
|
1482
1568
|
const packageJsonPath = path7.join(current, "package.json");
|
|
1483
|
-
if (
|
|
1569
|
+
if (fs8.existsSync(scriptsDir) && fs8.existsSync(packageJsonPath)) {
|
|
1484
1570
|
return scriptsDir;
|
|
1485
1571
|
}
|
|
1486
1572
|
const parent = path7.dirname(current);
|
|
@@ -1504,7 +1590,7 @@ var getWrapperPath = () => {
|
|
|
1504
1590
|
};
|
|
1505
1591
|
var readManifest = (manifestPath) => {
|
|
1506
1592
|
try {
|
|
1507
|
-
const raw =
|
|
1593
|
+
const raw = fs8.readFileSync(manifestPath, "utf8");
|
|
1508
1594
|
const data = JSON.parse(raw);
|
|
1509
1595
|
const origins = Array.isArray(data.allowed_origins) ? data.allowed_origins : [];
|
|
1510
1596
|
const match = origins.find((origin) => origin.startsWith("chrome-extension://"));
|
|
@@ -1541,57 +1627,11 @@ var readRegistryPath = () => {
|
|
|
1541
1627
|
};
|
|
1542
1628
|
var normalizePath = (value) => {
|
|
1543
1629
|
try {
|
|
1544
|
-
return
|
|
1630
|
+
return fs8.realpathSync(value);
|
|
1545
1631
|
} catch {
|
|
1546
1632
|
return path7.resolve(value);
|
|
1547
1633
|
}
|
|
1548
1634
|
};
|
|
1549
|
-
var getChromeUserDataRoots = () => {
|
|
1550
|
-
if (process.platform === "darwin") {
|
|
1551
|
-
return [
|
|
1552
|
-
path7.join(homedir6(), "Library", "Application Support", "Google", "Chrome"),
|
|
1553
|
-
path7.join(homedir6(), "Library", "Application Support", "Chromium"),
|
|
1554
|
-
path7.join(homedir6(), "Library", "Application Support", "BraveSoftware", "Brave-Browser")
|
|
1555
|
-
];
|
|
1556
|
-
}
|
|
1557
|
-
if (process.platform === "linux") {
|
|
1558
|
-
return [
|
|
1559
|
-
path7.join(homedir6(), ".config", "google-chrome"),
|
|
1560
|
-
path7.join(homedir6(), ".config", "chromium"),
|
|
1561
|
-
path7.join(homedir6(), ".config", "BraveSoftware", "Brave-Browser")
|
|
1562
|
-
];
|
|
1563
|
-
}
|
|
1564
|
-
if (process.platform === "win32") {
|
|
1565
|
-
const base = process.env.LOCALAPPDATA || (process.env.USERPROFILE ? path7.join(process.env.USERPROFILE, "AppData", "Local") : "");
|
|
1566
|
-
if (!base) return [];
|
|
1567
|
-
return [
|
|
1568
|
-
path7.join(base, "Google", "Chrome", "User Data"),
|
|
1569
|
-
path7.join(base, "Chromium", "User Data"),
|
|
1570
|
-
path7.join(base, "BraveSoftware", "Brave-Browser", "User Data")
|
|
1571
|
-
];
|
|
1572
|
-
}
|
|
1573
|
-
return [];
|
|
1574
|
-
};
|
|
1575
|
-
var PROFILE_PREFERENCES_FILES = ["Preferences", "Secure Preferences"];
|
|
1576
|
-
var getProfileDirs = (root) => {
|
|
1577
|
-
try {
|
|
1578
|
-
const entries = fs9.readdirSync(root, { withFileTypes: true });
|
|
1579
|
-
return entries.filter((entry) => entry.isDirectory() && (entry.name === "Default" || entry.name.startsWith("Profile "))).map((entry) => path7.join(root, entry.name)).filter((dir) => PROFILE_PREFERENCES_FILES.some((filename) => fs9.existsSync(path7.join(dir, filename))));
|
|
1580
|
-
} catch {
|
|
1581
|
-
return [];
|
|
1582
|
-
}
|
|
1583
|
-
};
|
|
1584
|
-
var readProfilePreferences = (profileDir) => {
|
|
1585
|
-
const records = [];
|
|
1586
|
-
for (const filename of PROFILE_PREFERENCES_FILES) {
|
|
1587
|
-
try {
|
|
1588
|
-
const raw = fs9.readFileSync(path7.join(profileDir, filename), "utf8");
|
|
1589
|
-
records.push(JSON.parse(raw));
|
|
1590
|
-
} catch {
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
return records;
|
|
1594
|
-
};
|
|
1595
1635
|
var findExtensionIdInCommands = (preferences) => {
|
|
1596
1636
|
const extensionCommands = preferences.extensions;
|
|
1597
1637
|
const commandMaps = [
|
|
@@ -1651,7 +1691,7 @@ var getExtensionPathCandidates = () => {
|
|
|
1651
1691
|
candidates.add(normalizePath(primary));
|
|
1652
1692
|
}
|
|
1653
1693
|
const cwdExtension = path7.join(process.cwd(), "extension");
|
|
1654
|
-
if (
|
|
1694
|
+
if (fs8.existsSync(path7.join(cwdExtension, "manifest.json"))) {
|
|
1655
1695
|
candidates.add(normalizePath(cwdExtension));
|
|
1656
1696
|
}
|
|
1657
1697
|
if (candidates.size === 0) {
|
|
@@ -1736,13 +1776,13 @@ var getNativeStatusSnapshot = () => {
|
|
|
1736
1776
|
let manifestExists = false;
|
|
1737
1777
|
let wrapperExists = false;
|
|
1738
1778
|
let extensionIdValue = null;
|
|
1739
|
-
if (
|
|
1779
|
+
if (fs8.existsSync(manifestPath)) {
|
|
1740
1780
|
manifestExists = true;
|
|
1741
1781
|
installed = true;
|
|
1742
1782
|
const manifest = readManifest(manifestPath);
|
|
1743
1783
|
extensionIdValue = manifest.extensionId;
|
|
1744
1784
|
}
|
|
1745
|
-
if (
|
|
1785
|
+
if (fs8.existsSync(wrapperPath)) {
|
|
1746
1786
|
wrapperExists = true;
|
|
1747
1787
|
}
|
|
1748
1788
|
if (!manifestExists || !wrapperExists) {
|
|
@@ -1768,6 +1808,30 @@ var getNativeStatusSnapshot = () => {
|
|
|
1768
1808
|
mismatch
|
|
1769
1809
|
};
|
|
1770
1810
|
};
|
|
1811
|
+
function assessNativeStatus(data) {
|
|
1812
|
+
if (!data.installed) {
|
|
1813
|
+
return {
|
|
1814
|
+
success: false,
|
|
1815
|
+
message: "Native host not installed.",
|
|
1816
|
+
summary: "not installed",
|
|
1817
|
+
exitCode: EXIT_DISCONNECTED
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
if (data.mismatch && data.extensionId && data.expectedExtensionId) {
|
|
1821
|
+
return {
|
|
1822
|
+
success: false,
|
|
1823
|
+
message: `Native host targets ${data.extensionId}, but the current extension is ${data.expectedExtensionId}. Reinstall with \`opendevbrowser native install ${data.expectedExtensionId}\` or rerun \`opendevbrowser serve\`.`,
|
|
1824
|
+
summary: `mismatch (${data.extensionId} != ${data.expectedExtensionId})`,
|
|
1825
|
+
exitCode: EXIT_DISCONNECTED
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
return {
|
|
1829
|
+
success: true,
|
|
1830
|
+
message: data.extensionId ? `Native host installed for extension ${data.extensionId}.` : "Native host installed (extension id missing).",
|
|
1831
|
+
summary: `installed${data.extensionId ? ` (${data.extensionId})` : ""}`,
|
|
1832
|
+
exitCode: null
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1771
1835
|
function installNativeHost(extensionId) {
|
|
1772
1836
|
const normalized = normalizeExtensionId(extensionId);
|
|
1773
1837
|
if (!normalized) {
|
|
@@ -1778,7 +1842,7 @@ function installNativeHost(extensionId) {
|
|
|
1778
1842
|
};
|
|
1779
1843
|
}
|
|
1780
1844
|
const hostScript = getHostScriptPath();
|
|
1781
|
-
if (!
|
|
1845
|
+
if (!fs8.existsSync(hostScript)) {
|
|
1782
1846
|
return {
|
|
1783
1847
|
success: false,
|
|
1784
1848
|
message: `Native host not found at ${hostScript}.`,
|
|
@@ -1816,34 +1880,27 @@ async function runNativeCommand(args) {
|
|
|
1816
1880
|
runScript(uninstallScript, []);
|
|
1817
1881
|
return { success: true, message: "Native host uninstalled." };
|
|
1818
1882
|
} catch (error) {
|
|
1819
|
-
const
|
|
1820
|
-
return { success: false, message: `Native uninstall failed: ${
|
|
1883
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1884
|
+
return { success: false, message: `Native uninstall failed: ${message}`, exitCode: EXIT_EXECUTION };
|
|
1821
1885
|
}
|
|
1822
1886
|
}
|
|
1823
1887
|
const data = getNativeStatusSnapshot();
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
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
|
-
}
|
|
1840
|
-
const message = data.extensionId ? `Native host installed for extension ${data.extensionId}.` : "Native host installed (extension id missing).";
|
|
1841
|
-
return { success: true, message, data };
|
|
1888
|
+
const assessment = assessNativeStatus(data);
|
|
1889
|
+
return {
|
|
1890
|
+
success: assessment.success,
|
|
1891
|
+
message: assessment.message,
|
|
1892
|
+
data,
|
|
1893
|
+
exitCode: assessment.exitCode
|
|
1894
|
+
};
|
|
1842
1895
|
}
|
|
1843
1896
|
|
|
1844
1897
|
// src/cli/commands/serve.ts
|
|
1845
1898
|
var daemonHandle = null;
|
|
1846
1899
|
var PS_MAX_BUFFER = 8 * 1024 * 1024;
|
|
1900
|
+
var SERVE_COMMAND_PATTERN = /(?:^|\s)(?:\S*[\\/])?(?:opendevbrowser|dist[\\/]+cli[\\/]+index\.js)(?=\s|$).*?\bserve\b/;
|
|
1901
|
+
var SERVE_STOP_PATTERN = /(?:^|\s)--stop(?:\s|$)/;
|
|
1902
|
+
var CURRENT_UID = typeof process.getuid === "function" ? process.getuid() : null;
|
|
1903
|
+
var CURRENT_EXECUTABLE = process.execPath;
|
|
1847
1904
|
function resolveTokenCandidates(requestedToken, metadataToken, configToken) {
|
|
1848
1905
|
return Array.from(new Set([requestedToken, metadataToken, configToken].filter((token) => typeof token === "string" && token.trim().length > 0)));
|
|
1849
1906
|
}
|
|
@@ -1901,32 +1958,52 @@ function parseServeArgs(rawArgs) {
|
|
|
1901
1958
|
}
|
|
1902
1959
|
return parsed;
|
|
1903
1960
|
}
|
|
1904
|
-
function
|
|
1905
|
-
const
|
|
1961
|
+
function parseServeProcessSnapshot(line) {
|
|
1962
|
+
const trimmed = line.trim();
|
|
1963
|
+
if (trimmed.length === 0) {
|
|
1964
|
+
return null;
|
|
1965
|
+
}
|
|
1966
|
+
const match = trimmed.match(/^(\d+)(?:\s+(\d+))?\s+(.*)$/);
|
|
1967
|
+
if (!match) {
|
|
1968
|
+
return null;
|
|
1969
|
+
}
|
|
1970
|
+
const pid = Number.parseInt(match[1] ?? "", 10);
|
|
1971
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
1972
|
+
return null;
|
|
1973
|
+
}
|
|
1974
|
+
const rawUid = match[2];
|
|
1975
|
+
const parsedUid = typeof rawUid === "string" && rawUid.length > 0 ? Number.parseInt(rawUid, 10) : null;
|
|
1976
|
+
const command = (match[3] ?? "").trim();
|
|
1977
|
+
if (command.length === 0) {
|
|
1978
|
+
return null;
|
|
1979
|
+
}
|
|
1980
|
+
return {
|
|
1981
|
+
pid,
|
|
1982
|
+
uid: typeof parsedUid === "number" && Number.isInteger(parsedUid) && parsedUid >= 0 ? parsedUid : null,
|
|
1983
|
+
command
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
function listServeProcessSnapshots() {
|
|
1987
|
+
const result = spawnSync("ps", ["-axww", "-o", "pid=,uid=,command="], {
|
|
1906
1988
|
encoding: "utf-8",
|
|
1907
1989
|
maxBuffer: PS_MAX_BUFFER
|
|
1908
1990
|
});
|
|
1909
1991
|
if ((result.status ?? 1) !== 0) {
|
|
1910
1992
|
return [];
|
|
1911
1993
|
}
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
if (pid === process.pid || pid === process.ppid) continue;
|
|
1926
|
-
if (!servePattern.test(command)) continue;
|
|
1927
|
-
pids.add(pid);
|
|
1928
|
-
}
|
|
1929
|
-
return [...pids];
|
|
1994
|
+
return String(result.stdout ?? "").split("\n").map((line) => parseServeProcessSnapshot(line)).filter((snapshot) => snapshot !== null);
|
|
1995
|
+
}
|
|
1996
|
+
function isCurrentExecutableServeProcess(snapshot) {
|
|
1997
|
+
if (CURRENT_UID === null || snapshot.uid === null || snapshot.uid !== CURRENT_UID) {
|
|
1998
|
+
return false;
|
|
1999
|
+
}
|
|
2000
|
+
if (!snapshot.command.includes(CURRENT_EXECUTABLE)) {
|
|
2001
|
+
return false;
|
|
2002
|
+
}
|
|
2003
|
+
if (!SERVE_COMMAND_PATTERN.test(snapshot.command)) {
|
|
2004
|
+
return false;
|
|
2005
|
+
}
|
|
2006
|
+
return !SERVE_STOP_PATTERN.test(snapshot.command);
|
|
1930
2007
|
}
|
|
1931
2008
|
function terminateProcess(pid) {
|
|
1932
2009
|
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid || pid === process.ppid) {
|
|
@@ -1943,16 +2020,29 @@ function terminateProcess(pid) {
|
|
|
1943
2020
|
}
|
|
1944
2021
|
return true;
|
|
1945
2022
|
}
|
|
1946
|
-
function
|
|
1947
|
-
const candidates =
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
if (
|
|
1952
|
-
|
|
2023
|
+
function cleanupCompetingServeProcesses(keepPid) {
|
|
2024
|
+
const candidates = listServeProcessSnapshots().filter((snapshot) => {
|
|
2025
|
+
if (!isCurrentExecutableServeProcess(snapshot)) {
|
|
2026
|
+
return false;
|
|
2027
|
+
}
|
|
2028
|
+
if (snapshot.pid === process.pid || snapshot.pid === process.ppid) {
|
|
2029
|
+
return false;
|
|
1953
2030
|
}
|
|
2031
|
+
if (Number.isInteger(keepPid) && snapshot.pid === keepPid) {
|
|
2032
|
+
return false;
|
|
2033
|
+
}
|
|
2034
|
+
return true;
|
|
2035
|
+
});
|
|
2036
|
+
if (candidates.length === 0) {
|
|
2037
|
+
return [];
|
|
1954
2038
|
}
|
|
1955
|
-
|
|
2039
|
+
const clearedPids = [];
|
|
2040
|
+
for (const snapshot of candidates) {
|
|
2041
|
+
if (terminateProcess(snapshot.pid)) {
|
|
2042
|
+
clearedPids.push(snapshot.pid);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
return clearedPids;
|
|
1956
2046
|
}
|
|
1957
2047
|
async function runServe(args) {
|
|
1958
2048
|
const serveArgs = parseServeArgs(args.rawArgs);
|
|
@@ -1986,10 +2076,13 @@ async function runServe(args) {
|
|
|
1986
2076
|
const metadataToken = metadata?.port === requestedPort ? metadata.token : void 0;
|
|
1987
2077
|
const tokenCandidates = resolveTokenCandidates(serveArgs.token, metadataToken, config.daemonToken);
|
|
1988
2078
|
const existingDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
|
|
1989
|
-
const
|
|
2079
|
+
const staleDaemonPids = new Set(cleanupCompetingServeProcesses(existingDaemon?.status.pid));
|
|
2080
|
+
const staleCleared = () => staleDaemonPids.size;
|
|
1990
2081
|
if (existingDaemon) {
|
|
1991
2082
|
const relayPort = existingDaemon.status.relay.port ?? config.relayPort;
|
|
1992
|
-
const
|
|
2083
|
+
const clearedCount2 = staleCleared();
|
|
2084
|
+
const staleNote2 = clearedCount2 > 0 ? `
|
|
2085
|
+
Cleared ${clearedCount2} stale daemon process${clearedCount2 === 1 ? "" : "es"}.` : "";
|
|
1993
2086
|
return {
|
|
1994
2087
|
success: true,
|
|
1995
2088
|
message: `Daemon already running on 127.0.0.1:${requestedPort} (pid=${existingDaemon.status.pid}, relay ${relayPort}).${staleNote2}`,
|
|
@@ -1998,7 +2091,7 @@ async function runServe(args) {
|
|
|
1998
2091
|
pid: existingDaemon.status.pid,
|
|
1999
2092
|
relayPort,
|
|
2000
2093
|
alreadyRunning: true,
|
|
2001
|
-
staleDaemonsCleared:
|
|
2094
|
+
staleDaemonsCleared: clearedCount2,
|
|
2002
2095
|
relay: existingDaemon.status.relay
|
|
2003
2096
|
},
|
|
2004
2097
|
exitCode: null
|
|
@@ -2026,32 +2119,62 @@ async function runServe(args) {
|
|
|
2026
2119
|
nativeMessage = "Native host not installed. Set nativeExtensionId in opendevbrowser.jsonc to auto-install.";
|
|
2027
2120
|
}
|
|
2028
2121
|
}
|
|
2029
|
-
let handle;
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2122
|
+
let handle = null;
|
|
2123
|
+
let startError = null;
|
|
2124
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
2125
|
+
try {
|
|
2126
|
+
handle = await startDaemon({
|
|
2127
|
+
port: serveArgs.port,
|
|
2128
|
+
token: serveArgs.token,
|
|
2129
|
+
config
|
|
2130
|
+
});
|
|
2131
|
+
startError = null;
|
|
2132
|
+
break;
|
|
2133
|
+
} catch (error) {
|
|
2134
|
+
startError = error;
|
|
2135
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
2136
|
+
if (!message2.includes("EADDRINUSE") && !message2.includes("in use")) {
|
|
2137
|
+
break;
|
|
2138
|
+
}
|
|
2039
2139
|
const runningDaemon = await resolveExistingDaemon(requestedPort, tokenCandidates);
|
|
2040
2140
|
if (runningDaemon) {
|
|
2041
2141
|
const relayPort = runningDaemon.status.relay.port ?? config.relayPort;
|
|
2142
|
+
const clearedCount2 = staleCleared();
|
|
2143
|
+
const staleNote2 = clearedCount2 > 0 ? `
|
|
2144
|
+
Cleared ${clearedCount2} stale daemon process${clearedCount2 === 1 ? "" : "es"}.` : "";
|
|
2042
2145
|
return {
|
|
2043
2146
|
success: true,
|
|
2044
|
-
message: `Daemon already running on 127.0.0.1:${requestedPort} (pid=${runningDaemon.status.pid}, relay ${relayPort})
|
|
2147
|
+
message: `Daemon already running on 127.0.0.1:${requestedPort} (pid=${runningDaemon.status.pid}, relay ${relayPort}).${staleNote2}`,
|
|
2045
2148
|
data: {
|
|
2046
2149
|
port: requestedPort,
|
|
2047
2150
|
pid: runningDaemon.status.pid,
|
|
2048
2151
|
relayPort,
|
|
2049
2152
|
alreadyRunning: true,
|
|
2153
|
+
staleDaemonsCleared: clearedCount2,
|
|
2050
2154
|
relay: runningDaemon.status.relay
|
|
2051
2155
|
},
|
|
2052
2156
|
exitCode: null
|
|
2053
2157
|
};
|
|
2054
2158
|
}
|
|
2159
|
+
if (attempt === 0) {
|
|
2160
|
+
let clearedNewPid = false;
|
|
2161
|
+
for (const pid of cleanupCompetingServeProcesses()) {
|
|
2162
|
+
const previousSize = staleDaemonPids.size;
|
|
2163
|
+
staleDaemonPids.add(pid);
|
|
2164
|
+
if (staleDaemonPids.size > previousSize) {
|
|
2165
|
+
clearedNewPid = true;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
if (clearedNewPid) {
|
|
2169
|
+
continue;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
break;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
if (!handle) {
|
|
2176
|
+
const message2 = startError instanceof Error ? startError.message : String(startError);
|
|
2177
|
+
if (message2.includes("EADDRINUSE") || message2.includes("in use")) {
|
|
2055
2178
|
return {
|
|
2056
2179
|
success: false,
|
|
2057
2180
|
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\`.`,
|
|
@@ -2067,54 +2190,93 @@ async function runServe(args) {
|
|
|
2067
2190
|
daemonHandle = handle;
|
|
2068
2191
|
const { state } = handle;
|
|
2069
2192
|
const baseMessage = `Daemon running on 127.0.0.1:${state.port} (relay ${state.relayPort})`;
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2193
|
+
const clearedCount = staleCleared();
|
|
2194
|
+
const staleNote = clearedCount > 0 ? `
|
|
2195
|
+
Cleared ${clearedCount} stale daemon process${clearedCount === 1 ? "" : "es"}.` : "";
|
|
2072
2196
|
const message = nativeMessage ? `${baseMessage}
|
|
2073
2197
|
${nativeMessage}${staleNote}` : `${baseMessage}${staleNote}`;
|
|
2074
2198
|
return {
|
|
2075
2199
|
success: true,
|
|
2076
2200
|
message,
|
|
2077
|
-
data: { port: state.port, pid: state.pid, relayPort: state.relayPort, native: nativeStatus, staleDaemonsCleared:
|
|
2201
|
+
data: { port: state.port, pid: state.pid, relayPort: state.relayPort, native: nativeStatus, staleDaemonsCleared: clearedCount },
|
|
2078
2202
|
exitCode: null
|
|
2079
2203
|
};
|
|
2080
2204
|
}
|
|
2081
2205
|
|
|
2082
2206
|
// src/cli/daemon-autostart.ts
|
|
2083
2207
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
2084
|
-
import { existsSync as
|
|
2085
|
-
import { homedir as
|
|
2086
|
-
import { dirname as dirname5, join as join8, resolve as resolve4 } from "path";
|
|
2087
|
-
import { fileURLToPath as
|
|
2208
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
2209
|
+
import { homedir as homedir6, tmpdir } from "os";
|
|
2210
|
+
import { dirname as dirname5, isAbsolute, join as join8, relative, resolve as resolve4 } from "path";
|
|
2211
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2088
2212
|
var MAC_LABEL = "com.opendevbrowser.daemon";
|
|
2089
2213
|
var WIN_TASK_NAME = "OpenDevBrowser Daemon";
|
|
2214
|
+
var STABLE_DAEMON_INSTALL_GUIDANCE = "Run opendevbrowser daemon install from a stable install location (for example, a global npm install or a persistent local package install).";
|
|
2090
2215
|
var defaultDeps = () => ({
|
|
2091
2216
|
platform: process.platform,
|
|
2092
2217
|
argv1: process.argv[1] ?? "",
|
|
2093
2218
|
moduleUrl: import.meta.url,
|
|
2094
2219
|
uid: typeof process.getuid === "function" ? process.getuid() : 0,
|
|
2095
|
-
homedir:
|
|
2096
|
-
existsSync:
|
|
2220
|
+
homedir: homedir6,
|
|
2221
|
+
existsSync: existsSync7,
|
|
2097
2222
|
mkdirSync: mkdirSync3,
|
|
2098
2223
|
writeFileSync: writeFileSync4,
|
|
2099
2224
|
unlinkSync: unlinkSync2,
|
|
2100
|
-
execFileSync: execFileSync2
|
|
2225
|
+
execFileSync: execFileSync2,
|
|
2226
|
+
transientEntrypointRoots: void 0
|
|
2101
2227
|
});
|
|
2228
|
+
var NPX_CACHE_SEGMENT_PATTERN = /[\\/]_npx(?:[\\/]|$)/;
|
|
2229
|
+
var formatCommand = (programArguments) => {
|
|
2230
|
+
return programArguments.map((value) => `"${value}"`).join(" ");
|
|
2231
|
+
};
|
|
2102
2232
|
var resolveCliPathFromModule = (moduleUrl, exists) => {
|
|
2103
|
-
const modulePath =
|
|
2233
|
+
const modulePath = fileURLToPath2(moduleUrl);
|
|
2104
2234
|
const candidate = resolve4(dirname5(modulePath), "..", "index.js");
|
|
2105
2235
|
if (!exists(candidate)) {
|
|
2106
2236
|
throw new Error(`CLI entrypoint not found at ${candidate}`);
|
|
2107
2237
|
}
|
|
2108
2238
|
return candidate;
|
|
2109
2239
|
};
|
|
2240
|
+
var normalizeComparisonPath = (value, platform) => {
|
|
2241
|
+
const resolvedPath = resolve4(value);
|
|
2242
|
+
return platform === "win32" ? resolvedPath.toLowerCase() : resolvedPath;
|
|
2243
|
+
};
|
|
2244
|
+
var isPathInsideRoot = (candidate, root, platform) => {
|
|
2245
|
+
const normalizedCandidate = normalizeComparisonPath(candidate, platform);
|
|
2246
|
+
const normalizedRoot = normalizeComparisonPath(root, platform);
|
|
2247
|
+
const relation = relative(normalizedRoot, normalizedCandidate);
|
|
2248
|
+
return relation === "" || !relation.startsWith("..") && !isAbsolute(relation);
|
|
2249
|
+
};
|
|
2250
|
+
var getTransientEntrypointRoots = (deps) => {
|
|
2251
|
+
const configuredRoots = deps.transientEntrypointRoots;
|
|
2252
|
+
if (configuredRoots && configuredRoots.length > 0) {
|
|
2253
|
+
return [...new Set(configuredRoots.map((root) => normalizeComparisonPath(root, deps.platform)))];
|
|
2254
|
+
}
|
|
2255
|
+
const roots = [tmpdir()];
|
|
2256
|
+
if (deps.platform === "darwin") {
|
|
2257
|
+
roots.push("/tmp", "/private/tmp");
|
|
2258
|
+
}
|
|
2259
|
+
return [...new Set(roots.map((root) => normalizeComparisonPath(root, deps.platform)))];
|
|
2260
|
+
};
|
|
2261
|
+
var isTransientCliPath = (cliPath, deps) => {
|
|
2262
|
+
const normalizedCliPath = normalizeComparisonPath(cliPath, deps.platform);
|
|
2263
|
+
return getTransientEntrypointRoots(deps).some((root) => isPathInsideRoot(cliPath, root, deps.platform)) || NPX_CACHE_SEGMENT_PATTERN.test(normalizedCliPath);
|
|
2264
|
+
};
|
|
2265
|
+
var TRANSIENT_AUTOSTART_INSTALL_ERROR_PREFIX = "Cannot install daemon autostart from transient CLI path";
|
|
2266
|
+
var isTransientAutostartInstallError = (error) => {
|
|
2267
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2268
|
+
return message.startsWith(TRANSIENT_AUTOSTART_INSTALL_ERROR_PREFIX);
|
|
2269
|
+
};
|
|
2110
2270
|
var resolveCliEntrypoint = (deps = {}) => {
|
|
2111
2271
|
const resolved = { ...defaultDeps(), ...deps };
|
|
2112
2272
|
const exists = resolved.existsSync;
|
|
2113
2273
|
let cliPath = null;
|
|
2274
|
+
let source = "module";
|
|
2114
2275
|
if (resolved.argv1) {
|
|
2115
2276
|
const candidate = resolve4(resolved.argv1);
|
|
2116
2277
|
if (exists(candidate)) {
|
|
2117
2278
|
cliPath = candidate;
|
|
2279
|
+
source = "argv1";
|
|
2118
2280
|
}
|
|
2119
2281
|
}
|
|
2120
2282
|
if (!cliPath) {
|
|
@@ -2122,16 +2284,17 @@ var resolveCliEntrypoint = (deps = {}) => {
|
|
|
2122
2284
|
}
|
|
2123
2285
|
const nodePath = process.execPath;
|
|
2124
2286
|
const args = [cliPath, "serve"];
|
|
2125
|
-
const command =
|
|
2126
|
-
|
|
2287
|
+
const command = formatCommand([nodePath, ...args]);
|
|
2288
|
+
const isTransient = isTransientCliPath(cliPath, resolved);
|
|
2289
|
+
return { nodePath, cliPath, args, command, source, isTransient };
|
|
2127
2290
|
};
|
|
2128
|
-
var getLaunchAgentPath = (home =
|
|
2291
|
+
var getLaunchAgentPath = (home = homedir6()) => {
|
|
2129
2292
|
return join8(home, "Library", "LaunchAgents", `${MAC_LABEL}.plist`);
|
|
2130
2293
|
};
|
|
2131
2294
|
var buildLaunchAgentPlist = (entrypoint, options = {}) => {
|
|
2132
2295
|
const label = options.label ?? MAC_LABEL;
|
|
2133
|
-
const stdoutPath = options.stdoutPath ?? join8(
|
|
2134
|
-
const stderrPath = options.stderrPath ?? join8(
|
|
2296
|
+
const stdoutPath = options.stdoutPath ?? join8(homedir6(), "Library", "Logs", "opendevbrowser-daemon.log");
|
|
2297
|
+
const stderrPath = options.stderrPath ?? join8(homedir6(), "Library", "Logs", "opendevbrowser-daemon.err.log");
|
|
2135
2298
|
const programArgs = [entrypoint.nodePath, ...entrypoint.args].map((value) => ` <string>${value}</string>`).join("\n");
|
|
2136
2299
|
return [
|
|
2137
2300
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
@@ -2158,7 +2321,7 @@ var buildLaunchAgentPlist = (entrypoint, options = {}) => {
|
|
|
2158
2321
|
].join("\n");
|
|
2159
2322
|
};
|
|
2160
2323
|
var buildWindowsTaskArgs = (entrypoint, taskName = WIN_TASK_NAME) => {
|
|
2161
|
-
const command =
|
|
2324
|
+
const command = formatCommand([entrypoint.nodePath, entrypoint.cliPath, "serve"]);
|
|
2162
2325
|
const args = [
|
|
2163
2326
|
"/Create",
|
|
2164
2327
|
"/TN",
|
|
@@ -2173,6 +2336,146 @@ var buildWindowsTaskArgs = (entrypoint, taskName = WIN_TASK_NAME) => {
|
|
|
2173
2336
|
];
|
|
2174
2337
|
return { taskName, command, args };
|
|
2175
2338
|
};
|
|
2339
|
+
var createAutostartStatus = (status) => status;
|
|
2340
|
+
var createMacAutostartStatus = (entrypoint, location, overrides) => {
|
|
2341
|
+
return createAutostartStatus({
|
|
2342
|
+
platform: "darwin",
|
|
2343
|
+
supported: true,
|
|
2344
|
+
installed: false,
|
|
2345
|
+
health: "missing",
|
|
2346
|
+
needsRepair: false,
|
|
2347
|
+
location,
|
|
2348
|
+
label: MAC_LABEL,
|
|
2349
|
+
expectedCommand: entrypoint.isTransient ? void 0 : entrypoint.command,
|
|
2350
|
+
...overrides
|
|
2351
|
+
});
|
|
2352
|
+
};
|
|
2353
|
+
var createWindowsAutostartStatus = (entrypoint, overrides) => {
|
|
2354
|
+
return createAutostartStatus({
|
|
2355
|
+
platform: "win32",
|
|
2356
|
+
supported: true,
|
|
2357
|
+
installed: false,
|
|
2358
|
+
health: "missing",
|
|
2359
|
+
needsRepair: false,
|
|
2360
|
+
taskName: WIN_TASK_NAME,
|
|
2361
|
+
expectedCommand: entrypoint.isTransient ? void 0 : entrypoint.command,
|
|
2362
|
+
...overrides
|
|
2363
|
+
});
|
|
2364
|
+
};
|
|
2365
|
+
var classifyPersistedProgramArguments = (programArguments, deps) => {
|
|
2366
|
+
const actualNodePath = programArguments[0];
|
|
2367
|
+
const actualCliPath = programArguments[1];
|
|
2368
|
+
if (!actualNodePath || !deps.existsSync(actualNodePath)) {
|
|
2369
|
+
return { health: "needs_repair", reason: "missing_node_path" };
|
|
2370
|
+
}
|
|
2371
|
+
if (!actualCliPath || !deps.existsSync(actualCliPath)) {
|
|
2372
|
+
return { health: "needs_repair", reason: "missing_cli_path" };
|
|
2373
|
+
}
|
|
2374
|
+
if (isTransientCliPath(actualCliPath, deps)) {
|
|
2375
|
+
return { health: "needs_repair", reason: "transient_cli_path" };
|
|
2376
|
+
}
|
|
2377
|
+
if (programArguments.length !== 3 || programArguments[2] !== "serve") {
|
|
2378
|
+
return { health: "needs_repair", reason: "entrypoint_mismatch" };
|
|
2379
|
+
}
|
|
2380
|
+
return { health: "healthy" };
|
|
2381
|
+
};
|
|
2382
|
+
var hasMatchingProgramArgument = (programArguments, expectedValue, deps, isPath = false) => {
|
|
2383
|
+
const normalizedExpected = isPath ? normalizeComparisonPath(expectedValue, deps.platform) : expectedValue;
|
|
2384
|
+
return programArguments.some((value) => {
|
|
2385
|
+
const normalizedValue = isPath ? normalizeComparisonPath(value, deps.platform) : value;
|
|
2386
|
+
return normalizedValue === normalizedExpected;
|
|
2387
|
+
});
|
|
2388
|
+
};
|
|
2389
|
+
var classifyExpectedProgramArguments = (expectedArgs, actualArgs, deps) => {
|
|
2390
|
+
if (!hasMatchingProgramArgument([actualArgs[0] ?? ""], expectedArgs[0] ?? "", deps, true)) {
|
|
2391
|
+
return hasMatchingProgramArgument(actualArgs, expectedArgs[0] ?? "", deps, true) ? "entrypoint_mismatch" : "missing_node_path";
|
|
2392
|
+
}
|
|
2393
|
+
if (!hasMatchingProgramArgument([actualArgs[1] ?? ""], expectedArgs[1] ?? "", deps, true)) {
|
|
2394
|
+
return hasMatchingProgramArgument(actualArgs, expectedArgs[1] ?? "", deps, true) ? "entrypoint_mismatch" : "missing_cli_path";
|
|
2395
|
+
}
|
|
2396
|
+
if (actualArgs.length !== expectedArgs.length || !actualArgs.every((value, index) => {
|
|
2397
|
+
const expectedValue = expectedArgs[index] ?? "";
|
|
2398
|
+
return index < 2 ? normalizeComparisonPath(value, deps.platform) === normalizeComparisonPath(expectedValue, deps.platform) : value === expectedValue;
|
|
2399
|
+
})) {
|
|
2400
|
+
return "entrypoint_mismatch";
|
|
2401
|
+
}
|
|
2402
|
+
return void 0;
|
|
2403
|
+
};
|
|
2404
|
+
var readMacLaunchAgentProgramArguments = (plistPath, deps) => {
|
|
2405
|
+
try {
|
|
2406
|
+
const text = deps.execFileSync("plutil", ["-convert", "json", "-o", "-", plistPath], { encoding: "utf-8" });
|
|
2407
|
+
const parsed = JSON.parse(text);
|
|
2408
|
+
const programArguments = parsed?.ProgramArguments;
|
|
2409
|
+
if (!Array.isArray(programArguments) || programArguments.length < 2 || programArguments.some((value) => typeof value !== "string")) {
|
|
2410
|
+
return { ok: false, reason: "missing_program_arguments" };
|
|
2411
|
+
}
|
|
2412
|
+
const commandArgs = programArguments;
|
|
2413
|
+
return {
|
|
2414
|
+
ok: true,
|
|
2415
|
+
command: formatCommand(commandArgs),
|
|
2416
|
+
programArguments: commandArgs
|
|
2417
|
+
};
|
|
2418
|
+
} catch {
|
|
2419
|
+
return { ok: false, reason: "malformed_plist" };
|
|
2420
|
+
}
|
|
2421
|
+
};
|
|
2422
|
+
var classifyMacAutostartStatus = (entrypoint, location, deps) => {
|
|
2423
|
+
if (!deps.existsSync(location)) {
|
|
2424
|
+
return createMacAutostartStatus(entrypoint, location, {
|
|
2425
|
+
installed: false,
|
|
2426
|
+
health: "missing",
|
|
2427
|
+
needsRepair: false,
|
|
2428
|
+
reason: "missing_plist"
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
const parsed = readMacLaunchAgentProgramArguments(location, deps);
|
|
2432
|
+
if (!parsed.ok) {
|
|
2433
|
+
return createMacAutostartStatus(entrypoint, location, {
|
|
2434
|
+
installed: true,
|
|
2435
|
+
health: "malformed",
|
|
2436
|
+
needsRepair: true,
|
|
2437
|
+
reason: parsed.reason
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
const expectedNodePath = entrypoint.nodePath;
|
|
2441
|
+
const expectedCliPath = entrypoint.cliPath;
|
|
2442
|
+
const expectedArgs = [expectedNodePath, ...entrypoint.args];
|
|
2443
|
+
const actualArgs = parsed.programArguments;
|
|
2444
|
+
const actualStatus = classifyPersistedProgramArguments(actualArgs, deps);
|
|
2445
|
+
if (actualStatus.health !== "healthy") {
|
|
2446
|
+
return createMacAutostartStatus(entrypoint, location, {
|
|
2447
|
+
installed: true,
|
|
2448
|
+
health: "needs_repair",
|
|
2449
|
+
needsRepair: true,
|
|
2450
|
+
command: parsed.command,
|
|
2451
|
+
reason: actualStatus.reason
|
|
2452
|
+
});
|
|
2453
|
+
}
|
|
2454
|
+
if (entrypoint.isTransient) {
|
|
2455
|
+
return createMacAutostartStatus(entrypoint, location, {
|
|
2456
|
+
installed: true,
|
|
2457
|
+
health: "healthy",
|
|
2458
|
+
needsRepair: false,
|
|
2459
|
+
command: parsed.command
|
|
2460
|
+
});
|
|
2461
|
+
}
|
|
2462
|
+
const mismatchReason = classifyExpectedProgramArguments(expectedArgs, actualArgs, deps);
|
|
2463
|
+
if (mismatchReason) {
|
|
2464
|
+
return createMacAutostartStatus(entrypoint, location, {
|
|
2465
|
+
installed: true,
|
|
2466
|
+
health: "needs_repair",
|
|
2467
|
+
needsRepair: true,
|
|
2468
|
+
command: parsed.command,
|
|
2469
|
+
reason: mismatchReason
|
|
2470
|
+
});
|
|
2471
|
+
}
|
|
2472
|
+
return createMacAutostartStatus(entrypoint, location, {
|
|
2473
|
+
installed: true,
|
|
2474
|
+
health: "healthy",
|
|
2475
|
+
needsRepair: false,
|
|
2476
|
+
command: parsed.command
|
|
2477
|
+
});
|
|
2478
|
+
};
|
|
2176
2479
|
var runCommand = (exec, command, args, ignoreFailure = false) => {
|
|
2177
2480
|
try {
|
|
2178
2481
|
exec(command, args, { stdio: "ignore" });
|
|
@@ -2182,41 +2485,57 @@ var runCommand = (exec, command, args, ignoreFailure = false) => {
|
|
|
2182
2485
|
throw new Error(`${command} ${args.join(" ")} failed: ${message}`);
|
|
2183
2486
|
}
|
|
2184
2487
|
};
|
|
2488
|
+
var assertPersistentEntrypoint = (entrypoint) => {
|
|
2489
|
+
if (!entrypoint.isTransient) {
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
throw new Error(
|
|
2493
|
+
`${TRANSIENT_AUTOSTART_INSTALL_ERROR_PREFIX} "${entrypoint.cliPath}". ${STABLE_DAEMON_INSTALL_GUIDANCE} Do not use a temporary npx cache or onboarding workspace.`
|
|
2494
|
+
);
|
|
2495
|
+
};
|
|
2185
2496
|
var installMacAutostart = (deps = {}) => {
|
|
2186
2497
|
const resolved = { ...defaultDeps(), ...deps };
|
|
2187
2498
|
const entrypoint = resolveCliEntrypoint(resolved);
|
|
2188
|
-
|
|
2499
|
+
assertPersistentEntrypoint(entrypoint);
|
|
2500
|
+
const home = resolved.homedir();
|
|
2501
|
+
const plistPath = getLaunchAgentPath(home);
|
|
2502
|
+
const stdoutPath = join8(home, "Library", "Logs", "opendevbrowser-daemon.log");
|
|
2503
|
+
const stderrPath = join8(home, "Library", "Logs", "opendevbrowser-daemon.err.log");
|
|
2504
|
+
const logsDir = dirname5(stdoutPath);
|
|
2189
2505
|
resolved.mkdirSync(dirname5(plistPath), { recursive: true });
|
|
2190
|
-
resolved.
|
|
2506
|
+
resolved.mkdirSync(logsDir, { recursive: true });
|
|
2507
|
+
resolved.writeFileSync(
|
|
2508
|
+
plistPath,
|
|
2509
|
+
buildLaunchAgentPlist(entrypoint, { stdoutPath, stderrPath }),
|
|
2510
|
+
{ encoding: "utf-8" }
|
|
2511
|
+
);
|
|
2191
2512
|
const uid = resolved.uid;
|
|
2192
2513
|
runCommand(resolved.execFileSync, "launchctl", ["bootout", `gui/${uid}`, plistPath], true);
|
|
2193
2514
|
runCommand(resolved.execFileSync, "launchctl", ["bootstrap", `gui/${uid}`, plistPath]);
|
|
2194
2515
|
runCommand(resolved.execFileSync, "launchctl", ["enable", `gui/${uid}/${MAC_LABEL}`], true);
|
|
2195
2516
|
runCommand(resolved.execFileSync, "launchctl", ["kickstart", "-k", `gui/${uid}/${MAC_LABEL}`], true);
|
|
2196
|
-
return {
|
|
2197
|
-
platform: "darwin",
|
|
2198
|
-
supported: true,
|
|
2517
|
+
return createMacAutostartStatus(entrypoint, plistPath, {
|
|
2199
2518
|
installed: true,
|
|
2200
|
-
|
|
2201
|
-
|
|
2519
|
+
health: "healthy",
|
|
2520
|
+
needsRepair: false,
|
|
2202
2521
|
command: entrypoint.command
|
|
2203
|
-
};
|
|
2522
|
+
});
|
|
2204
2523
|
};
|
|
2205
2524
|
var uninstallMacAutostart = (deps = {}) => {
|
|
2206
2525
|
const resolved = { ...defaultDeps(), ...deps };
|
|
2526
|
+
const entrypoint = resolveCliEntrypoint(resolved);
|
|
2207
2527
|
const plistPath = getLaunchAgentPath(resolved.homedir());
|
|
2208
2528
|
const uid = resolved.uid;
|
|
2209
2529
|
runCommand(resolved.execFileSync, "launchctl", ["bootout", `gui/${uid}`, plistPath], true);
|
|
2210
2530
|
if (resolved.existsSync(plistPath)) {
|
|
2211
2531
|
resolved.unlinkSync(plistPath);
|
|
2212
2532
|
}
|
|
2213
|
-
return {
|
|
2214
|
-
platform: "darwin",
|
|
2215
|
-
supported: true,
|
|
2533
|
+
return createMacAutostartStatus(entrypoint, plistPath, {
|
|
2216
2534
|
installed: false,
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2535
|
+
health: "missing",
|
|
2536
|
+
needsRepair: false,
|
|
2537
|
+
reason: "missing_plist"
|
|
2538
|
+
});
|
|
2220
2539
|
};
|
|
2221
2540
|
var isWindowsTaskInstalled = (deps = {}) => {
|
|
2222
2541
|
const resolved = { ...defaultDeps(), ...deps };
|
|
@@ -2227,55 +2546,175 @@ var isWindowsTaskInstalled = (deps = {}) => {
|
|
|
2227
2546
|
return false;
|
|
2228
2547
|
}
|
|
2229
2548
|
};
|
|
2549
|
+
var decodeXmlText = (value) => {
|
|
2550
|
+
return value.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
2551
|
+
};
|
|
2552
|
+
var readXmlTag = (xml, tagName) => {
|
|
2553
|
+
const match = xml.match(new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, "i"));
|
|
2554
|
+
return match?.[1] ? decodeXmlText(match[1]) : void 0;
|
|
2555
|
+
};
|
|
2556
|
+
var splitCommandLine = (value) => {
|
|
2557
|
+
const args = [];
|
|
2558
|
+
let current = "";
|
|
2559
|
+
let inQuotes = false;
|
|
2560
|
+
let backslashes = 0;
|
|
2561
|
+
for (const char of value) {
|
|
2562
|
+
if (char === "\\") {
|
|
2563
|
+
backslashes += 1;
|
|
2564
|
+
continue;
|
|
2565
|
+
}
|
|
2566
|
+
if (char === '"') {
|
|
2567
|
+
if (backslashes > 0) {
|
|
2568
|
+
current += "\\".repeat(Math.floor(backslashes / 2));
|
|
2569
|
+
if (backslashes % 2 === 1) {
|
|
2570
|
+
current += '"';
|
|
2571
|
+
backslashes = 0;
|
|
2572
|
+
continue;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
backslashes = 0;
|
|
2576
|
+
inQuotes = !inQuotes;
|
|
2577
|
+
continue;
|
|
2578
|
+
}
|
|
2579
|
+
if (backslashes > 0) {
|
|
2580
|
+
current += "\\".repeat(backslashes);
|
|
2581
|
+
backslashes = 0;
|
|
2582
|
+
}
|
|
2583
|
+
if (!inQuotes && /\s/.test(char)) {
|
|
2584
|
+
if (current.length > 0) {
|
|
2585
|
+
args.push(current);
|
|
2586
|
+
current = "";
|
|
2587
|
+
}
|
|
2588
|
+
continue;
|
|
2589
|
+
}
|
|
2590
|
+
current += char;
|
|
2591
|
+
}
|
|
2592
|
+
if (backslashes > 0) {
|
|
2593
|
+
current += "\\".repeat(backslashes);
|
|
2594
|
+
}
|
|
2595
|
+
if (current.length > 0) {
|
|
2596
|
+
args.push(current);
|
|
2597
|
+
}
|
|
2598
|
+
return args;
|
|
2599
|
+
};
|
|
2600
|
+
var readWindowsTaskAction = (taskName, deps) => {
|
|
2601
|
+
try {
|
|
2602
|
+
const xml = deps.execFileSync("schtasks", ["/Query", "/TN", taskName, "/XML"], { encoding: "utf-8" });
|
|
2603
|
+
const command = readXmlTag(xml, "Command");
|
|
2604
|
+
const argumentsValue = readXmlTag(xml, "Arguments");
|
|
2605
|
+
if (!command) {
|
|
2606
|
+
return { ok: false };
|
|
2607
|
+
}
|
|
2608
|
+
const programArguments = argumentsValue !== void 0 ? [command, ...splitCommandLine(argumentsValue)] : splitCommandLine(command);
|
|
2609
|
+
if (programArguments.length === 0) {
|
|
2610
|
+
return { ok: false };
|
|
2611
|
+
}
|
|
2612
|
+
return {
|
|
2613
|
+
ok: true,
|
|
2614
|
+
command: formatCommand(programArguments),
|
|
2615
|
+
programArguments
|
|
2616
|
+
};
|
|
2617
|
+
} catch {
|
|
2618
|
+
return { ok: false };
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
var classifyWindowsAutostartStatus = (entrypoint, deps) => {
|
|
2622
|
+
const installed = isWindowsTaskInstalled(deps);
|
|
2623
|
+
if (!installed) {
|
|
2624
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2625
|
+
installed: false,
|
|
2626
|
+
health: "missing",
|
|
2627
|
+
needsRepair: false
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
const parsed = readWindowsTaskAction(WIN_TASK_NAME, deps);
|
|
2631
|
+
if (!parsed.ok) {
|
|
2632
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2633
|
+
installed: true,
|
|
2634
|
+
health: "needs_repair",
|
|
2635
|
+
needsRepair: true,
|
|
2636
|
+
reason: "entrypoint_mismatch"
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
const expectedArgs = [entrypoint.nodePath, ...entrypoint.args];
|
|
2640
|
+
const actualStatus = classifyPersistedProgramArguments(parsed.programArguments, deps);
|
|
2641
|
+
if (actualStatus.health !== "healthy") {
|
|
2642
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2643
|
+
installed: true,
|
|
2644
|
+
health: "needs_repair",
|
|
2645
|
+
needsRepair: true,
|
|
2646
|
+
command: parsed.command,
|
|
2647
|
+
reason: actualStatus.reason
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
if (entrypoint.isTransient) {
|
|
2651
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2652
|
+
installed: true,
|
|
2653
|
+
health: "healthy",
|
|
2654
|
+
needsRepair: false,
|
|
2655
|
+
command: parsed.command
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
const mismatchReason = classifyExpectedProgramArguments(expectedArgs, parsed.programArguments, deps);
|
|
2659
|
+
if (mismatchReason) {
|
|
2660
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2661
|
+
installed: true,
|
|
2662
|
+
health: "needs_repair",
|
|
2663
|
+
needsRepair: true,
|
|
2664
|
+
command: parsed.command,
|
|
2665
|
+
reason: mismatchReason
|
|
2666
|
+
});
|
|
2667
|
+
}
|
|
2668
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2669
|
+
installed: true,
|
|
2670
|
+
health: "healthy",
|
|
2671
|
+
needsRepair: false,
|
|
2672
|
+
command: parsed.command
|
|
2673
|
+
});
|
|
2674
|
+
};
|
|
2230
2675
|
var installWindowsAutostart = (deps = {}) => {
|
|
2231
2676
|
const resolved = { ...defaultDeps(), ...deps };
|
|
2232
2677
|
const entrypoint = resolveCliEntrypoint(resolved);
|
|
2678
|
+
assertPersistentEntrypoint(entrypoint);
|
|
2233
2679
|
const { args } = buildWindowsTaskArgs(entrypoint, WIN_TASK_NAME);
|
|
2234
2680
|
runCommand(resolved.execFileSync, "schtasks", args);
|
|
2235
|
-
return {
|
|
2236
|
-
platform: "win32",
|
|
2237
|
-
supported: true,
|
|
2681
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2238
2682
|
installed: true,
|
|
2239
|
-
|
|
2683
|
+
health: "healthy",
|
|
2684
|
+
needsRepair: false,
|
|
2240
2685
|
command: entrypoint.command
|
|
2241
|
-
};
|
|
2686
|
+
});
|
|
2242
2687
|
};
|
|
2243
2688
|
var uninstallWindowsAutostart = (deps = {}) => {
|
|
2244
2689
|
const resolved = { ...defaultDeps(), ...deps };
|
|
2690
|
+
const entrypoint = resolveCliEntrypoint(resolved);
|
|
2245
2691
|
runCommand(resolved.execFileSync, "schtasks", ["/Delete", "/TN", WIN_TASK_NAME, "/F"], true);
|
|
2246
|
-
return {
|
|
2247
|
-
platform: "win32",
|
|
2248
|
-
supported: true,
|
|
2692
|
+
return createWindowsAutostartStatus(entrypoint, {
|
|
2249
2693
|
installed: false,
|
|
2250
|
-
|
|
2251
|
-
|
|
2694
|
+
health: "missing",
|
|
2695
|
+
needsRepair: false
|
|
2696
|
+
});
|
|
2252
2697
|
};
|
|
2253
2698
|
var getAutostartStatus = (deps = {}) => {
|
|
2254
2699
|
const resolved = { ...defaultDeps(), ...deps };
|
|
2255
2700
|
const platform = resolved.platform;
|
|
2256
2701
|
if (platform === "darwin") {
|
|
2702
|
+
const entrypoint = resolveCliEntrypoint(resolved);
|
|
2257
2703
|
const location = getLaunchAgentPath(resolved.homedir());
|
|
2258
|
-
return
|
|
2259
|
-
platform,
|
|
2260
|
-
supported: true,
|
|
2261
|
-
installed: resolved.existsSync(location),
|
|
2262
|
-
location,
|
|
2263
|
-
label: MAC_LABEL
|
|
2264
|
-
};
|
|
2704
|
+
return classifyMacAutostartStatus(entrypoint, location, resolved);
|
|
2265
2705
|
}
|
|
2266
2706
|
if (platform === "win32") {
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
supported: true,
|
|
2270
|
-
installed: isWindowsTaskInstalled(resolved),
|
|
2271
|
-
taskName: WIN_TASK_NAME
|
|
2272
|
-
};
|
|
2707
|
+
const entrypoint = resolveCliEntrypoint(resolved);
|
|
2708
|
+
return classifyWindowsAutostartStatus(entrypoint, resolved);
|
|
2273
2709
|
}
|
|
2274
|
-
return {
|
|
2710
|
+
return createAutostartStatus({
|
|
2275
2711
|
platform,
|
|
2276
2712
|
supported: false,
|
|
2277
|
-
installed: false
|
|
2278
|
-
|
|
2713
|
+
installed: false,
|
|
2714
|
+
health: "unsupported",
|
|
2715
|
+
needsRepair: false,
|
|
2716
|
+
reason: "unsupported_platform"
|
|
2717
|
+
});
|
|
2279
2718
|
};
|
|
2280
2719
|
var installAutostart = (deps = {}) => {
|
|
2281
2720
|
const platform = deps.platform ?? process.platform;
|
|
@@ -2285,11 +2724,14 @@ var installAutostart = (deps = {}) => {
|
|
|
2285
2724
|
if (platform === "win32") {
|
|
2286
2725
|
return installWindowsAutostart(deps);
|
|
2287
2726
|
}
|
|
2288
|
-
return {
|
|
2727
|
+
return createAutostartStatus({
|
|
2289
2728
|
platform,
|
|
2290
2729
|
supported: false,
|
|
2291
|
-
installed: false
|
|
2292
|
-
|
|
2730
|
+
installed: false,
|
|
2731
|
+
health: "unsupported",
|
|
2732
|
+
needsRepair: false,
|
|
2733
|
+
reason: "unsupported_platform"
|
|
2734
|
+
});
|
|
2293
2735
|
};
|
|
2294
2736
|
var uninstallAutostart = (deps = {}) => {
|
|
2295
2737
|
const platform = deps.platform ?? process.platform;
|
|
@@ -2299,11 +2741,14 @@ var uninstallAutostart = (deps = {}) => {
|
|
|
2299
2741
|
if (platform === "win32") {
|
|
2300
2742
|
return uninstallWindowsAutostart(deps);
|
|
2301
2743
|
}
|
|
2302
|
-
return {
|
|
2744
|
+
return createAutostartStatus({
|
|
2303
2745
|
platform,
|
|
2304
2746
|
supported: false,
|
|
2305
|
-
installed: false
|
|
2306
|
-
|
|
2747
|
+
installed: false,
|
|
2748
|
+
health: "unsupported",
|
|
2749
|
+
needsRepair: false,
|
|
2750
|
+
reason: "unsupported_platform"
|
|
2751
|
+
});
|
|
2307
2752
|
};
|
|
2308
2753
|
|
|
2309
2754
|
// src/cli/commands/daemon.ts
|
|
@@ -2329,20 +2774,55 @@ var stopDaemonIfRunning = async () => {
|
|
|
2329
2774
|
return false;
|
|
2330
2775
|
}
|
|
2331
2776
|
};
|
|
2777
|
+
var formatReason = (reason) => {
|
|
2778
|
+
return reason ? reason.replace(/_/g, " ") : "unknown reason";
|
|
2779
|
+
};
|
|
2780
|
+
var buildStableAutostartGuidance = (action) => {
|
|
2781
|
+
return `${STABLE_DAEMON_INSTALL_GUIDANCE.replace(/\.$/, "")} to ${action} it.`;
|
|
2782
|
+
};
|
|
2783
|
+
var describeAutostartLocation = (autostart) => {
|
|
2784
|
+
if (autostart.location) {
|
|
2785
|
+
return ` at ${autostart.location}`;
|
|
2786
|
+
}
|
|
2787
|
+
if (autostart.taskName) {
|
|
2788
|
+
return ` (${autostart.taskName})`;
|
|
2789
|
+
}
|
|
2790
|
+
return "";
|
|
2791
|
+
};
|
|
2332
2792
|
var buildStatusMessage = (autostart, running) => {
|
|
2793
|
+
const runningText = running ? "running" : "not running";
|
|
2333
2794
|
if (!autostart.supported) {
|
|
2334
|
-
return `Daemon autostart is not supported on ${autostart.platform}.`;
|
|
2795
|
+
return `Daemon autostart is not supported on ${autostart.platform}. Daemon is ${runningText}.`;
|
|
2335
2796
|
}
|
|
2336
|
-
const
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2797
|
+
const location = describeAutostartLocation(autostart);
|
|
2798
|
+
if (autostart.health === "healthy") {
|
|
2799
|
+
return `Autostart is installed and healthy${location}. Daemon is ${runningText}.`;
|
|
2800
|
+
}
|
|
2801
|
+
if (autostart.health === "missing") {
|
|
2802
|
+
return `Autostart is not installed${location}. ${buildStableAutostartGuidance("install")} Daemon is ${runningText}.`;
|
|
2803
|
+
}
|
|
2804
|
+
if (autostart.health === "needs_repair") {
|
|
2805
|
+
return `Autostart is installed${location} but needs repair (${formatReason(autostart.reason)}). ${buildStableAutostartGuidance("repair")} Daemon is ${runningText}.`;
|
|
2806
|
+
}
|
|
2807
|
+
if (autostart.health === "malformed") {
|
|
2808
|
+
return `Autostart exists${location} but is malformed (${formatReason(autostart.reason)}). ${buildStableAutostartGuidance("repair")} Daemon is ${runningText}.`;
|
|
2809
|
+
}
|
|
2810
|
+
return `Daemon autostart is not supported on ${autostart.platform}. Daemon is ${runningText}.`;
|
|
2341
2811
|
};
|
|
2342
2812
|
async function runDaemonCommand(args) {
|
|
2343
2813
|
const { subcommand } = parseDaemonArgs(args.rawArgs);
|
|
2344
2814
|
if (subcommand === "install") {
|
|
2345
|
-
|
|
2815
|
+
let result;
|
|
2816
|
+
try {
|
|
2817
|
+
result = installAutostart();
|
|
2818
|
+
} catch (error) {
|
|
2819
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
2820
|
+
return {
|
|
2821
|
+
success: false,
|
|
2822
|
+
message: isTransientAutostartInstallError(error) ? message2 : `Daemon autostart install failed: ${message2}`,
|
|
2823
|
+
exitCode: EXIT_EXECUTION
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2346
2826
|
if (!result.supported) {
|
|
2347
2827
|
return {
|
|
2348
2828
|
success: false,
|
|
@@ -2400,7 +2880,21 @@ async function runDaemonCommand(args) {
|
|
|
2400
2880
|
|
|
2401
2881
|
// src/cli/commands/artifacts.ts
|
|
2402
2882
|
import { join as join9, resolve as resolve5 } from "path";
|
|
2403
|
-
import { tmpdir } from "os";
|
|
2883
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
2884
|
+
var PASSTHROUGH_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
2885
|
+
"--with-config",
|
|
2886
|
+
"--no-prompt",
|
|
2887
|
+
"--no-interactive",
|
|
2888
|
+
"--quiet",
|
|
2889
|
+
"--skills-global",
|
|
2890
|
+
"--skills-local",
|
|
2891
|
+
"--no-skills",
|
|
2892
|
+
"--full"
|
|
2893
|
+
]);
|
|
2894
|
+
var PASSTHROUGH_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
2895
|
+
"--output-format",
|
|
2896
|
+
"--transport"
|
|
2897
|
+
]);
|
|
2404
2898
|
var usageError = () => {
|
|
2405
2899
|
throw createUsageError("Usage: opendevbrowser artifacts cleanup --expired-only [--output-dir <path>]");
|
|
2406
2900
|
};
|
|
@@ -2411,6 +2905,24 @@ var requireValue = (rawArgs, index, flag) => {
|
|
|
2411
2905
|
}
|
|
2412
2906
|
return value;
|
|
2413
2907
|
};
|
|
2908
|
+
var consumePassthroughFlag = (rawArgs, index) => {
|
|
2909
|
+
const arg = rawArgs[index];
|
|
2910
|
+
if (!arg) {
|
|
2911
|
+
return null;
|
|
2912
|
+
}
|
|
2913
|
+
if (PASSTHROUGH_BOOLEAN_FLAGS.has(arg)) {
|
|
2914
|
+
return index;
|
|
2915
|
+
}
|
|
2916
|
+
if (PASSTHROUGH_VALUE_FLAGS.has(arg)) {
|
|
2917
|
+
requireValue(rawArgs, index, arg);
|
|
2918
|
+
return index + 1;
|
|
2919
|
+
}
|
|
2920
|
+
const equalsFlag = arg.split("=", 2)[0];
|
|
2921
|
+
if (equalsFlag && PASSTHROUGH_VALUE_FLAGS.has(equalsFlag)) {
|
|
2922
|
+
return index;
|
|
2923
|
+
}
|
|
2924
|
+
return null;
|
|
2925
|
+
};
|
|
2414
2926
|
var parseArtifactsArgs = (rawArgs) => {
|
|
2415
2927
|
const [candidate, ...rest] = rawArgs;
|
|
2416
2928
|
if (candidate !== "cleanup") {
|
|
@@ -2438,6 +2950,11 @@ var parseArtifactsArgs = (rawArgs) => {
|
|
|
2438
2950
|
outputDir = value;
|
|
2439
2951
|
continue;
|
|
2440
2952
|
}
|
|
2953
|
+
const passthroughIndex = consumePassthroughFlag(rest, index);
|
|
2954
|
+
if (passthroughIndex !== null) {
|
|
2955
|
+
index = passthroughIndex;
|
|
2956
|
+
continue;
|
|
2957
|
+
}
|
|
2441
2958
|
throw createUsageError(`Unknown artifacts flag: ${arg}`);
|
|
2442
2959
|
}
|
|
2443
2960
|
if (!expiredOnly) {
|
|
@@ -2451,7 +2968,7 @@ var parseArtifactsArgs = (rawArgs) => {
|
|
|
2451
2968
|
};
|
|
2452
2969
|
async function runArtifactsCommand(args) {
|
|
2453
2970
|
const parsed = parseArtifactsArgs(args.rawArgs);
|
|
2454
|
-
const rootDir = parsed.outputDir ? resolve5(parsed.outputDir) : join9(
|
|
2971
|
+
const rootDir = parsed.outputDir ? resolve5(parsed.outputDir) : join9(tmpdir2(), "opendevbrowser");
|
|
2455
2972
|
const cleaned = await cleanupExpiredArtifacts(rootDir);
|
|
2456
2973
|
return {
|
|
2457
2974
|
success: true,
|
|
@@ -2467,10 +2984,139 @@ async function runArtifactsCommand(args) {
|
|
|
2467
2984
|
};
|
|
2468
2985
|
}
|
|
2469
2986
|
|
|
2987
|
+
// src/cli/install-autostart-reconciliation.ts
|
|
2988
|
+
var INSTALL_AUTOSTART_SKIP_ENV_VAR = "OPDEVBROWSER_SKIP_INSTALL_AUTOSTART_RECONCILIATION";
|
|
2989
|
+
var defaultDeps2 = () => ({
|
|
2990
|
+
getAutostartStatus,
|
|
2991
|
+
installAutostart
|
|
2992
|
+
});
|
|
2993
|
+
function shouldSkipInstallAutostartReconciliation(env = process.env) {
|
|
2994
|
+
const raw = env[INSTALL_AUTOSTART_SKIP_ENV_VAR];
|
|
2995
|
+
if (raw === void 0) {
|
|
2996
|
+
return false;
|
|
2997
|
+
}
|
|
2998
|
+
const normalized = raw.trim().toLowerCase();
|
|
2999
|
+
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
3000
|
+
}
|
|
3001
|
+
function reconcileInstallAutostart(installResult, deps = {}, options = {}) {
|
|
3002
|
+
if (!installResult.success || shouldSkipInstallAutostartReconciliation(options.env)) {
|
|
3003
|
+
return { attempted: false };
|
|
3004
|
+
}
|
|
3005
|
+
const resolved = { ...defaultDeps2(), ...deps };
|
|
3006
|
+
const status = resolved.getAutostartStatus();
|
|
3007
|
+
if (!status.supported) {
|
|
3008
|
+
return {
|
|
3009
|
+
attempted: false,
|
|
3010
|
+
autostart: status,
|
|
3011
|
+
autostartAction: "unsupported"
|
|
3012
|
+
};
|
|
3013
|
+
}
|
|
3014
|
+
if (status.health === "healthy") {
|
|
3015
|
+
return {
|
|
3016
|
+
attempted: false,
|
|
3017
|
+
autostart: status,
|
|
3018
|
+
autostartAction: "already_healthy"
|
|
3019
|
+
};
|
|
3020
|
+
}
|
|
3021
|
+
if (status.health !== "missing" && status.health !== "needs_repair" && status.health !== "malformed") {
|
|
3022
|
+
return {
|
|
3023
|
+
attempted: false,
|
|
3024
|
+
autostart: status
|
|
3025
|
+
};
|
|
3026
|
+
}
|
|
3027
|
+
try {
|
|
3028
|
+
const autostart = resolved.installAutostart();
|
|
3029
|
+
return {
|
|
3030
|
+
attempted: true,
|
|
3031
|
+
autostart,
|
|
3032
|
+
autostartAction: status.health === "missing" ? "installed" : "repaired"
|
|
3033
|
+
};
|
|
3034
|
+
} catch (error) {
|
|
3035
|
+
let autostart = status;
|
|
3036
|
+
try {
|
|
3037
|
+
autostart = resolved.getAutostartStatus();
|
|
3038
|
+
} catch {
|
|
3039
|
+
autostart = status;
|
|
3040
|
+
}
|
|
3041
|
+
return {
|
|
3042
|
+
attempted: true,
|
|
3043
|
+
autostart,
|
|
3044
|
+
autostartAction: "repair_failed",
|
|
3045
|
+
autostartError: error instanceof Error ? error.message : String(error)
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
// src/cli/install-autostart-output.ts
|
|
3051
|
+
function createInstallAutostartOutputPayload(result) {
|
|
3052
|
+
if (!result) {
|
|
3053
|
+
return {};
|
|
3054
|
+
}
|
|
3055
|
+
return {
|
|
3056
|
+
autostart: result.autostart,
|
|
3057
|
+
autostartAction: result.autostartAction,
|
|
3058
|
+
...result.autostartAction === "repair_failed" && result.autostartError ? { autostartError: result.autostartError } : {}
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
function formatAutostartReconciliationMessage(result) {
|
|
3062
|
+
switch (result.autostartAction) {
|
|
3063
|
+
case "unsupported":
|
|
3064
|
+
return result.autostart ? `Autostart not supported on ${result.autostart.platform}.` : "Autostart not supported on this platform.";
|
|
3065
|
+
case "already_healthy":
|
|
3066
|
+
return "Autostart already healthy.";
|
|
3067
|
+
case "installed":
|
|
3068
|
+
return result.autostart ? `Autostart installed (${result.autostart.platform}).` : "Autostart installed.";
|
|
3069
|
+
case "repaired":
|
|
3070
|
+
return result.autostart ? `Autostart repaired (${result.autostart.platform}).` : "Autostart repaired.";
|
|
3071
|
+
case "repair_failed":
|
|
3072
|
+
if (result.autostartError && isTransientAutostartInstallError(result.autostartError)) {
|
|
3073
|
+
return `Plugin install succeeded but autostart repair was skipped because the current CLI path is transient: ${result.autostartError}`;
|
|
3074
|
+
}
|
|
3075
|
+
return `Plugin install succeeded but autostart repair failed: ${result.autostartError ?? "unknown error"}. Run opendevbrowser daemon install to repair it.`;
|
|
3076
|
+
default:
|
|
3077
|
+
return null;
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
|
|
2470
3081
|
// src/cli/commands/run.ts
|
|
2471
3082
|
import { readFileSync as readFileSync4 } from "fs";
|
|
2472
3083
|
|
|
2473
3084
|
// src/cli/output.ts
|
|
3085
|
+
var normalizeExitCode = (code) => {
|
|
3086
|
+
return Number.isInteger(code) ? Number(code) : 0;
|
|
3087
|
+
};
|
|
3088
|
+
var flushStream = (stream) => {
|
|
3089
|
+
return new Promise((resolve6) => {
|
|
3090
|
+
if (!stream || typeof stream.write !== "function") {
|
|
3091
|
+
resolve6();
|
|
3092
|
+
return;
|
|
3093
|
+
}
|
|
3094
|
+
try {
|
|
3095
|
+
stream.write("", () => resolve6());
|
|
3096
|
+
} catch {
|
|
3097
|
+
resolve6();
|
|
3098
|
+
}
|
|
3099
|
+
});
|
|
3100
|
+
};
|
|
3101
|
+
async function flushOutputAndExit(code, proc = process, timeoutMs = 250) {
|
|
3102
|
+
const finalCode = normalizeExitCode(code);
|
|
3103
|
+
proc.exitCode = finalCode;
|
|
3104
|
+
await new Promise((resolve6) => {
|
|
3105
|
+
let settled = false;
|
|
3106
|
+
const finish = () => {
|
|
3107
|
+
if (settled) return;
|
|
3108
|
+
settled = true;
|
|
3109
|
+
resolve6();
|
|
3110
|
+
};
|
|
3111
|
+
const timer = setTimeout(finish, Math.max(0, timeoutMs));
|
|
3112
|
+
timer.unref?.();
|
|
3113
|
+
void Promise.allSettled([flushStream(proc.stdout), flushStream(proc.stderr)]).finally(() => {
|
|
3114
|
+
clearTimeout(timer);
|
|
3115
|
+
finish();
|
|
3116
|
+
});
|
|
3117
|
+
});
|
|
3118
|
+
proc.exit(finalCode);
|
|
3119
|
+
}
|
|
2474
3120
|
function writeOutput(payload, options) {
|
|
2475
3121
|
if (options.quiet) {
|
|
2476
3122
|
return;
|
|
@@ -2526,7 +3172,19 @@ function parseRunArgs(rawArgs) {
|
|
|
2526
3172
|
continue;
|
|
2527
3173
|
}
|
|
2528
3174
|
if (arg === "--persist-profile") {
|
|
2529
|
-
|
|
3175
|
+
const value = rawArgs[i + 1];
|
|
3176
|
+
if (value && !value.startsWith("--")) {
|
|
3177
|
+
parsed.persistProfile = parseBooleanFlag(value, "--persist-profile");
|
|
3178
|
+
i += 1;
|
|
3179
|
+
} else {
|
|
3180
|
+
parsed.persistProfile = true;
|
|
3181
|
+
}
|
|
3182
|
+
continue;
|
|
3183
|
+
}
|
|
3184
|
+
if (arg?.startsWith("--persist-profile=")) {
|
|
3185
|
+
const value = arg.split("=", 2)[1];
|
|
3186
|
+
if (!value) throw createUsageError("Missing value for --persist-profile");
|
|
3187
|
+
parsed.persistProfile = parseBooleanFlag(value, "--persist-profile");
|
|
2530
3188
|
continue;
|
|
2531
3189
|
}
|
|
2532
3190
|
if (arg === "--chrome-path") {
|
|
@@ -2613,7 +3271,7 @@ async function runScriptCommand(args) {
|
|
|
2613
3271
|
startUrl: runArgs.startUrl,
|
|
2614
3272
|
chromePath: runArgs.chromePath,
|
|
2615
3273
|
flags: runArgs.flags.length ? runArgs.flags : void 0,
|
|
2616
|
-
persistProfile: runArgs.persistProfile
|
|
3274
|
+
persistProfile: runArgs.persistProfile ?? false
|
|
2617
3275
|
});
|
|
2618
3276
|
try {
|
|
2619
3277
|
const result = await core.runner.run(launchResult.sessionId, steps, true);
|
|
@@ -2632,13 +3290,8 @@ async function runScriptCommand(args) {
|
|
|
2632
3290
|
|
|
2633
3291
|
// src/cli/commands/session/launch.ts
|
|
2634
3292
|
var MIN_LAUNCH_CALL_TIMEOUT_MS = 3e4;
|
|
3293
|
+
var MANAGED_HEADED_LAUNCH_CALL_TIMEOUT_MS = 6e4;
|
|
2635
3294
|
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
|
-
};
|
|
2642
3295
|
function parseLaunchArgs(rawArgs) {
|
|
2643
3296
|
const parsed = { flags: [] };
|
|
2644
3297
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
@@ -2743,7 +3396,8 @@ function parseLaunchArgs(rawArgs) {
|
|
|
2743
3396
|
}
|
|
2744
3397
|
function deriveLaunchCallTimeoutMs(launchArgs) {
|
|
2745
3398
|
const waitHintMs = typeof launchArgs.waitTimeoutMs === "number" ? launchArgs.waitTimeoutMs + LAUNCH_CALL_TIMEOUT_BUFFER_MS : 0;
|
|
2746
|
-
|
|
3399
|
+
const managedHeadedHintMs = launchArgs.noExtension && launchArgs.headless !== true ? MANAGED_HEADED_LAUNCH_CALL_TIMEOUT_MS : 0;
|
|
3400
|
+
return Math.max(MIN_LAUNCH_CALL_TIMEOUT_MS, waitHintMs, managedHeadedHintMs);
|
|
2747
3401
|
}
|
|
2748
3402
|
async function runSessionLaunch(args) {
|
|
2749
3403
|
const launchArgs = parseLaunchArgs(args.rawArgs);
|
|
@@ -2829,6 +3483,7 @@ function promptYesNo(question, defaultYes) {
|
|
|
2829
3483
|
}
|
|
2830
3484
|
|
|
2831
3485
|
// src/cli/commands/session/connect.ts
|
|
3486
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
|
|
2832
3487
|
function parseConnectArgs(rawArgs) {
|
|
2833
3488
|
const parsed = {};
|
|
2834
3489
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
@@ -2896,7 +3551,9 @@ function parseConnectArgs(rawArgs) {
|
|
|
2896
3551
|
}
|
|
2897
3552
|
async function runSessionConnect(args) {
|
|
2898
3553
|
const connectArgs = parseConnectArgs(args.rawArgs);
|
|
2899
|
-
const result = await callDaemon("session.connect", connectArgs
|
|
3554
|
+
const result = await callDaemon("session.connect", connectArgs, {
|
|
3555
|
+
timeoutMs: DEFAULT_CONNECT_TIMEOUT_MS
|
|
3556
|
+
});
|
|
2900
3557
|
return {
|
|
2901
3558
|
success: true,
|
|
2902
3559
|
message: `Session connected: ${result.sessionId}`,
|
|
@@ -2932,10 +3589,120 @@ async function runSessionDisconnect(args) {
|
|
|
2932
3589
|
if (!sessionId) {
|
|
2933
3590
|
throw createUsageError("Missing --session-id");
|
|
2934
3591
|
}
|
|
2935
|
-
|
|
3592
|
+
const timeoutMs = closeBrowser ? 12e4 : 2e4;
|
|
3593
|
+
await callDaemon("session.disconnect", { sessionId, closeBrowser }, { timeoutMs });
|
|
2936
3594
|
return { success: true, message: `Session disconnected: ${sessionId}` };
|
|
2937
3595
|
}
|
|
2938
3596
|
|
|
3597
|
+
// src/cli/commands/session/inspector.ts
|
|
3598
|
+
function parseSessionInspectorArgs(rawArgs) {
|
|
3599
|
+
const parsed = {};
|
|
3600
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
3601
|
+
const arg = rawArgs[index];
|
|
3602
|
+
if (arg === "--session-id") {
|
|
3603
|
+
const value = rawArgs[index + 1];
|
|
3604
|
+
if (!value) throw createUsageError("Missing value for --session-id");
|
|
3605
|
+
parsed.sessionId = value;
|
|
3606
|
+
index += 1;
|
|
3607
|
+
continue;
|
|
3608
|
+
}
|
|
3609
|
+
if (arg?.startsWith("--session-id=")) {
|
|
3610
|
+
parsed.sessionId = arg.split("=", 2)[1];
|
|
3611
|
+
continue;
|
|
3612
|
+
}
|
|
3613
|
+
if (arg === "--include-urls") {
|
|
3614
|
+
parsed.includeUrls = true;
|
|
3615
|
+
continue;
|
|
3616
|
+
}
|
|
3617
|
+
if (arg === "--since-console-seq") {
|
|
3618
|
+
const value = rawArgs[index + 1];
|
|
3619
|
+
if (!value) throw createUsageError("Missing value for --since-console-seq");
|
|
3620
|
+
parsed.sinceConsoleSeq = parseNumberFlag(value, "--since-console-seq", { min: 0 });
|
|
3621
|
+
index += 1;
|
|
3622
|
+
continue;
|
|
3623
|
+
}
|
|
3624
|
+
if (arg?.startsWith("--since-console-seq=")) {
|
|
3625
|
+
const value = arg.split("=", 2)[1];
|
|
3626
|
+
if (!value) throw createUsageError("Missing value for --since-console-seq");
|
|
3627
|
+
parsed.sinceConsoleSeq = parseNumberFlag(value, "--since-console-seq", { min: 0 });
|
|
3628
|
+
continue;
|
|
3629
|
+
}
|
|
3630
|
+
if (arg === "--since-network-seq") {
|
|
3631
|
+
const value = rawArgs[index + 1];
|
|
3632
|
+
if (!value) throw createUsageError("Missing value for --since-network-seq");
|
|
3633
|
+
parsed.sinceNetworkSeq = parseNumberFlag(value, "--since-network-seq", { min: 0 });
|
|
3634
|
+
index += 1;
|
|
3635
|
+
continue;
|
|
3636
|
+
}
|
|
3637
|
+
if (arg?.startsWith("--since-network-seq=")) {
|
|
3638
|
+
const value = arg.split("=", 2)[1];
|
|
3639
|
+
if (!value) throw createUsageError("Missing value for --since-network-seq");
|
|
3640
|
+
parsed.sinceNetworkSeq = parseNumberFlag(value, "--since-network-seq", { min: 0 });
|
|
3641
|
+
continue;
|
|
3642
|
+
}
|
|
3643
|
+
if (arg === "--since-exception-seq") {
|
|
3644
|
+
const value = rawArgs[index + 1];
|
|
3645
|
+
if (!value) throw createUsageError("Missing value for --since-exception-seq");
|
|
3646
|
+
parsed.sinceExceptionSeq = parseNumberFlag(value, "--since-exception-seq", { min: 0 });
|
|
3647
|
+
index += 1;
|
|
3648
|
+
continue;
|
|
3649
|
+
}
|
|
3650
|
+
if (arg?.startsWith("--since-exception-seq=")) {
|
|
3651
|
+
const value = arg.split("=", 2)[1];
|
|
3652
|
+
if (!value) throw createUsageError("Missing value for --since-exception-seq");
|
|
3653
|
+
parsed.sinceExceptionSeq = parseNumberFlag(value, "--since-exception-seq", { min: 0 });
|
|
3654
|
+
continue;
|
|
3655
|
+
}
|
|
3656
|
+
if (arg === "--max") {
|
|
3657
|
+
const value = rawArgs[index + 1];
|
|
3658
|
+
if (!value) throw createUsageError("Missing value for --max");
|
|
3659
|
+
parsed.max = parseNumberFlag(value, "--max", { min: 1 });
|
|
3660
|
+
index += 1;
|
|
3661
|
+
continue;
|
|
3662
|
+
}
|
|
3663
|
+
if (arg?.startsWith("--max=")) {
|
|
3664
|
+
const value = arg.split("=", 2)[1];
|
|
3665
|
+
if (!value) throw createUsageError("Missing value for --max");
|
|
3666
|
+
parsed.max = parseNumberFlag(value, "--max", { min: 1 });
|
|
3667
|
+
continue;
|
|
3668
|
+
}
|
|
3669
|
+
if (arg === "--request-id") {
|
|
3670
|
+
const value = rawArgs[index + 1];
|
|
3671
|
+
if (!value) throw createUsageError("Missing value for --request-id");
|
|
3672
|
+
parsed.requestId = value;
|
|
3673
|
+
index += 1;
|
|
3674
|
+
continue;
|
|
3675
|
+
}
|
|
3676
|
+
if (arg?.startsWith("--request-id=")) {
|
|
3677
|
+
const value = arg.split("=", 2)[1];
|
|
3678
|
+
if (!value) throw createUsageError("Missing value for --request-id");
|
|
3679
|
+
parsed.requestId = value;
|
|
3680
|
+
continue;
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
return parsed;
|
|
3684
|
+
}
|
|
3685
|
+
async function runSessionInspector(args) {
|
|
3686
|
+
const parsed = parseSessionInspectorArgs(args.rawArgs);
|
|
3687
|
+
if (!parsed.sessionId) {
|
|
3688
|
+
throw createUsageError("Missing --session-id");
|
|
3689
|
+
}
|
|
3690
|
+
const result = await callDaemon("session.inspect", {
|
|
3691
|
+
sessionId: parsed.sessionId,
|
|
3692
|
+
...typeof parsed.includeUrls === "boolean" ? { includeUrls: parsed.includeUrls } : {},
|
|
3693
|
+
sinceConsoleSeq: parsed.sinceConsoleSeq,
|
|
3694
|
+
sinceNetworkSeq: parsed.sinceNetworkSeq,
|
|
3695
|
+
sinceExceptionSeq: parsed.sinceExceptionSeq,
|
|
3696
|
+
max: parsed.max,
|
|
3697
|
+
requestId: parsed.requestId
|
|
3698
|
+
});
|
|
3699
|
+
return {
|
|
3700
|
+
success: true,
|
|
3701
|
+
message: "Session inspector snapshot captured.",
|
|
3702
|
+
data: result
|
|
3703
|
+
};
|
|
3704
|
+
}
|
|
3705
|
+
|
|
2939
3706
|
// src/cli/commands/session/status.ts
|
|
2940
3707
|
function parseStatusArgs(rawArgs) {
|
|
2941
3708
|
const parsed = {};
|
|
@@ -2965,6 +3732,11 @@ async function runSessionStatus(args) {
|
|
|
2965
3732
|
}
|
|
2966
3733
|
|
|
2967
3734
|
// src/cli/commands/status.ts
|
|
3735
|
+
var DAEMON_STATUS_READ_OPTIONS = {
|
|
3736
|
+
timeoutMs: 5e3,
|
|
3737
|
+
retryAttempts: 5,
|
|
3738
|
+
retryDelayMs: 250
|
|
3739
|
+
};
|
|
2968
3740
|
var parseStatusArgs2 = (rawArgs) => {
|
|
2969
3741
|
const parsed = { daemon: false };
|
|
2970
3742
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
@@ -2997,41 +3769,31 @@ async function runStatus(args) {
|
|
|
2997
3769
|
}
|
|
2998
3770
|
if (!daemon && args.transport === "native") {
|
|
2999
3771
|
const nativeStatus2 = getNativeStatusSnapshot();
|
|
3000
|
-
|
|
3001
|
-
return {
|
|
3002
|
-
success: false,
|
|
3003
|
-
message: "Native host not installed.",
|
|
3004
|
-
data: nativeStatus2,
|
|
3005
|
-
exitCode: EXIT_DISCONNECTED
|
|
3006
|
-
};
|
|
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
|
-
}
|
|
3772
|
+
const assessment = assessNativeStatus(nativeStatus2);
|
|
3016
3773
|
return {
|
|
3017
|
-
success:
|
|
3018
|
-
message:
|
|
3019
|
-
data: nativeStatus2
|
|
3774
|
+
success: assessment.success,
|
|
3775
|
+
message: assessment.message,
|
|
3776
|
+
data: nativeStatus2,
|
|
3777
|
+
exitCode: assessment.exitCode ?? void 0
|
|
3020
3778
|
};
|
|
3021
3779
|
}
|
|
3022
|
-
const daemonStatus = await fetchDaemonStatusFromMetadata();
|
|
3780
|
+
const daemonStatus = await fetchDaemonStatusFromMetadata(void 0, DAEMON_STATUS_READ_OPTIONS);
|
|
3023
3781
|
if (!daemonStatus) {
|
|
3024
3782
|
throw createUsageError("Daemon not running. Start with `opendevbrowser serve`.");
|
|
3025
3783
|
}
|
|
3026
3784
|
const nativeStatus = getNativeStatusSnapshot();
|
|
3027
|
-
const
|
|
3028
|
-
const
|
|
3785
|
+
const nativeAssessment = assessNativeStatus(nativeStatus);
|
|
3786
|
+
const baseLines = [
|
|
3029
3787
|
`Daemon OK (pid=${daemonStatus.pid})`,
|
|
3030
3788
|
`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: ${
|
|
3789
|
+
`Native: ${nativeAssessment.summary}`,
|
|
3032
3790
|
daemonStatus.relay.lastHandshakeError ? `Relay last handshake error: ${daemonStatus.relay.lastHandshakeError.code} (${daemonStatus.relay.lastHandshakeError.message})` : "Relay last handshake error: none",
|
|
3033
3791
|
"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"
|
|
3034
|
-
]
|
|
3792
|
+
];
|
|
3793
|
+
if (!nativeAssessment.success) {
|
|
3794
|
+
baseLines.splice(3, 0, `Native detail: ${nativeAssessment.message}`);
|
|
3795
|
+
}
|
|
3796
|
+
const baseMessage = baseLines.join("\n");
|
|
3035
3797
|
const message = daemon || args.outputFormat !== "text" ? baseMessage : [
|
|
3036
3798
|
"Warning: `status` defaults to daemon status. Use --daemon explicitly or --session-id for session status.",
|
|
3037
3799
|
baseMessage
|
|
@@ -3135,30 +3897,119 @@ function parseWaitArgs(rawArgs) {
|
|
|
3135
3897
|
i += 1;
|
|
3136
3898
|
continue;
|
|
3137
3899
|
}
|
|
3138
|
-
if (arg?.startsWith("--ref=")) {
|
|
3139
|
-
parsed.ref = arg.split("=", 2)[1];
|
|
3900
|
+
if (arg?.startsWith("--ref=")) {
|
|
3901
|
+
parsed.ref = arg.split("=", 2)[1];
|
|
3902
|
+
continue;
|
|
3903
|
+
}
|
|
3904
|
+
if (arg === "--state") {
|
|
3905
|
+
const value = rawArgs[i + 1];
|
|
3906
|
+
if (!value) throw createUsageError("Missing value for --state");
|
|
3907
|
+
parsed.state = value;
|
|
3908
|
+
i += 1;
|
|
3909
|
+
continue;
|
|
3910
|
+
}
|
|
3911
|
+
if (arg?.startsWith("--state=")) {
|
|
3912
|
+
parsed.state = arg.split("=", 2)[1];
|
|
3913
|
+
continue;
|
|
3914
|
+
}
|
|
3915
|
+
if (arg === "--until") {
|
|
3916
|
+
const value = rawArgs[i + 1];
|
|
3917
|
+
if (!value) throw createUsageError("Missing value for --until");
|
|
3918
|
+
parsed.until = value;
|
|
3919
|
+
i += 1;
|
|
3920
|
+
continue;
|
|
3921
|
+
}
|
|
3922
|
+
if (arg?.startsWith("--until=")) {
|
|
3923
|
+
parsed.until = arg.split("=", 2)[1];
|
|
3924
|
+
continue;
|
|
3925
|
+
}
|
|
3926
|
+
if (arg === "--timeout-ms") {
|
|
3927
|
+
const value = rawArgs[i + 1];
|
|
3928
|
+
if (!value) throw createUsageError("Missing value for --timeout-ms");
|
|
3929
|
+
parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
|
|
3930
|
+
i += 1;
|
|
3931
|
+
continue;
|
|
3932
|
+
}
|
|
3933
|
+
if (arg?.startsWith("--timeout-ms=")) {
|
|
3934
|
+
const value = arg.split("=", 2)[1];
|
|
3935
|
+
if (!value) throw createUsageError("Missing value for --timeout-ms");
|
|
3936
|
+
parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
|
|
3937
|
+
continue;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
return parsed;
|
|
3941
|
+
}
|
|
3942
|
+
async function runWait(args) {
|
|
3943
|
+
const { sessionId, ref, state, until, timeoutMs } = parseWaitArgs(args.rawArgs);
|
|
3944
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
3945
|
+
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
3946
|
+
const result = await callDaemon("nav.wait", {
|
|
3947
|
+
sessionId,
|
|
3948
|
+
ref,
|
|
3949
|
+
state,
|
|
3950
|
+
until,
|
|
3951
|
+
timeoutMs,
|
|
3952
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
3953
|
+
});
|
|
3954
|
+
return { success: true, message: "Wait complete.", data: result };
|
|
3955
|
+
}
|
|
3956
|
+
|
|
3957
|
+
// src/cli/transport-timeouts.ts
|
|
3958
|
+
var DEFAULT_CLICK_TRANSPORT_TIMEOUT_MS = 6e4;
|
|
3959
|
+
var DEFAULT_DIALOG_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3960
|
+
var DEFAULT_TARGET_CREATION_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3961
|
+
var DEFAULT_SNAPSHOT_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3962
|
+
var DEFAULT_REVIEW_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3963
|
+
var DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS = 3e4;
|
|
3964
|
+
var DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS = 12e4;
|
|
3965
|
+
|
|
3966
|
+
// src/cli/commands/nav/snapshot.ts
|
|
3967
|
+
function parseSnapshotArgs(rawArgs) {
|
|
3968
|
+
const parsed = {};
|
|
3969
|
+
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
3970
|
+
const arg = rawArgs[i];
|
|
3971
|
+
if (arg === "--session-id") {
|
|
3972
|
+
const value = rawArgs[i + 1];
|
|
3973
|
+
if (!value) throw createUsageError("Missing value for --session-id");
|
|
3974
|
+
parsed.sessionId = value;
|
|
3975
|
+
i += 1;
|
|
3976
|
+
continue;
|
|
3977
|
+
}
|
|
3978
|
+
if (arg?.startsWith("--session-id=")) {
|
|
3979
|
+
parsed.sessionId = arg.split("=", 2)[1];
|
|
3980
|
+
continue;
|
|
3981
|
+
}
|
|
3982
|
+
if (arg === "--mode") {
|
|
3983
|
+
const value = rawArgs[i + 1];
|
|
3984
|
+
if (!value) throw createUsageError("Missing value for --mode");
|
|
3985
|
+
parsed.mode = value;
|
|
3986
|
+
i += 1;
|
|
3987
|
+
continue;
|
|
3988
|
+
}
|
|
3989
|
+
if (arg?.startsWith("--mode=")) {
|
|
3990
|
+
parsed.mode = arg.split("=", 2)[1];
|
|
3140
3991
|
continue;
|
|
3141
3992
|
}
|
|
3142
|
-
if (arg === "--
|
|
3993
|
+
if (arg === "--max-chars") {
|
|
3143
3994
|
const value = rawArgs[i + 1];
|
|
3144
|
-
if (!value) throw createUsageError("Missing value for --
|
|
3145
|
-
parsed.
|
|
3995
|
+
if (!value) throw createUsageError("Missing value for --max-chars");
|
|
3996
|
+
parsed.maxChars = Number(value);
|
|
3146
3997
|
i += 1;
|
|
3147
3998
|
continue;
|
|
3148
3999
|
}
|
|
3149
|
-
if (arg?.startsWith("--
|
|
3150
|
-
parsed.
|
|
4000
|
+
if (arg?.startsWith("--max-chars=")) {
|
|
4001
|
+
parsed.maxChars = Number(arg.split("=", 2)[1]);
|
|
3151
4002
|
continue;
|
|
3152
4003
|
}
|
|
3153
|
-
if (arg === "--
|
|
4004
|
+
if (arg === "--cursor") {
|
|
3154
4005
|
const value = rawArgs[i + 1];
|
|
3155
|
-
if (!value) throw createUsageError("Missing value for --
|
|
3156
|
-
parsed.
|
|
4006
|
+
if (!value) throw createUsageError("Missing value for --cursor");
|
|
4007
|
+
parsed.cursor = value;
|
|
3157
4008
|
i += 1;
|
|
3158
4009
|
continue;
|
|
3159
4010
|
}
|
|
3160
|
-
if (arg?.startsWith("--
|
|
3161
|
-
parsed.
|
|
4011
|
+
if (arg?.startsWith("--cursor=")) {
|
|
4012
|
+
parsed.cursor = arg.split("=", 2)[1];
|
|
3162
4013
|
continue;
|
|
3163
4014
|
}
|
|
3164
4015
|
if (arg === "--timeout-ms") {
|
|
@@ -3172,28 +4023,29 @@ function parseWaitArgs(rawArgs) {
|
|
|
3172
4023
|
const value = arg.split("=", 2)[1];
|
|
3173
4024
|
if (!value) throw createUsageError("Missing value for --timeout-ms");
|
|
3174
4025
|
parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
|
|
3175
|
-
continue;
|
|
3176
4026
|
}
|
|
3177
4027
|
}
|
|
3178
4028
|
return parsed;
|
|
3179
4029
|
}
|
|
3180
|
-
async function
|
|
3181
|
-
const { sessionId,
|
|
4030
|
+
async function runSnapshot(args) {
|
|
4031
|
+
const { sessionId, mode, maxChars, cursor, timeoutMs } = parseSnapshotArgs(args.rawArgs);
|
|
3182
4032
|
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
3183
4033
|
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
3184
|
-
const
|
|
4034
|
+
const payload = {
|
|
3185
4035
|
sessionId,
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
timeoutMs,
|
|
4036
|
+
mode,
|
|
4037
|
+
maxChars,
|
|
4038
|
+
cursor,
|
|
3190
4039
|
...typeof targetId === "string" ? { targetId } : {}
|
|
4040
|
+
};
|
|
4041
|
+
const result = await callDaemon("nav.snapshot", payload, {
|
|
4042
|
+
timeoutMs: timeoutMs ?? DEFAULT_SNAPSHOT_TRANSPORT_TIMEOUT_MS
|
|
3191
4043
|
});
|
|
3192
|
-
return { success: true, message: "
|
|
4044
|
+
return { success: true, message: "Snapshot captured.", data: result };
|
|
3193
4045
|
}
|
|
3194
4046
|
|
|
3195
|
-
// src/cli/commands/nav/
|
|
3196
|
-
function
|
|
4047
|
+
// src/cli/commands/nav/review.ts
|
|
4048
|
+
function parseReviewArgs(rawArgs) {
|
|
3197
4049
|
const parsed = {};
|
|
3198
4050
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
3199
4051
|
const arg = rawArgs[i];
|
|
@@ -3208,17 +4060,6 @@ function parseSnapshotArgs(rawArgs) {
|
|
|
3208
4060
|
parsed.sessionId = arg.split("=", 2)[1];
|
|
3209
4061
|
continue;
|
|
3210
4062
|
}
|
|
3211
|
-
if (arg === "--mode") {
|
|
3212
|
-
const value = rawArgs[i + 1];
|
|
3213
|
-
if (!value) throw createUsageError("Missing value for --mode");
|
|
3214
|
-
parsed.mode = value;
|
|
3215
|
-
i += 1;
|
|
3216
|
-
continue;
|
|
3217
|
-
}
|
|
3218
|
-
if (arg?.startsWith("--mode=")) {
|
|
3219
|
-
parsed.mode = arg.split("=", 2)[1];
|
|
3220
|
-
continue;
|
|
3221
|
-
}
|
|
3222
4063
|
if (arg === "--max-chars") {
|
|
3223
4064
|
const value = rawArgs[i + 1];
|
|
3224
4065
|
if (!value) throw createUsageError("Missing value for --max-chars");
|
|
@@ -3241,21 +4082,35 @@ function parseSnapshotArgs(rawArgs) {
|
|
|
3241
4082
|
parsed.cursor = arg.split("=", 2)[1];
|
|
3242
4083
|
continue;
|
|
3243
4084
|
}
|
|
4085
|
+
if (arg === "--timeout-ms") {
|
|
4086
|
+
const value = rawArgs[i + 1];
|
|
4087
|
+
if (!value) throw createUsageError("Missing value for --timeout-ms");
|
|
4088
|
+
parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
|
|
4089
|
+
i += 1;
|
|
4090
|
+
continue;
|
|
4091
|
+
}
|
|
4092
|
+
if (arg?.startsWith("--timeout-ms=")) {
|
|
4093
|
+
const value = arg.split("=", 2)[1];
|
|
4094
|
+
if (!value) throw createUsageError("Missing value for --timeout-ms");
|
|
4095
|
+
parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
|
|
4096
|
+
}
|
|
3244
4097
|
}
|
|
3245
4098
|
return parsed;
|
|
3246
4099
|
}
|
|
3247
|
-
async function
|
|
3248
|
-
const { sessionId,
|
|
4100
|
+
async function runReview(args) {
|
|
4101
|
+
const { sessionId, maxChars, cursor, timeoutMs } = parseReviewArgs(args.rawArgs);
|
|
3249
4102
|
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
3250
4103
|
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
3251
|
-
const
|
|
4104
|
+
const payload = {
|
|
3252
4105
|
sessionId,
|
|
3253
|
-
mode,
|
|
3254
4106
|
maxChars,
|
|
3255
4107
|
cursor,
|
|
3256
4108
|
...typeof targetId === "string" ? { targetId } : {}
|
|
4109
|
+
};
|
|
4110
|
+
const result = await callDaemon("nav.review", payload, {
|
|
4111
|
+
timeoutMs: timeoutMs ?? DEFAULT_REVIEW_TRANSPORT_TIMEOUT_MS
|
|
3257
4112
|
});
|
|
3258
|
-
return { success: true, message: "
|
|
4113
|
+
return { success: true, message: "Review captured.", data: result };
|
|
3259
4114
|
}
|
|
3260
4115
|
|
|
3261
4116
|
// src/cli/commands/annotate.ts
|
|
@@ -3435,8 +4290,6 @@ async function runAnnotate(args) {
|
|
|
3435
4290
|
// src/cli/commands/canvas.ts
|
|
3436
4291
|
import { readFileSync as readFileSync5 } from "fs";
|
|
3437
4292
|
var DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS = 3e4;
|
|
3438
|
-
var MIN_FEEDBACK_STREAM_POLL_MS = 250;
|
|
3439
|
-
var MAX_FEEDBACK_STREAM_POLL_MS = 1e3;
|
|
3440
4293
|
var isRecord = (value) => {
|
|
3441
4294
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3442
4295
|
};
|
|
@@ -3449,23 +4302,23 @@ var asNumber = (value) => {
|
|
|
3449
4302
|
var asRecordArray = (value) => {
|
|
3450
4303
|
return Array.isArray(value) ? value.filter(isRecord) : [];
|
|
3451
4304
|
};
|
|
3452
|
-
var
|
|
3453
|
-
await new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
3454
|
-
};
|
|
3455
|
-
var toFeedbackPollResult = (value) => {
|
|
4305
|
+
var toFeedbackSubscribeResult = (value) => {
|
|
3456
4306
|
if (!isRecord(value)) {
|
|
3457
|
-
return {
|
|
4307
|
+
return {
|
|
4308
|
+
subscriptionId: null,
|
|
4309
|
+
initialItems: [],
|
|
4310
|
+
cursor: null,
|
|
4311
|
+
heartbeatMs: 15e3
|
|
4312
|
+
};
|
|
3458
4313
|
}
|
|
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
4314
|
return {
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
4315
|
+
subscriptionId: asString(value.subscriptionId),
|
|
4316
|
+
initialItems: asRecordArray(value.initialItems),
|
|
4317
|
+
cursor: asString(value.cursor),
|
|
4318
|
+
heartbeatMs: Math.max(asNumber(value.heartbeatMs) ?? 15e3, 1e3)
|
|
3466
4319
|
};
|
|
3467
4320
|
};
|
|
3468
|
-
async function
|
|
4321
|
+
async function streamFeedbackViaSubscription(client, args, canvasArgs, params, initial) {
|
|
3469
4322
|
const outputOptions = { format: args.outputFormat, quiet: args.quiet };
|
|
3470
4323
|
writeOutput({
|
|
3471
4324
|
success: true,
|
|
@@ -3475,86 +4328,95 @@ async function streamFeedbackViaPolling(client, args, canvasArgs, params, initia
|
|
|
3475
4328
|
result: initial
|
|
3476
4329
|
}
|
|
3477
4330
|
}, outputOptions);
|
|
3478
|
-
const
|
|
3479
|
-
const
|
|
3480
|
-
|
|
3481
|
-
Math.max(MIN_FEEDBACK_STREAM_POLL_MS, Math.floor(heartbeatMs / 3))
|
|
3482
|
-
);
|
|
4331
|
+
const initialResult = toFeedbackSubscribeResult(initial);
|
|
4332
|
+
const subscriptionId = initialResult.subscriptionId;
|
|
4333
|
+
const heartbeatMs = initialResult.heartbeatMs;
|
|
3483
4334
|
const streamTimeoutMs = canvasArgs.timeoutMs ?? DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS;
|
|
3484
4335
|
const deadline = Date.now() + streamTimeoutMs;
|
|
3485
|
-
let cursor =
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
4336
|
+
let cursor = initialResult.cursor;
|
|
4337
|
+
for (const item of initialResult.initialItems) {
|
|
4338
|
+
const itemCursor = asString(item.cursor);
|
|
4339
|
+
if (itemCursor) {
|
|
4340
|
+
cursor = itemCursor;
|
|
4341
|
+
}
|
|
4342
|
+
writeOutput({
|
|
4343
|
+
success: true,
|
|
4344
|
+
message: `Canvas feedback: ${canvasArgs.command}`,
|
|
4345
|
+
data: {
|
|
4346
|
+
command: canvasArgs.command,
|
|
4347
|
+
streamEvent: {
|
|
4348
|
+
eventType: "feedback.item",
|
|
4349
|
+
item
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
}, outputOptions);
|
|
4353
|
+
}
|
|
4354
|
+
while (subscriptionId && Date.now() < deadline) {
|
|
3489
4355
|
const remainingMs = deadline - Date.now();
|
|
3490
4356
|
if (remainingMs <= 0) {
|
|
3491
4357
|
break;
|
|
3492
4358
|
}
|
|
3493
|
-
const
|
|
4359
|
+
const nextEvent = await client.call(
|
|
3494
4360
|
"canvas.execute",
|
|
3495
4361
|
{
|
|
3496
|
-
command: "canvas.feedback.
|
|
4362
|
+
command: "canvas.feedback.next",
|
|
3497
4363
|
params: {
|
|
3498
4364
|
...params,
|
|
3499
|
-
|
|
4365
|
+
subscriptionId,
|
|
4366
|
+
timeoutMs: Math.min(heartbeatMs, remainingMs)
|
|
3500
4367
|
}
|
|
3501
4368
|
},
|
|
3502
4369
|
{ timeoutMs: remainingMs }
|
|
3503
|
-
)
|
|
3504
|
-
if (
|
|
3505
|
-
|
|
3506
|
-
const itemCursor = asString(item.cursor);
|
|
4370
|
+
);
|
|
4371
|
+
if (isRecord(nextEvent)) {
|
|
4372
|
+
if (nextEvent.eventType === "feedback.item" && isRecord(nextEvent.item)) {
|
|
4373
|
+
const itemCursor = asString(nextEvent.item.cursor);
|
|
3507
4374
|
if (itemCursor) {
|
|
3508
4375
|
cursor = itemCursor;
|
|
3509
4376
|
}
|
|
3510
|
-
|
|
3511
|
-
|
|
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);
|
|
4377
|
+
} else if (typeof nextEvent.cursor === "string") {
|
|
4378
|
+
cursor = nextEvent.cursor;
|
|
3522
4379
|
}
|
|
3523
|
-
lastHeartbeatAt = Date.now();
|
|
3524
|
-
continue;
|
|
3525
4380
|
}
|
|
3526
|
-
|
|
3527
|
-
|
|
4381
|
+
writeOutput({
|
|
4382
|
+
success: true,
|
|
4383
|
+
message: `Canvas feedback: ${canvasArgs.command}`,
|
|
4384
|
+
data: {
|
|
4385
|
+
command: canvasArgs.command,
|
|
4386
|
+
streamEvent: nextEvent
|
|
4387
|
+
}
|
|
4388
|
+
}, outputOptions);
|
|
4389
|
+
if (isRecord(nextEvent) && nextEvent.eventType === "feedback.complete") {
|
|
4390
|
+
break;
|
|
3528
4391
|
}
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
}
|
|
4392
|
+
}
|
|
4393
|
+
if (Date.now() >= deadline) {
|
|
4394
|
+
writeOutput({
|
|
4395
|
+
success: true,
|
|
4396
|
+
message: `Canvas feedback: ${canvasArgs.command}`,
|
|
4397
|
+
data: {
|
|
4398
|
+
command: canvasArgs.command,
|
|
4399
|
+
streamEvent: {
|
|
4400
|
+
eventType: "feedback.complete",
|
|
4401
|
+
cursor: cursor ?? null,
|
|
4402
|
+
reason: "timeout"
|
|
3541
4403
|
}
|
|
3542
|
-
}
|
|
3543
|
-
|
|
3544
|
-
}
|
|
4404
|
+
}
|
|
4405
|
+
}, outputOptions);
|
|
3545
4406
|
}
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
4407
|
+
if (subscriptionId) {
|
|
4408
|
+
await client.call(
|
|
4409
|
+
"canvas.execute",
|
|
4410
|
+
{
|
|
4411
|
+
command: "canvas.feedback.unsubscribe",
|
|
4412
|
+
params: {
|
|
4413
|
+
...params,
|
|
4414
|
+
subscriptionId
|
|
4415
|
+
}
|
|
3555
4416
|
}
|
|
3556
|
-
|
|
3557
|
-
|
|
4417
|
+
).catch(() => {
|
|
4418
|
+
});
|
|
4419
|
+
}
|
|
3558
4420
|
}
|
|
3559
4421
|
var requireValue3 = (value, flag) => {
|
|
3560
4422
|
if (!value) throw createUsageError(`Missing value for ${flag}`);
|
|
@@ -3639,6 +4501,15 @@ var resolveCanvasParams = (canvasArgs) => {
|
|
|
3639
4501
|
}
|
|
3640
4502
|
return {};
|
|
3641
4503
|
};
|
|
4504
|
+
var attachRepoRoot = (params) => {
|
|
4505
|
+
if (typeof params.repoRoot === "string" && params.repoRoot.trim().length > 0) {
|
|
4506
|
+
return params;
|
|
4507
|
+
}
|
|
4508
|
+
return {
|
|
4509
|
+
...params,
|
|
4510
|
+
repoRoot: process.cwd()
|
|
4511
|
+
};
|
|
4512
|
+
};
|
|
3642
4513
|
async function runCanvas(args) {
|
|
3643
4514
|
const canvasArgs = parseCanvasArgs(args.rawArgs);
|
|
3644
4515
|
if (!canvasArgs.command) {
|
|
@@ -3649,7 +4520,7 @@ async function runCanvas(args) {
|
|
|
3649
4520
|
}
|
|
3650
4521
|
const client = new DaemonClient({ autoRenew: true });
|
|
3651
4522
|
try {
|
|
3652
|
-
const params = resolveCanvasParams(canvasArgs);
|
|
4523
|
+
const params = attachRepoRoot(resolveCanvasParams(canvasArgs));
|
|
3653
4524
|
const result = await client.call(
|
|
3654
4525
|
"canvas.execute",
|
|
3655
4526
|
{
|
|
@@ -3659,7 +4530,7 @@ async function runCanvas(args) {
|
|
|
3659
4530
|
{ timeoutMs: canvasArgs.timeoutMs }
|
|
3660
4531
|
);
|
|
3661
4532
|
if (canvasArgs.command === "canvas.feedback.subscribe" && args.outputFormat === "stream-json" && isRecord(result)) {
|
|
3662
|
-
await
|
|
4533
|
+
await streamFeedbackViaSubscription(client, args, canvasArgs, params, result);
|
|
3663
4534
|
return {
|
|
3664
4535
|
success: true,
|
|
3665
4536
|
message: `Canvas executed: ${canvasArgs.command}`,
|
|
@@ -3813,7 +4684,10 @@ async function runRpc(args) {
|
|
|
3813
4684
|
|
|
3814
4685
|
// src/cli/commands/interact/click.ts
|
|
3815
4686
|
function parseClickArgs(rawArgs) {
|
|
3816
|
-
const
|
|
4687
|
+
const timeoutValue = parseOptionalStringFlag(rawArgs, "--timeout-ms");
|
|
4688
|
+
const parsed = {
|
|
4689
|
+
timeoutMs: typeof timeoutValue === "string" ? parseNumberFlag(timeoutValue, "--timeout-ms", { min: 1 }) : void 0
|
|
4690
|
+
};
|
|
3817
4691
|
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
3818
4692
|
const arg = rawArgs[i];
|
|
3819
4693
|
if (arg === "--session-id") {
|
|
@@ -3842,14 +4716,17 @@ function parseClickArgs(rawArgs) {
|
|
|
3842
4716
|
return parsed;
|
|
3843
4717
|
}
|
|
3844
4718
|
async function runClick(args) {
|
|
3845
|
-
const { sessionId, ref } = parseClickArgs(args.rawArgs);
|
|
4719
|
+
const { sessionId, ref, timeoutMs } = parseClickArgs(args.rawArgs);
|
|
3846
4720
|
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
3847
4721
|
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
3848
4722
|
if (!ref) throw createUsageError("Missing --ref");
|
|
3849
|
-
const
|
|
4723
|
+
const params = {
|
|
3850
4724
|
sessionId,
|
|
3851
4725
|
ref,
|
|
3852
4726
|
...typeof targetId === "string" ? { targetId } : {}
|
|
4727
|
+
};
|
|
4728
|
+
const result = await callDaemon("interact.click", params, {
|
|
4729
|
+
timeoutMs: timeoutMs ?? DEFAULT_CLICK_TRANSPORT_TIMEOUT_MS
|
|
3853
4730
|
});
|
|
3854
4731
|
return { success: true, message: "Click complete.", data: result };
|
|
3855
4732
|
}
|
|
@@ -4260,6 +5137,146 @@ async function runScrollIntoView(args) {
|
|
|
4260
5137
|
return { success: true, message: "Scroll into view complete.", data: result };
|
|
4261
5138
|
}
|
|
4262
5139
|
|
|
5140
|
+
// src/cli/commands/interact/upload.ts
|
|
5141
|
+
function parseUploadArgs(rawArgs) {
|
|
5142
|
+
return {
|
|
5143
|
+
sessionId: parseOptionalStringFlag(rawArgs, "--session-id"),
|
|
5144
|
+
targetId: parseOptionalStringFlag(rawArgs, "--target-id"),
|
|
5145
|
+
ref: parseOptionalStringFlag(rawArgs, "--ref"),
|
|
5146
|
+
files: parseStringArrayFlag(rawArgs, "--files")
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
async function runUpload(args) {
|
|
5150
|
+
const { sessionId, targetId, ref, files } = parseUploadArgs(args.rawArgs);
|
|
5151
|
+
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
5152
|
+
if (!ref) throw createUsageError("Missing --ref");
|
|
5153
|
+
if (!files) throw createUsageError("Missing --files");
|
|
5154
|
+
const result = await callDaemon("interact.upload", {
|
|
5155
|
+
sessionId,
|
|
5156
|
+
ref,
|
|
5157
|
+
files,
|
|
5158
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
5159
|
+
});
|
|
5160
|
+
return { success: true, message: "Upload complete.", data: result };
|
|
5161
|
+
}
|
|
5162
|
+
|
|
5163
|
+
// src/cli/commands/interact/pointer-shared.ts
|
|
5164
|
+
var POINTER_BUTTONS = /* @__PURE__ */ new Set(["left", "middle", "right"]);
|
|
5165
|
+
function requireFlagValue(rawArgs, flag) {
|
|
5166
|
+
const value = parseOptionalStringFlag(rawArgs, flag);
|
|
5167
|
+
if (!value) {
|
|
5168
|
+
throw createUsageError(`Missing ${flag}`);
|
|
5169
|
+
}
|
|
5170
|
+
return value;
|
|
5171
|
+
}
|
|
5172
|
+
function requirePointerCoordinate(rawArgs, flag) {
|
|
5173
|
+
return parseNumberFlag(requireFlagValue(rawArgs, flag), flag, { integer: false });
|
|
5174
|
+
}
|
|
5175
|
+
function parsePointerSteps(rawArgs) {
|
|
5176
|
+
const value = parseOptionalStringFlag(rawArgs, "--steps");
|
|
5177
|
+
return value ? parseNumberFlag(value, "--steps", { min: 1 }) : void 0;
|
|
5178
|
+
}
|
|
5179
|
+
function parsePointerClickCount(rawArgs) {
|
|
5180
|
+
const value = parseOptionalStringFlag(rawArgs, "--click-count");
|
|
5181
|
+
return value ? parseNumberFlag(value, "--click-count", { min: 1 }) : void 0;
|
|
5182
|
+
}
|
|
5183
|
+
function parsePointerButton(rawArgs) {
|
|
5184
|
+
const value = parseOptionalStringFlag(rawArgs, "--button");
|
|
5185
|
+
if (!value) {
|
|
5186
|
+
return void 0;
|
|
5187
|
+
}
|
|
5188
|
+
if (!POINTER_BUTTONS.has(value)) {
|
|
5189
|
+
throw createUsageError(`Invalid --button: ${value}`);
|
|
5190
|
+
}
|
|
5191
|
+
return value;
|
|
5192
|
+
}
|
|
5193
|
+
|
|
5194
|
+
// src/cli/commands/interact/pointer-move.ts
|
|
5195
|
+
async function runPointerMove(args) {
|
|
5196
|
+
const sessionId = parseOptionalStringFlag(args.rawArgs, "--session-id");
|
|
5197
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
5198
|
+
const x = requirePointerCoordinate(args.rawArgs, "--x");
|
|
5199
|
+
const y = requirePointerCoordinate(args.rawArgs, "--y");
|
|
5200
|
+
const steps = parsePointerSteps(args.rawArgs);
|
|
5201
|
+
if (!sessionId) {
|
|
5202
|
+
throw createUsageError("Missing --session-id");
|
|
5203
|
+
}
|
|
5204
|
+
const result = await callDaemon("pointer.move", {
|
|
5205
|
+
sessionId,
|
|
5206
|
+
x,
|
|
5207
|
+
y,
|
|
5208
|
+
...typeof steps === "number" ? { steps } : {},
|
|
5209
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
5210
|
+
});
|
|
5211
|
+
return { success: true, message: "Pointer move complete.", data: result };
|
|
5212
|
+
}
|
|
5213
|
+
|
|
5214
|
+
// src/cli/commands/interact/pointer-down.ts
|
|
5215
|
+
async function runPointerDown(args) {
|
|
5216
|
+
const sessionId = parseOptionalStringFlag(args.rawArgs, "--session-id");
|
|
5217
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
5218
|
+
const x = requirePointerCoordinate(args.rawArgs, "--x");
|
|
5219
|
+
const y = requirePointerCoordinate(args.rawArgs, "--y");
|
|
5220
|
+
const button = parsePointerButton(args.rawArgs);
|
|
5221
|
+
const clickCount = parsePointerClickCount(args.rawArgs);
|
|
5222
|
+
if (!sessionId) {
|
|
5223
|
+
throw createUsageError("Missing --session-id");
|
|
5224
|
+
}
|
|
5225
|
+
const result = await callDaemon("pointer.down", {
|
|
5226
|
+
sessionId,
|
|
5227
|
+
x,
|
|
5228
|
+
y,
|
|
5229
|
+
...typeof button === "string" ? { button } : {},
|
|
5230
|
+
...typeof clickCount === "number" ? { clickCount } : {},
|
|
5231
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
5232
|
+
});
|
|
5233
|
+
return { success: true, message: "Pointer down complete.", data: result };
|
|
5234
|
+
}
|
|
5235
|
+
|
|
5236
|
+
// src/cli/commands/interact/pointer-up.ts
|
|
5237
|
+
async function runPointerUp(args) {
|
|
5238
|
+
const sessionId = parseOptionalStringFlag(args.rawArgs, "--session-id");
|
|
5239
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
5240
|
+
const x = requirePointerCoordinate(args.rawArgs, "--x");
|
|
5241
|
+
const y = requirePointerCoordinate(args.rawArgs, "--y");
|
|
5242
|
+
const button = parsePointerButton(args.rawArgs);
|
|
5243
|
+
const clickCount = parsePointerClickCount(args.rawArgs);
|
|
5244
|
+
if (!sessionId) {
|
|
5245
|
+
throw createUsageError("Missing --session-id");
|
|
5246
|
+
}
|
|
5247
|
+
const result = await callDaemon("pointer.up", {
|
|
5248
|
+
sessionId,
|
|
5249
|
+
x,
|
|
5250
|
+
y,
|
|
5251
|
+
...typeof button === "string" ? { button } : {},
|
|
5252
|
+
...typeof clickCount === "number" ? { clickCount } : {},
|
|
5253
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
5254
|
+
});
|
|
5255
|
+
return { success: true, message: "Pointer up complete.", data: result };
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5258
|
+
// src/cli/commands/interact/pointer-drag.ts
|
|
5259
|
+
async function runPointerDrag(args) {
|
|
5260
|
+
const sessionId = parseOptionalStringFlag(args.rawArgs, "--session-id");
|
|
5261
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
5262
|
+
const fromX = requirePointerCoordinate(args.rawArgs, "--from-x");
|
|
5263
|
+
const fromY = requirePointerCoordinate(args.rawArgs, "--from-y");
|
|
5264
|
+
const toX = requirePointerCoordinate(args.rawArgs, "--to-x");
|
|
5265
|
+
const toY = requirePointerCoordinate(args.rawArgs, "--to-y");
|
|
5266
|
+
const steps = parsePointerSteps(args.rawArgs);
|
|
5267
|
+
if (!sessionId) {
|
|
5268
|
+
throw createUsageError("Missing --session-id");
|
|
5269
|
+
}
|
|
5270
|
+
const result = await callDaemon("pointer.drag", {
|
|
5271
|
+
sessionId,
|
|
5272
|
+
from: { x: fromX, y: fromY },
|
|
5273
|
+
to: { x: toX, y: toY },
|
|
5274
|
+
...typeof steps === "number" ? { steps } : {},
|
|
5275
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
5276
|
+
});
|
|
5277
|
+
return { success: true, message: "Pointer drag complete.", data: result };
|
|
5278
|
+
}
|
|
5279
|
+
|
|
4263
5280
|
// src/cli/commands/targets/list.ts
|
|
4264
5281
|
function parseTargetsListArgs(rawArgs) {
|
|
4265
5282
|
const parsed = {};
|
|
@@ -4360,7 +5377,11 @@ function parseTargetNewArgs(rawArgs) {
|
|
|
4360
5377
|
async function runTargetNew(args) {
|
|
4361
5378
|
const { sessionId, url } = parseTargetNewArgs(args.rawArgs);
|
|
4362
5379
|
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
4363
|
-
const result = await callDaemon(
|
|
5380
|
+
const result = await callDaemon(
|
|
5381
|
+
"targets.new",
|
|
5382
|
+
{ sessionId, url },
|
|
5383
|
+
{ timeoutMs: DEFAULT_TARGET_CREATION_TRANSPORT_TIMEOUT_MS }
|
|
5384
|
+
);
|
|
4364
5385
|
return { success: true, message: "Target created.", data: result };
|
|
4365
5386
|
}
|
|
4366
5387
|
|
|
@@ -4447,7 +5468,11 @@ async function runPageOpen(args) {
|
|
|
4447
5468
|
const { sessionId, name, url } = parsePageOpenArgs(args.rawArgs);
|
|
4448
5469
|
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
4449
5470
|
if (!name) throw createUsageError("Missing --name");
|
|
4450
|
-
const result = await callDaemon(
|
|
5471
|
+
const result = await callDaemon(
|
|
5472
|
+
"page.open",
|
|
5473
|
+
{ sessionId, name, url },
|
|
5474
|
+
{ timeoutMs: DEFAULT_TARGET_CREATION_TRANSPORT_TIMEOUT_MS }
|
|
5475
|
+
);
|
|
4451
5476
|
return { success: true, message: `Page ready: ${name}`, data: result };
|
|
4452
5477
|
}
|
|
4453
5478
|
|
|
@@ -4945,97 +5970,162 @@ async function runCloneComponent(args) {
|
|
|
4945
5970
|
});
|
|
4946
5971
|
return { success: true, message: "Component cloned.", data: result };
|
|
4947
5972
|
}
|
|
4948
|
-
|
|
4949
|
-
// src/cli/commands/devtools/perf.ts
|
|
4950
|
-
function parsePerfArgs(rawArgs) {
|
|
4951
|
-
const parsed = {};
|
|
4952
|
-
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
4953
|
-
const arg = rawArgs[i];
|
|
4954
|
-
if (arg === "--session-id") {
|
|
4955
|
-
const value = rawArgs[i + 1];
|
|
4956
|
-
if (!value) throw createUsageError("Missing value for --session-id");
|
|
4957
|
-
parsed.sessionId = value;
|
|
4958
|
-
i += 1;
|
|
4959
|
-
continue;
|
|
4960
|
-
}
|
|
4961
|
-
if (arg?.startsWith("--session-id=")) {
|
|
4962
|
-
parsed.sessionId = arg.split("=", 2)[1];
|
|
4963
|
-
continue;
|
|
4964
|
-
}
|
|
4965
|
-
}
|
|
4966
|
-
return parsed;
|
|
4967
|
-
}
|
|
4968
|
-
async function runPerf(args) {
|
|
4969
|
-
const { sessionId } = parsePerfArgs(args.rawArgs);
|
|
4970
|
-
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
4971
|
-
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
4972
|
-
const result = await callDaemon("devtools.perf", {
|
|
4973
|
-
sessionId,
|
|
4974
|
-
...typeof targetId === "string" ? { targetId } : {}
|
|
4975
|
-
});
|
|
4976
|
-
return { success: true, message: "Performance metrics captured.", data: result };
|
|
4977
|
-
}
|
|
4978
|
-
|
|
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
|
-
};
|
|
4984
|
-
function parseScreenshotArgs(rawArgs) {
|
|
4985
|
-
const parsed = {};
|
|
4986
|
-
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
4987
|
-
const arg = rawArgs[i];
|
|
4988
|
-
if (arg === "--session-id") {
|
|
4989
|
-
parsed.sessionId = requireValue5(rawArgs[i + 1], "--session-id");
|
|
4990
|
-
i += 1;
|
|
4991
|
-
continue;
|
|
4992
|
-
}
|
|
4993
|
-
if (arg?.startsWith("--session-id=")) {
|
|
4994
|
-
parsed.sessionId = requireValue5(arg.split("=", 2)[1], "--session-id");
|
|
4995
|
-
continue;
|
|
4996
|
-
}
|
|
4997
|
-
if (arg === "--target-id") {
|
|
4998
|
-
parsed.targetId = requireValue5(rawArgs[i + 1], "--target-id");
|
|
4999
|
-
i += 1;
|
|
5000
|
-
continue;
|
|
5001
|
-
}
|
|
5002
|
-
if (arg?.startsWith("--target-id=")) {
|
|
5003
|
-
parsed.targetId = requireValue5(arg.split("=", 2)[1], "--target-id");
|
|
5004
|
-
continue;
|
|
5005
|
-
}
|
|
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 });
|
|
5973
|
+
|
|
5974
|
+
// src/cli/commands/devtools/perf.ts
|
|
5975
|
+
function parsePerfArgs(rawArgs) {
|
|
5976
|
+
const parsed = {};
|
|
5977
|
+
for (let i = 0; i < rawArgs.length; i += 1) {
|
|
5978
|
+
const arg = rawArgs[i];
|
|
5979
|
+
if (arg === "--session-id") {
|
|
5980
|
+
const value = rawArgs[i + 1];
|
|
5981
|
+
if (!value) throw createUsageError("Missing value for --session-id");
|
|
5982
|
+
parsed.sessionId = value;
|
|
5017
5983
|
i += 1;
|
|
5018
5984
|
continue;
|
|
5019
5985
|
}
|
|
5020
|
-
if (arg?.startsWith("--
|
|
5021
|
-
parsed.
|
|
5986
|
+
if (arg?.startsWith("--session-id=")) {
|
|
5987
|
+
parsed.sessionId = arg.split("=", 2)[1];
|
|
5022
5988
|
continue;
|
|
5023
5989
|
}
|
|
5024
5990
|
}
|
|
5025
5991
|
return parsed;
|
|
5026
5992
|
}
|
|
5993
|
+
async function runPerf(args) {
|
|
5994
|
+
const { sessionId } = parsePerfArgs(args.rawArgs);
|
|
5995
|
+
const targetId = parseOptionalStringFlag(args.rawArgs, "--target-id");
|
|
5996
|
+
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
5997
|
+
const result = await callDaemon("devtools.perf", {
|
|
5998
|
+
sessionId,
|
|
5999
|
+
...typeof targetId === "string" ? { targetId } : {}
|
|
6000
|
+
});
|
|
6001
|
+
return { success: true, message: "Performance metrics captured.", data: result };
|
|
6002
|
+
}
|
|
6003
|
+
|
|
6004
|
+
// src/cli/commands/devtools/screenshot.ts
|
|
6005
|
+
function parseScreenshotArgs(rawArgs) {
|
|
6006
|
+
const timeoutValue = parseOptionalStringFlag(rawArgs, "--timeout-ms");
|
|
6007
|
+
const parsed = {
|
|
6008
|
+
sessionId: parseOptionalStringFlag(rawArgs, "--session-id"),
|
|
6009
|
+
targetId: parseOptionalStringFlag(rawArgs, "--target-id"),
|
|
6010
|
+
path: parseOptionalStringFlag(rawArgs, "--path"),
|
|
6011
|
+
ref: parseOptionalStringFlag(rawArgs, "--ref"),
|
|
6012
|
+
fullPage: rawArgs.includes("--full-page"),
|
|
6013
|
+
timeoutMs: typeof timeoutValue === "string" ? parseNumberFlag(timeoutValue, "--timeout-ms", { min: 1 }) : void 0
|
|
6014
|
+
};
|
|
6015
|
+
if (parsed.ref && parsed.fullPage) {
|
|
6016
|
+
throw createUsageError("Choose either --ref or --full-page.");
|
|
6017
|
+
}
|
|
6018
|
+
return parsed;
|
|
6019
|
+
}
|
|
5027
6020
|
async function runScreenshot(args) {
|
|
5028
|
-
const { sessionId, targetId, path: path8, timeoutMs } = parseScreenshotArgs(args.rawArgs);
|
|
6021
|
+
const { sessionId, targetId, path: path8, ref, fullPage, timeoutMs } = parseScreenshotArgs(args.rawArgs);
|
|
5029
6022
|
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
5030
6023
|
const params = {
|
|
5031
6024
|
sessionId,
|
|
5032
|
-
path: path8,
|
|
5033
|
-
...typeof targetId === "string" ? { targetId } : {}
|
|
6025
|
+
...typeof path8 === "string" ? { path: path8 } : {},
|
|
6026
|
+
...typeof targetId === "string" ? { targetId } : {},
|
|
6027
|
+
...typeof ref === "string" ? { ref } : {},
|
|
6028
|
+
...fullPage === true ? { fullPage: true } : {}
|
|
5034
6029
|
};
|
|
5035
|
-
const result =
|
|
6030
|
+
const result = await callDaemon("page.screenshot", params, {
|
|
6031
|
+
timeoutMs: timeoutMs ?? DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS
|
|
6032
|
+
});
|
|
5036
6033
|
return { success: true, message: "Screenshot captured.", data: result };
|
|
5037
6034
|
}
|
|
5038
6035
|
|
|
6036
|
+
// src/cli/commands/devtools/screencast-start.ts
|
|
6037
|
+
function parseScreencastStartArgs(rawArgs) {
|
|
6038
|
+
const intervalValue = parseOptionalStringFlag(rawArgs, "--interval-ms");
|
|
6039
|
+
const maxFramesValue = parseOptionalStringFlag(rawArgs, "--max-frames");
|
|
6040
|
+
const timeoutValue = parseOptionalStringFlag(rawArgs, "--timeout-ms");
|
|
6041
|
+
return {
|
|
6042
|
+
sessionId: parseOptionalStringFlag(rawArgs, "--session-id"),
|
|
6043
|
+
targetId: parseOptionalStringFlag(rawArgs, "--target-id"),
|
|
6044
|
+
outputDir: parseOptionalStringFlag(rawArgs, "--output-dir"),
|
|
6045
|
+
intervalMs: typeof intervalValue === "string" ? parseNumberFlag(intervalValue, "--interval-ms", { min: 250 }) : void 0,
|
|
6046
|
+
maxFrames: typeof maxFramesValue === "string" ? parseNumberFlag(maxFramesValue, "--max-frames", { min: 1 }) : void 0,
|
|
6047
|
+
timeoutMs: typeof timeoutValue === "string" ? parseNumberFlag(timeoutValue, "--timeout-ms", { min: 1 }) : void 0
|
|
6048
|
+
};
|
|
6049
|
+
}
|
|
6050
|
+
async function runScreencastStart(args) {
|
|
6051
|
+
const { sessionId, targetId, outputDir, intervalMs, maxFrames, timeoutMs } = parseScreencastStartArgs(args.rawArgs);
|
|
6052
|
+
if (!sessionId) {
|
|
6053
|
+
throw createUsageError("Missing --session-id");
|
|
6054
|
+
}
|
|
6055
|
+
const result = await callDaemon("page.screencast.start", {
|
|
6056
|
+
sessionId,
|
|
6057
|
+
...typeof targetId === "string" ? { targetId } : {},
|
|
6058
|
+
...typeof outputDir === "string" ? { outputDir } : {},
|
|
6059
|
+
...typeof intervalMs === "number" ? { intervalMs } : {},
|
|
6060
|
+
...typeof maxFrames === "number" ? { maxFrames } : {}
|
|
6061
|
+
}, {
|
|
6062
|
+
timeoutMs: timeoutMs ?? DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS
|
|
6063
|
+
});
|
|
6064
|
+
return { success: true, message: "Screencast started.", data: result };
|
|
6065
|
+
}
|
|
6066
|
+
|
|
6067
|
+
// src/cli/commands/devtools/screencast-stop.ts
|
|
6068
|
+
function parseScreencastStopArgs(rawArgs) {
|
|
6069
|
+
const timeoutValue = parseOptionalStringFlag(rawArgs, "--timeout-ms");
|
|
6070
|
+
return {
|
|
6071
|
+
sessionId: parseOptionalStringFlag(rawArgs, "--session-id"),
|
|
6072
|
+
screencastId: parseOptionalStringFlag(rawArgs, "--screencast-id"),
|
|
6073
|
+
timeoutMs: typeof timeoutValue === "string" ? parseNumberFlag(timeoutValue, "--timeout-ms", { min: 1 }) : void 0
|
|
6074
|
+
};
|
|
6075
|
+
}
|
|
6076
|
+
async function runScreencastStop(args) {
|
|
6077
|
+
const { sessionId, screencastId, timeoutMs } = parseScreencastStopArgs(args.rawArgs);
|
|
6078
|
+
if (!sessionId) {
|
|
6079
|
+
throw createUsageError("Missing --session-id");
|
|
6080
|
+
}
|
|
6081
|
+
if (!screencastId) {
|
|
6082
|
+
throw createUsageError("Missing --screencast-id");
|
|
6083
|
+
}
|
|
6084
|
+
const result = await callDaemon("page.screencast.stop", { sessionId, screencastId }, {
|
|
6085
|
+
timeoutMs: timeoutMs ?? DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS
|
|
6086
|
+
});
|
|
6087
|
+
return { success: true, message: "Screencast stopped.", data: result };
|
|
6088
|
+
}
|
|
6089
|
+
|
|
6090
|
+
// src/cli/commands/devtools/dialog.ts
|
|
6091
|
+
function parseDialogAction(value) {
|
|
6092
|
+
if (!value) {
|
|
6093
|
+
return "status";
|
|
6094
|
+
}
|
|
6095
|
+
if (value === "status" || value === "accept" || value === "dismiss") {
|
|
6096
|
+
return value;
|
|
6097
|
+
}
|
|
6098
|
+
throw createUsageError(`Invalid --action: ${value}`);
|
|
6099
|
+
}
|
|
6100
|
+
function parseDialogArgs(rawArgs) {
|
|
6101
|
+
const timeoutValue = parseOptionalStringFlag(rawArgs, "--timeout-ms");
|
|
6102
|
+
const parsed = {
|
|
6103
|
+
sessionId: parseOptionalStringFlag(rawArgs, "--session-id"),
|
|
6104
|
+
targetId: parseOptionalStringFlag(rawArgs, "--target-id"),
|
|
6105
|
+
action: parseDialogAction(parseOptionalStringFlag(rawArgs, "--action")),
|
|
6106
|
+
promptText: parseOptionalStringFlag(rawArgs, "--prompt-text"),
|
|
6107
|
+
timeoutMs: typeof timeoutValue === "string" ? parseNumberFlag(timeoutValue, "--timeout-ms", { min: 1 }) : void 0
|
|
6108
|
+
};
|
|
6109
|
+
if (parsed.promptText && parsed.action !== "accept") {
|
|
6110
|
+
throw createUsageError("--prompt-text is only valid with --action accept");
|
|
6111
|
+
}
|
|
6112
|
+
return parsed;
|
|
6113
|
+
}
|
|
6114
|
+
async function runDialog(args) {
|
|
6115
|
+
const { sessionId, targetId, action, promptText, timeoutMs } = parseDialogArgs(args.rawArgs);
|
|
6116
|
+
if (!sessionId) throw createUsageError("Missing --session-id");
|
|
6117
|
+
const params = {
|
|
6118
|
+
sessionId,
|
|
6119
|
+
action,
|
|
6120
|
+
...typeof targetId === "string" ? { targetId } : {},
|
|
6121
|
+
...typeof promptText === "string" ? { promptText } : {}
|
|
6122
|
+
};
|
|
6123
|
+
const result = await callDaemon("page.dialog", params, {
|
|
6124
|
+
timeoutMs: timeoutMs ?? DEFAULT_DIALOG_TRANSPORT_TIMEOUT_MS
|
|
6125
|
+
});
|
|
6126
|
+
return { success: true, message: "Dialog request complete.", data: result };
|
|
6127
|
+
}
|
|
6128
|
+
|
|
5039
6129
|
// src/cli/commands/devtools/console-poll.ts
|
|
5040
6130
|
function parseConsolePollArgs(rawArgs) {
|
|
5041
6131
|
const parsed = {};
|
|
@@ -5236,9 +6326,103 @@ async function runDebugTraceSnapshot(args) {
|
|
|
5236
6326
|
};
|
|
5237
6327
|
}
|
|
5238
6328
|
|
|
6329
|
+
// src/cli/commands/desktop/shared.ts
|
|
6330
|
+
function parseDesktopTimeoutArgs(rawArgs) {
|
|
6331
|
+
const timeoutValue = parseOptionalStringFlag(rawArgs, "--timeout-ms");
|
|
6332
|
+
return {
|
|
6333
|
+
timeoutMs: typeof timeoutValue === "string" ? parseNumberFlag(timeoutValue, "--timeout-ms", { min: 1 }) : void 0
|
|
6334
|
+
};
|
|
6335
|
+
}
|
|
6336
|
+
function parseDesktopReasonArgs(rawArgs) {
|
|
6337
|
+
return {
|
|
6338
|
+
...parseDesktopTimeoutArgs(rawArgs),
|
|
6339
|
+
reason: parseOptionalStringFlag(rawArgs, "--reason")
|
|
6340
|
+
};
|
|
6341
|
+
}
|
|
6342
|
+
function parseDesktopWindowReasonArgs(rawArgs) {
|
|
6343
|
+
return {
|
|
6344
|
+
...parseDesktopReasonArgs(rawArgs),
|
|
6345
|
+
windowId: parseOptionalStringFlag(rawArgs, "--window-id")
|
|
6346
|
+
};
|
|
6347
|
+
}
|
|
6348
|
+
function requireDesktopReason(reason) {
|
|
6349
|
+
if (!reason) {
|
|
6350
|
+
throw createUsageError("Missing --reason");
|
|
6351
|
+
}
|
|
6352
|
+
return reason;
|
|
6353
|
+
}
|
|
6354
|
+
function requireDesktopWindowId(windowId) {
|
|
6355
|
+
if (!windowId) {
|
|
6356
|
+
throw createUsageError("Missing --window-id");
|
|
6357
|
+
}
|
|
6358
|
+
return windowId;
|
|
6359
|
+
}
|
|
6360
|
+
async function callDesktopCommand(name, params, timeoutMs) {
|
|
6361
|
+
return callDaemon(name, params, {
|
|
6362
|
+
timeoutMs: timeoutMs ?? DEFAULT_SCREENSHOT_TRANSPORT_TIMEOUT_MS
|
|
6363
|
+
});
|
|
6364
|
+
}
|
|
6365
|
+
function desktopCommandResult(message, data) {
|
|
6366
|
+
return { success: true, message, data };
|
|
6367
|
+
}
|
|
6368
|
+
|
|
6369
|
+
// src/cli/commands/desktop/status.ts
|
|
6370
|
+
async function runDesktopStatus(args) {
|
|
6371
|
+
const { timeoutMs } = parseDesktopTimeoutArgs(args.rawArgs);
|
|
6372
|
+
const result = await callDesktopCommand("desktop.status", {}, timeoutMs);
|
|
6373
|
+
return desktopCommandResult("Desktop status captured.", result);
|
|
6374
|
+
}
|
|
6375
|
+
|
|
6376
|
+
// src/cli/commands/desktop/windows.ts
|
|
6377
|
+
async function runDesktopWindows(args) {
|
|
6378
|
+
const { reason, timeoutMs } = parseDesktopReasonArgs(args.rawArgs);
|
|
6379
|
+
const result = await callDesktopCommand("desktop.windows.list", {
|
|
6380
|
+
...typeof reason === "string" ? { reason } : {}
|
|
6381
|
+
}, timeoutMs);
|
|
6382
|
+
return desktopCommandResult("Desktop windows listed.", result);
|
|
6383
|
+
}
|
|
6384
|
+
|
|
6385
|
+
// src/cli/commands/desktop/active-window.ts
|
|
6386
|
+
async function runDesktopActiveWindow(args) {
|
|
6387
|
+
const { reason, timeoutMs } = parseDesktopReasonArgs(args.rawArgs);
|
|
6388
|
+
const result = await callDesktopCommand("desktop.window.active", {
|
|
6389
|
+
...typeof reason === "string" ? { reason } : {}
|
|
6390
|
+
}, timeoutMs);
|
|
6391
|
+
return desktopCommandResult("Active desktop window captured.", result);
|
|
6392
|
+
}
|
|
6393
|
+
|
|
6394
|
+
// src/cli/commands/desktop/capture-desktop.ts
|
|
6395
|
+
async function runDesktopCaptureDesktop(args) {
|
|
6396
|
+
const { reason, timeoutMs } = parseDesktopReasonArgs(args.rawArgs);
|
|
6397
|
+
const result = await callDesktopCommand("desktop.capture.desktop", {
|
|
6398
|
+
reason: requireDesktopReason(reason)
|
|
6399
|
+
}, timeoutMs);
|
|
6400
|
+
return desktopCommandResult("Desktop captured.", result);
|
|
6401
|
+
}
|
|
6402
|
+
|
|
6403
|
+
// src/cli/commands/desktop/capture-window.ts
|
|
6404
|
+
async function runDesktopCaptureWindow(args) {
|
|
6405
|
+
const { windowId, reason, timeoutMs } = parseDesktopWindowReasonArgs(args.rawArgs);
|
|
6406
|
+
const result = await callDesktopCommand("desktop.capture.window", {
|
|
6407
|
+
windowId: requireDesktopWindowId(windowId),
|
|
6408
|
+
reason: requireDesktopReason(reason)
|
|
6409
|
+
}, timeoutMs);
|
|
6410
|
+
return desktopCommandResult("Desktop window captured.", result);
|
|
6411
|
+
}
|
|
6412
|
+
|
|
6413
|
+
// src/cli/commands/desktop/accessibility-snapshot.ts
|
|
6414
|
+
async function runDesktopAccessibilitySnapshot(args) {
|
|
6415
|
+
const { windowId, reason, timeoutMs } = parseDesktopWindowReasonArgs(args.rawArgs);
|
|
6416
|
+
const result = await callDesktopCommand("desktop.accessibility.snapshot", {
|
|
6417
|
+
reason: requireDesktopReason(reason),
|
|
6418
|
+
...typeof windowId === "string" ? { windowId } : {}
|
|
6419
|
+
}, timeoutMs);
|
|
6420
|
+
return desktopCommandResult("Desktop accessibility snapshot captured.", result);
|
|
6421
|
+
}
|
|
6422
|
+
|
|
5239
6423
|
// src/cli/commands/session/cookie-import.ts
|
|
5240
6424
|
import { readFileSync as readFileSync7 } from "fs";
|
|
5241
|
-
var
|
|
6425
|
+
var requireValue5 = (value, flag) => {
|
|
5242
6426
|
if (!value) {
|
|
5243
6427
|
throw createUsageError(`Missing value for ${flag}`);
|
|
5244
6428
|
}
|
|
@@ -5255,30 +6439,30 @@ var parseCookieImportArgs = (rawArgs) => {
|
|
|
5255
6439
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
5256
6440
|
const arg = rawArgs[index];
|
|
5257
6441
|
if (arg === "--session-id") {
|
|
5258
|
-
parsed.sessionId =
|
|
6442
|
+
parsed.sessionId = requireValue5(rawArgs[index + 1], "--session-id");
|
|
5259
6443
|
index += 1;
|
|
5260
6444
|
continue;
|
|
5261
6445
|
}
|
|
5262
6446
|
if (arg?.startsWith("--session-id=")) {
|
|
5263
|
-
parsed.sessionId =
|
|
6447
|
+
parsed.sessionId = requireValue5(arg.split("=", 2)[1], "--session-id");
|
|
5264
6448
|
continue;
|
|
5265
6449
|
}
|
|
5266
6450
|
if (arg === "--cookies") {
|
|
5267
|
-
parsed.cookies =
|
|
6451
|
+
parsed.cookies = requireValue5(rawArgs[index + 1], "--cookies");
|
|
5268
6452
|
index += 1;
|
|
5269
6453
|
continue;
|
|
5270
6454
|
}
|
|
5271
6455
|
if (arg?.startsWith("--cookies=")) {
|
|
5272
|
-
parsed.cookies =
|
|
6456
|
+
parsed.cookies = requireValue5(arg.split("=", 2)[1], "--cookies");
|
|
5273
6457
|
continue;
|
|
5274
6458
|
}
|
|
5275
6459
|
if (arg === "--cookies-file") {
|
|
5276
|
-
parsed.cookiesFile =
|
|
6460
|
+
parsed.cookiesFile = requireValue5(rawArgs[index + 1], "--cookies-file");
|
|
5277
6461
|
index += 1;
|
|
5278
6462
|
continue;
|
|
5279
6463
|
}
|
|
5280
6464
|
if (arg?.startsWith("--cookies-file=")) {
|
|
5281
|
-
parsed.cookiesFile =
|
|
6465
|
+
parsed.cookiesFile = requireValue5(arg.split("=", 2)[1], "--cookies-file");
|
|
5282
6466
|
continue;
|
|
5283
6467
|
}
|
|
5284
6468
|
if (arg === "--strict") {
|
|
@@ -5286,16 +6470,16 @@ var parseCookieImportArgs = (rawArgs) => {
|
|
|
5286
6470
|
continue;
|
|
5287
6471
|
}
|
|
5288
6472
|
if (arg?.startsWith("--strict=")) {
|
|
5289
|
-
parsed.strict = parseStrictValue(
|
|
6473
|
+
parsed.strict = parseStrictValue(requireValue5(arg.split("=", 2)[1], "--strict"), "--strict");
|
|
5290
6474
|
continue;
|
|
5291
6475
|
}
|
|
5292
6476
|
if (arg === "--request-id") {
|
|
5293
|
-
parsed.requestId =
|
|
6477
|
+
parsed.requestId = requireValue5(rawArgs[index + 1], "--request-id");
|
|
5294
6478
|
index += 1;
|
|
5295
6479
|
continue;
|
|
5296
6480
|
}
|
|
5297
6481
|
if (arg?.startsWith("--request-id=")) {
|
|
5298
|
-
parsed.requestId =
|
|
6482
|
+
parsed.requestId = requireValue5(arg.split("=", 2)[1], "--request-id");
|
|
5299
6483
|
continue;
|
|
5300
6484
|
}
|
|
5301
6485
|
}
|
|
@@ -5383,7 +6567,7 @@ async function runCookieImport(args) {
|
|
|
5383
6567
|
}
|
|
5384
6568
|
|
|
5385
6569
|
// src/cli/commands/session/cookie-list.ts
|
|
5386
|
-
var
|
|
6570
|
+
var requireValue6 = (value, flag) => {
|
|
5387
6571
|
if (!value) {
|
|
5388
6572
|
throw createUsageError(`Missing value for ${flag}`);
|
|
5389
6573
|
}
|
|
@@ -5420,31 +6604,31 @@ var parseCookieListArgs = (rawArgs) => {
|
|
|
5420
6604
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
5421
6605
|
const arg = rawArgs[index];
|
|
5422
6606
|
if (arg === "--session-id") {
|
|
5423
|
-
parsed.sessionId =
|
|
6607
|
+
parsed.sessionId = requireValue6(rawArgs[index + 1], "--session-id");
|
|
5424
6608
|
index += 1;
|
|
5425
6609
|
continue;
|
|
5426
6610
|
}
|
|
5427
6611
|
if (arg?.startsWith("--session-id=")) {
|
|
5428
|
-
parsed.sessionId =
|
|
6612
|
+
parsed.sessionId = requireValue6(arg.split("=", 2)[1], "--session-id");
|
|
5429
6613
|
continue;
|
|
5430
6614
|
}
|
|
5431
6615
|
if (arg === "--url") {
|
|
5432
|
-
const rawValue =
|
|
6616
|
+
const rawValue = requireValue6(rawArgs[index + 1], "--url");
|
|
5433
6617
|
parsed.urls.push(...rawValue.split(","));
|
|
5434
6618
|
index += 1;
|
|
5435
6619
|
continue;
|
|
5436
6620
|
}
|
|
5437
6621
|
if (arg?.startsWith("--url=")) {
|
|
5438
|
-
parsed.urls.push(...
|
|
6622
|
+
parsed.urls.push(...requireValue6(arg.split("=", 2)[1], "--url").split(","));
|
|
5439
6623
|
continue;
|
|
5440
6624
|
}
|
|
5441
6625
|
if (arg === "--request-id") {
|
|
5442
|
-
parsed.requestId =
|
|
6626
|
+
parsed.requestId = requireValue6(rawArgs[index + 1], "--request-id");
|
|
5443
6627
|
index += 1;
|
|
5444
6628
|
continue;
|
|
5445
6629
|
}
|
|
5446
6630
|
if (arg?.startsWith("--request-id=")) {
|
|
5447
|
-
parsed.requestId =
|
|
6631
|
+
parsed.requestId = requireValue6(arg.split("=", 2)[1], "--request-id");
|
|
5448
6632
|
continue;
|
|
5449
6633
|
}
|
|
5450
6634
|
}
|
|
@@ -5470,7 +6654,7 @@ async function runCookieList(args) {
|
|
|
5470
6654
|
}
|
|
5471
6655
|
|
|
5472
6656
|
// src/cli/commands/macro-resolve.ts
|
|
5473
|
-
var
|
|
6657
|
+
var requireValue7 = (value, flag) => {
|
|
5474
6658
|
if (!value) {
|
|
5475
6659
|
throw createUsageError(`Missing value for ${flag}`);
|
|
5476
6660
|
}
|
|
@@ -5481,21 +6665,21 @@ var parseMacroResolveArgs = (rawArgs) => {
|
|
|
5481
6665
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
5482
6666
|
const arg = rawArgs[index];
|
|
5483
6667
|
if (arg === "--expression") {
|
|
5484
|
-
parsed.expression =
|
|
6668
|
+
parsed.expression = requireValue7(rawArgs[index + 1], "--expression");
|
|
5485
6669
|
index += 1;
|
|
5486
6670
|
continue;
|
|
5487
6671
|
}
|
|
5488
6672
|
if (arg?.startsWith("--expression=")) {
|
|
5489
|
-
parsed.expression =
|
|
6673
|
+
parsed.expression = requireValue7(arg.split("=", 2)[1], "--expression");
|
|
5490
6674
|
continue;
|
|
5491
6675
|
}
|
|
5492
6676
|
if (arg === "--default-provider") {
|
|
5493
|
-
parsed.defaultProvider =
|
|
6677
|
+
parsed.defaultProvider = requireValue7(rawArgs[index + 1], "--default-provider");
|
|
5494
6678
|
index += 1;
|
|
5495
6679
|
continue;
|
|
5496
6680
|
}
|
|
5497
6681
|
if (arg?.startsWith("--default-provider=")) {
|
|
5498
|
-
parsed.defaultProvider =
|
|
6682
|
+
parsed.defaultProvider = requireValue7(arg.split("=", 2)[1], "--default-provider");
|
|
5499
6683
|
continue;
|
|
5500
6684
|
}
|
|
5501
6685
|
if (arg === "--include-catalog") {
|
|
@@ -5507,13 +6691,30 @@ var parseMacroResolveArgs = (rawArgs) => {
|
|
|
5507
6691
|
continue;
|
|
5508
6692
|
}
|
|
5509
6693
|
if (arg === "--timeout-ms") {
|
|
5510
|
-
const value =
|
|
6694
|
+
const value = requireValue7(rawArgs[index + 1], "--timeout-ms");
|
|
5511
6695
|
parsed.timeoutMs = parseNumberFlag(value, "--timeout-ms", { min: 1 });
|
|
5512
6696
|
index += 1;
|
|
5513
6697
|
continue;
|
|
5514
6698
|
}
|
|
5515
6699
|
if (arg?.startsWith("--timeout-ms=")) {
|
|
5516
|
-
parsed.timeoutMs = parseNumberFlag(
|
|
6700
|
+
parsed.timeoutMs = parseNumberFlag(requireValue7(arg.split("=", 2)[1], "--timeout-ms"), "--timeout-ms", { min: 1 });
|
|
6701
|
+
continue;
|
|
6702
|
+
}
|
|
6703
|
+
if (arg === "--challenge-automation-mode") {
|
|
6704
|
+
const value = requireValue7(rawArgs[index + 1], "--challenge-automation-mode");
|
|
6705
|
+
if (!isChallengeAutomationMode(value)) {
|
|
6706
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
6707
|
+
}
|
|
6708
|
+
parsed.challengeAutomationMode = value;
|
|
6709
|
+
index += 1;
|
|
6710
|
+
continue;
|
|
6711
|
+
}
|
|
6712
|
+
if (arg?.startsWith("--challenge-automation-mode=")) {
|
|
6713
|
+
const value = requireValue7(arg.split("=", 2)[1], "--challenge-automation-mode");
|
|
6714
|
+
if (!isChallengeAutomationMode(value)) {
|
|
6715
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
6716
|
+
}
|
|
6717
|
+
parsed.challengeAutomationMode = value;
|
|
5517
6718
|
continue;
|
|
5518
6719
|
}
|
|
5519
6720
|
}
|
|
@@ -5528,7 +6729,9 @@ async function runMacroResolve(args) {
|
|
|
5528
6729
|
expression: parsed.expression,
|
|
5529
6730
|
defaultProvider: parsed.defaultProvider,
|
|
5530
6731
|
includeCatalog: parsed.includeCatalog ?? false,
|
|
5531
|
-
execute: parsed.execute ?? false
|
|
6732
|
+
execute: parsed.execute ?? false,
|
|
6733
|
+
...typeof parsed.timeoutMs === "number" ? { timeoutMs: parsed.timeoutMs } : {},
|
|
6734
|
+
...parsed.challengeAutomationMode ? { challengeAutomationMode: parsed.challengeAutomationMode } : {}
|
|
5532
6735
|
};
|
|
5533
6736
|
const result = typeof parsed.timeoutMs === "number" ? await callDaemon("macro.resolve", params, { timeoutMs: parsed.timeoutMs }) : await callDaemon("macro.resolve", params);
|
|
5534
6737
|
return {
|
|
@@ -5538,12 +6741,42 @@ async function runMacroResolve(args) {
|
|
|
5538
6741
|
};
|
|
5539
6742
|
}
|
|
5540
6743
|
|
|
6744
|
+
// src/cli/utils/workflow-message.ts
|
|
6745
|
+
var readMeta = (data) => {
|
|
6746
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return null;
|
|
6747
|
+
const meta = data.meta;
|
|
6748
|
+
return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
|
|
6749
|
+
};
|
|
6750
|
+
var readPrimarySummary = (data) => {
|
|
6751
|
+
const meta = readMeta(data);
|
|
6752
|
+
if (!meta) return null;
|
|
6753
|
+
const summary = meta.primaryConstraintSummary;
|
|
6754
|
+
return typeof summary === "string" && summary.trim().length > 0 ? summary.trim() : null;
|
|
6755
|
+
};
|
|
6756
|
+
var readFailures = (data) => {
|
|
6757
|
+
const meta = readMeta(data);
|
|
6758
|
+
if (!meta) return [];
|
|
6759
|
+
const failures = meta.failures;
|
|
6760
|
+
return Array.isArray(failures) ? failures.filter((entry) => Boolean(entry) && typeof entry === "object") : [];
|
|
6761
|
+
};
|
|
6762
|
+
var buildWorkflowCompletionMessage = (workflowLabel, data) => {
|
|
6763
|
+
const explicitSummary = readPrimarySummary(data);
|
|
6764
|
+
if (explicitSummary) {
|
|
6765
|
+
return `${workflowLabel} completed with provider follow-up required: ${explicitSummary}`;
|
|
6766
|
+
}
|
|
6767
|
+
const inferred = summarizePrimaryProviderIssue(readFailures(data));
|
|
6768
|
+
if (inferred) {
|
|
6769
|
+
return `${workflowLabel} completed with provider follow-up required: ${inferred.summary}`;
|
|
6770
|
+
}
|
|
6771
|
+
return `${workflowLabel} completed.`;
|
|
6772
|
+
};
|
|
6773
|
+
|
|
5541
6774
|
// src/cli/commands/research.ts
|
|
5542
6775
|
var SOURCE_VALUES = /* @__PURE__ */ new Set(["web", "community", "social", "shopping"]);
|
|
5543
6776
|
var SOURCE_SELECTION_VALUES = /* @__PURE__ */ new Set(["auto", "web", "community", "social", "shopping", "all"]);
|
|
5544
6777
|
var MODE_VALUES = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
|
|
5545
6778
|
var COOKIE_POLICY_VALUES = /* @__PURE__ */ new Set(["off", "auto", "required"]);
|
|
5546
|
-
var
|
|
6779
|
+
var requireValue8 = (rawArgs, index, flag) => {
|
|
5547
6780
|
const value = rawArgs[index + 1];
|
|
5548
6781
|
if (!value) {
|
|
5549
6782
|
throw createUsageError(`Missing value for ${flag}`);
|
|
@@ -5573,7 +6806,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5573
6806
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
5574
6807
|
const arg = rawArgs[index];
|
|
5575
6808
|
if (arg === "--topic") {
|
|
5576
|
-
parsed.topic =
|
|
6809
|
+
parsed.topic = requireValue8(rawArgs, index, "--topic");
|
|
5577
6810
|
index += 1;
|
|
5578
6811
|
continue;
|
|
5579
6812
|
}
|
|
@@ -5582,7 +6815,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5582
6815
|
continue;
|
|
5583
6816
|
}
|
|
5584
6817
|
if (arg === "--days") {
|
|
5585
|
-
parsed.days = parseNumberFlag(
|
|
6818
|
+
parsed.days = parseNumberFlag(requireValue8(rawArgs, index, "--days"), "--days", { min: 1, max: 365 });
|
|
5586
6819
|
index += 1;
|
|
5587
6820
|
continue;
|
|
5588
6821
|
}
|
|
@@ -5591,7 +6824,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5591
6824
|
continue;
|
|
5592
6825
|
}
|
|
5593
6826
|
if (arg === "--from") {
|
|
5594
|
-
parsed.from =
|
|
6827
|
+
parsed.from = requireValue8(rawArgs, index, "--from");
|
|
5595
6828
|
index += 1;
|
|
5596
6829
|
continue;
|
|
5597
6830
|
}
|
|
@@ -5600,7 +6833,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5600
6833
|
continue;
|
|
5601
6834
|
}
|
|
5602
6835
|
if (arg === "--to") {
|
|
5603
|
-
parsed.to =
|
|
6836
|
+
parsed.to = requireValue8(rawArgs, index, "--to");
|
|
5604
6837
|
index += 1;
|
|
5605
6838
|
continue;
|
|
5606
6839
|
}
|
|
@@ -5609,7 +6842,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5609
6842
|
continue;
|
|
5610
6843
|
}
|
|
5611
6844
|
if (arg === "--source-selection") {
|
|
5612
|
-
const value =
|
|
6845
|
+
const value = requireValue8(rawArgs, index, "--source-selection").toLowerCase();
|
|
5613
6846
|
if (!SOURCE_SELECTION_VALUES.has(value)) {
|
|
5614
6847
|
throw createUsageError(`Invalid --source-selection: ${value}`);
|
|
5615
6848
|
}
|
|
@@ -5626,7 +6859,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5626
6859
|
continue;
|
|
5627
6860
|
}
|
|
5628
6861
|
if (arg === "--sources") {
|
|
5629
|
-
parsed.sources = parseSources(
|
|
6862
|
+
parsed.sources = parseSources(requireValue8(rawArgs, index, "--sources"));
|
|
5630
6863
|
index += 1;
|
|
5631
6864
|
continue;
|
|
5632
6865
|
}
|
|
@@ -5635,7 +6868,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5635
6868
|
continue;
|
|
5636
6869
|
}
|
|
5637
6870
|
if (arg === "--mode") {
|
|
5638
|
-
const value =
|
|
6871
|
+
const value = requireValue8(rawArgs, index, "--mode").toLowerCase();
|
|
5639
6872
|
if (!MODE_VALUES.has(value)) {
|
|
5640
6873
|
throw createUsageError(`Invalid --mode: ${value}`);
|
|
5641
6874
|
}
|
|
@@ -5656,7 +6889,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5656
6889
|
continue;
|
|
5657
6890
|
}
|
|
5658
6891
|
if (arg === "--limit-per-source") {
|
|
5659
|
-
parsed.limitPerSource = parseNumberFlag(
|
|
6892
|
+
parsed.limitPerSource = parseNumberFlag(requireValue8(rawArgs, index, "--limit-per-source"), "--limit-per-source", { min: 1, max: 100 });
|
|
5660
6893
|
index += 1;
|
|
5661
6894
|
continue;
|
|
5662
6895
|
}
|
|
@@ -5664,8 +6897,17 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5664
6897
|
parsed.limitPerSource = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--limit-per-source", { min: 1, max: 100 });
|
|
5665
6898
|
continue;
|
|
5666
6899
|
}
|
|
6900
|
+
if (arg === "--timeout-ms") {
|
|
6901
|
+
parsed.timeoutMs = parseNumberFlag(requireValue8(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
|
|
6902
|
+
index += 1;
|
|
6903
|
+
continue;
|
|
6904
|
+
}
|
|
6905
|
+
if (arg?.startsWith("--timeout-ms=")) {
|
|
6906
|
+
parsed.timeoutMs = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--timeout-ms", { min: 1 });
|
|
6907
|
+
continue;
|
|
6908
|
+
}
|
|
5667
6909
|
if (arg === "--output-dir") {
|
|
5668
|
-
parsed.outputDir =
|
|
6910
|
+
parsed.outputDir = requireValue8(rawArgs, index, "--output-dir");
|
|
5669
6911
|
index += 1;
|
|
5670
6912
|
continue;
|
|
5671
6913
|
}
|
|
@@ -5674,7 +6916,7 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5674
6916
|
continue;
|
|
5675
6917
|
}
|
|
5676
6918
|
if (arg === "--ttl-hours") {
|
|
5677
|
-
parsed.ttlHours = parseNumberFlag(
|
|
6919
|
+
parsed.ttlHours = parseNumberFlag(requireValue8(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
|
|
5678
6920
|
index += 1;
|
|
5679
6921
|
continue;
|
|
5680
6922
|
}
|
|
@@ -5690,8 +6932,25 @@ var parseResearchRunArgs = (rawArgs) => {
|
|
|
5690
6932
|
parsed.useCookies = parseBoolean(arg.split("=", 2)[1] ?? "", "--use-cookies");
|
|
5691
6933
|
continue;
|
|
5692
6934
|
}
|
|
6935
|
+
if (arg === "--challenge-automation-mode") {
|
|
6936
|
+
const value = requireValue8(rawArgs, index, "--challenge-automation-mode");
|
|
6937
|
+
if (!isChallengeAutomationMode(value)) {
|
|
6938
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
6939
|
+
}
|
|
6940
|
+
parsed.challengeAutomationMode = value;
|
|
6941
|
+
index += 1;
|
|
6942
|
+
continue;
|
|
6943
|
+
}
|
|
6944
|
+
if (arg?.startsWith("--challenge-automation-mode=")) {
|
|
6945
|
+
const value = arg.split("=", 2)[1] ?? "";
|
|
6946
|
+
if (!isChallengeAutomationMode(value)) {
|
|
6947
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
6948
|
+
}
|
|
6949
|
+
parsed.challengeAutomationMode = value;
|
|
6950
|
+
continue;
|
|
6951
|
+
}
|
|
5693
6952
|
if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
|
|
5694
|
-
const value =
|
|
6953
|
+
const value = requireValue8(rawArgs, index, arg).toLowerCase();
|
|
5695
6954
|
if (!COOKIE_POLICY_VALUES.has(value)) {
|
|
5696
6955
|
throw createUsageError(`Invalid ${arg}: ${value}`);
|
|
5697
6956
|
}
|
|
@@ -5719,7 +6978,7 @@ async function runResearchCommand(args) {
|
|
|
5719
6978
|
if (!parsed.topic?.trim()) {
|
|
5720
6979
|
throw createUsageError("Missing --topic");
|
|
5721
6980
|
}
|
|
5722
|
-
const
|
|
6981
|
+
const payload = {
|
|
5723
6982
|
topic: parsed.topic,
|
|
5724
6983
|
days: parsed.days,
|
|
5725
6984
|
from: parsed.from,
|
|
@@ -5729,14 +6988,17 @@ async function runResearchCommand(args) {
|
|
|
5729
6988
|
mode: parsed.mode ?? "compact",
|
|
5730
6989
|
includeEngagement: parsed.includeEngagement ?? false,
|
|
5731
6990
|
limitPerSource: parsed.limitPerSource,
|
|
6991
|
+
timeoutMs: parsed.timeoutMs ?? DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS,
|
|
5732
6992
|
outputDir: parsed.outputDir,
|
|
5733
6993
|
ttlHours: parsed.ttlHours,
|
|
5734
6994
|
useCookies: parsed.useCookies,
|
|
6995
|
+
challengeAutomationMode: parsed.challengeAutomationMode,
|
|
5735
6996
|
cookiePolicyOverride: parsed.cookiePolicyOverride
|
|
5736
|
-
}
|
|
6997
|
+
};
|
|
6998
|
+
const data = await callDaemon("research.run", payload);
|
|
5737
6999
|
return {
|
|
5738
7000
|
success: true,
|
|
5739
|
-
message: "Research workflow
|
|
7001
|
+
message: buildWorkflowCompletionMessage("Research workflow", data),
|
|
5740
7002
|
data
|
|
5741
7003
|
};
|
|
5742
7004
|
}
|
|
@@ -5745,7 +7007,15 @@ async function runResearchCommand(args) {
|
|
|
5745
7007
|
var SORT_VALUES = /* @__PURE__ */ new Set(["best_deal", "lowest_price", "highest_rating", "fastest_shipping"]);
|
|
5746
7008
|
var MODE_VALUES2 = /* @__PURE__ */ new Set(["compact", "json", "md", "context", "path"]);
|
|
5747
7009
|
var COOKIE_POLICY_VALUES2 = /* @__PURE__ */ new Set(["off", "auto", "required"]);
|
|
5748
|
-
var
|
|
7010
|
+
var BROWSER_MODE_VALUES = /* @__PURE__ */ new Set(["auto", "extension", "managed"]);
|
|
7011
|
+
var SHOPPING_TRANSPORT_TIMEOUT_BUFFER_MS = 6e4;
|
|
7012
|
+
var deriveShoppingTransportTimeoutMs = (timeoutMs) => {
|
|
7013
|
+
return Math.max(
|
|
7014
|
+
DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS,
|
|
7015
|
+
timeoutMs + SHOPPING_TRANSPORT_TIMEOUT_BUFFER_MS
|
|
7016
|
+
);
|
|
7017
|
+
};
|
|
7018
|
+
var requireValue9 = (rawArgs, index, flag) => {
|
|
5749
7019
|
const value = rawArgs[index + 1];
|
|
5750
7020
|
if (!value) {
|
|
5751
7021
|
throw createUsageError(`Missing value for ${flag}`);
|
|
@@ -5769,7 +7039,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5769
7039
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
5770
7040
|
const arg = rawArgs[index];
|
|
5771
7041
|
if (arg === "--query") {
|
|
5772
|
-
parsed.query =
|
|
7042
|
+
parsed.query = requireValue9(rawArgs, index, "--query");
|
|
5773
7043
|
index += 1;
|
|
5774
7044
|
continue;
|
|
5775
7045
|
}
|
|
@@ -5778,7 +7048,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5778
7048
|
continue;
|
|
5779
7049
|
}
|
|
5780
7050
|
if (arg === "--providers") {
|
|
5781
|
-
parsed.providers = parseProviders(
|
|
7051
|
+
parsed.providers = parseProviders(requireValue9(rawArgs, index, "--providers"));
|
|
5782
7052
|
index += 1;
|
|
5783
7053
|
continue;
|
|
5784
7054
|
}
|
|
@@ -5787,7 +7057,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5787
7057
|
continue;
|
|
5788
7058
|
}
|
|
5789
7059
|
if (arg === "--budget") {
|
|
5790
|
-
parsed.budget = parseNumberFlag(
|
|
7060
|
+
parsed.budget = parseNumberFlag(requireValue9(rawArgs, index, "--budget"), "--budget", { min: 1, integer: false });
|
|
5791
7061
|
index += 1;
|
|
5792
7062
|
continue;
|
|
5793
7063
|
}
|
|
@@ -5796,7 +7066,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5796
7066
|
continue;
|
|
5797
7067
|
}
|
|
5798
7068
|
if (arg === "--region") {
|
|
5799
|
-
parsed.region =
|
|
7069
|
+
parsed.region = requireValue9(rawArgs, index, "--region");
|
|
5800
7070
|
index += 1;
|
|
5801
7071
|
continue;
|
|
5802
7072
|
}
|
|
@@ -5804,8 +7074,25 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5804
7074
|
parsed.region = arg.split("=", 2)[1];
|
|
5805
7075
|
continue;
|
|
5806
7076
|
}
|
|
7077
|
+
if (arg === "--browser-mode") {
|
|
7078
|
+
const value = requireValue9(rawArgs, index, "--browser-mode").toLowerCase();
|
|
7079
|
+
if (!BROWSER_MODE_VALUES.has(value)) {
|
|
7080
|
+
throw createUsageError(`Invalid --browser-mode: ${value}`);
|
|
7081
|
+
}
|
|
7082
|
+
parsed.browserMode = value;
|
|
7083
|
+
index += 1;
|
|
7084
|
+
continue;
|
|
7085
|
+
}
|
|
7086
|
+
if (arg?.startsWith("--browser-mode=")) {
|
|
7087
|
+
const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
|
|
7088
|
+
if (!BROWSER_MODE_VALUES.has(value)) {
|
|
7089
|
+
throw createUsageError(`Invalid --browser-mode: ${value}`);
|
|
7090
|
+
}
|
|
7091
|
+
parsed.browserMode = value;
|
|
7092
|
+
continue;
|
|
7093
|
+
}
|
|
5807
7094
|
if (arg === "--sort") {
|
|
5808
|
-
const value =
|
|
7095
|
+
const value = requireValue9(rawArgs, index, "--sort").toLowerCase();
|
|
5809
7096
|
if (!SORT_VALUES.has(value)) {
|
|
5810
7097
|
throw createUsageError(`Invalid --sort: ${value}`);
|
|
5811
7098
|
}
|
|
@@ -5822,7 +7109,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5822
7109
|
continue;
|
|
5823
7110
|
}
|
|
5824
7111
|
if (arg === "--mode") {
|
|
5825
|
-
const value =
|
|
7112
|
+
const value = requireValue9(rawArgs, index, "--mode").toLowerCase();
|
|
5826
7113
|
if (!MODE_VALUES2.has(value)) {
|
|
5827
7114
|
throw createUsageError(`Invalid --mode: ${value}`);
|
|
5828
7115
|
}
|
|
@@ -5839,7 +7126,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5839
7126
|
continue;
|
|
5840
7127
|
}
|
|
5841
7128
|
if (arg === "--timeout-ms") {
|
|
5842
|
-
parsed.timeoutMs = parseNumberFlag(
|
|
7129
|
+
parsed.timeoutMs = parseNumberFlag(requireValue9(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
|
|
5843
7130
|
index += 1;
|
|
5844
7131
|
continue;
|
|
5845
7132
|
}
|
|
@@ -5848,7 +7135,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5848
7135
|
continue;
|
|
5849
7136
|
}
|
|
5850
7137
|
if (arg === "--output-dir") {
|
|
5851
|
-
parsed.outputDir =
|
|
7138
|
+
parsed.outputDir = requireValue9(rawArgs, index, "--output-dir");
|
|
5852
7139
|
index += 1;
|
|
5853
7140
|
continue;
|
|
5854
7141
|
}
|
|
@@ -5857,7 +7144,7 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5857
7144
|
continue;
|
|
5858
7145
|
}
|
|
5859
7146
|
if (arg === "--ttl-hours") {
|
|
5860
|
-
parsed.ttlHours = parseNumberFlag(
|
|
7147
|
+
parsed.ttlHours = parseNumberFlag(requireValue9(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
|
|
5861
7148
|
index += 1;
|
|
5862
7149
|
continue;
|
|
5863
7150
|
}
|
|
@@ -5873,8 +7160,25 @@ var parseShoppingRunArgs = (rawArgs) => {
|
|
|
5873
7160
|
parsed.useCookies = parseBoolean2(arg.split("=", 2)[1] ?? "", "--use-cookies");
|
|
5874
7161
|
continue;
|
|
5875
7162
|
}
|
|
7163
|
+
if (arg === "--challenge-automation-mode") {
|
|
7164
|
+
const value = requireValue9(rawArgs, index, "--challenge-automation-mode");
|
|
7165
|
+
if (!isChallengeAutomationMode(value)) {
|
|
7166
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
7167
|
+
}
|
|
7168
|
+
parsed.challengeAutomationMode = value;
|
|
7169
|
+
index += 1;
|
|
7170
|
+
continue;
|
|
7171
|
+
}
|
|
7172
|
+
if (arg?.startsWith("--challenge-automation-mode=")) {
|
|
7173
|
+
const value = arg.split("=", 2)[1] ?? "";
|
|
7174
|
+
if (!isChallengeAutomationMode(value)) {
|
|
7175
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
7176
|
+
}
|
|
7177
|
+
parsed.challengeAutomationMode = value;
|
|
7178
|
+
continue;
|
|
7179
|
+
}
|
|
5876
7180
|
if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
|
|
5877
|
-
const value =
|
|
7181
|
+
const value = requireValue9(rawArgs, index, arg).toLowerCase();
|
|
5878
7182
|
if (!COOKIE_POLICY_VALUES2.has(value)) {
|
|
5879
7183
|
throw createUsageError(`Invalid ${arg}: ${value}`);
|
|
5880
7184
|
}
|
|
@@ -5907,24 +7211,28 @@ async function runShoppingCommand(args) {
|
|
|
5907
7211
|
providers: parsed.providers,
|
|
5908
7212
|
budget: parsed.budget,
|
|
5909
7213
|
region: parsed.region,
|
|
7214
|
+
browserMode: parsed.browserMode,
|
|
5910
7215
|
sort: parsed.sort,
|
|
5911
7216
|
mode: parsed.mode ?? "compact",
|
|
5912
|
-
|
|
7217
|
+
timeoutMs: parsed.timeoutMs ?? DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS,
|
|
5913
7218
|
outputDir: parsed.outputDir,
|
|
5914
7219
|
ttlHours: parsed.ttlHours,
|
|
5915
7220
|
useCookies: parsed.useCookies,
|
|
7221
|
+
challengeAutomationMode: parsed.challengeAutomationMode,
|
|
5916
7222
|
cookiePolicyOverride: parsed.cookiePolicyOverride
|
|
5917
7223
|
};
|
|
5918
|
-
const data =
|
|
7224
|
+
const data = await callDaemon("shopping.run", payload, {
|
|
7225
|
+
timeoutMs: deriveShoppingTransportTimeoutMs(payload.timeoutMs)
|
|
7226
|
+
});
|
|
5919
7227
|
return {
|
|
5920
7228
|
success: true,
|
|
5921
|
-
message: "Shopping workflow
|
|
7229
|
+
message: buildWorkflowCompletionMessage("Shopping workflow", data),
|
|
5922
7230
|
data
|
|
5923
7231
|
};
|
|
5924
7232
|
}
|
|
5925
7233
|
|
|
5926
7234
|
// src/cli/commands/product-video.ts
|
|
5927
|
-
var
|
|
7235
|
+
var requireValue10 = (rawArgs, index, flag) => {
|
|
5928
7236
|
const value = rawArgs[index + 1];
|
|
5929
7237
|
if (!value) {
|
|
5930
7238
|
throw createUsageError(`Missing value for ${flag}`);
|
|
@@ -5942,7 +7250,7 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
5942
7250
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
5943
7251
|
const arg = rawArgs[index];
|
|
5944
7252
|
if (arg === "--product-url") {
|
|
5945
|
-
parsed.productUrl =
|
|
7253
|
+
parsed.productUrl = requireValue10(rawArgs, index, "--product-url");
|
|
5946
7254
|
index += 1;
|
|
5947
7255
|
continue;
|
|
5948
7256
|
}
|
|
@@ -5951,7 +7259,7 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
5951
7259
|
continue;
|
|
5952
7260
|
}
|
|
5953
7261
|
if (arg === "--product-name") {
|
|
5954
|
-
parsed.productName =
|
|
7262
|
+
parsed.productName = requireValue10(rawArgs, index, "--product-name");
|
|
5955
7263
|
index += 1;
|
|
5956
7264
|
continue;
|
|
5957
7265
|
}
|
|
@@ -5960,7 +7268,7 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
5960
7268
|
continue;
|
|
5961
7269
|
}
|
|
5962
7270
|
if (arg === "--provider-hint") {
|
|
5963
|
-
parsed.providerHint =
|
|
7271
|
+
parsed.providerHint = requireValue10(rawArgs, index, "--provider-hint");
|
|
5964
7272
|
index += 1;
|
|
5965
7273
|
continue;
|
|
5966
7274
|
}
|
|
@@ -5993,7 +7301,7 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
5993
7301
|
continue;
|
|
5994
7302
|
}
|
|
5995
7303
|
if (arg === "--output-dir") {
|
|
5996
|
-
parsed.outputDir =
|
|
7304
|
+
parsed.outputDir = requireValue10(rawArgs, index, "--output-dir");
|
|
5997
7305
|
index += 1;
|
|
5998
7306
|
continue;
|
|
5999
7307
|
}
|
|
@@ -6002,7 +7310,7 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
6002
7310
|
continue;
|
|
6003
7311
|
}
|
|
6004
7312
|
if (arg === "--ttl-hours") {
|
|
6005
|
-
parsed.ttlHours = parseNumberFlag(
|
|
7313
|
+
parsed.ttlHours = parseNumberFlag(requireValue10(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
|
|
6006
7314
|
index += 1;
|
|
6007
7315
|
continue;
|
|
6008
7316
|
}
|
|
@@ -6011,7 +7319,7 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
6011
7319
|
continue;
|
|
6012
7320
|
}
|
|
6013
7321
|
if (arg === "--timeout-ms") {
|
|
6014
|
-
parsed.timeoutMs = parseNumberFlag(
|
|
7322
|
+
parsed.timeoutMs = parseNumberFlag(requireValue10(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
|
|
6015
7323
|
index += 1;
|
|
6016
7324
|
continue;
|
|
6017
7325
|
}
|
|
@@ -6027,8 +7335,25 @@ var parseProductVideoArgs = (rawArgs) => {
|
|
|
6027
7335
|
parsed.useCookies = parseBoolean3(arg.split("=", 2)[1] ?? "", "--use-cookies");
|
|
6028
7336
|
continue;
|
|
6029
7337
|
}
|
|
7338
|
+
if (arg === "--challenge-automation-mode") {
|
|
7339
|
+
const value = requireValue10(rawArgs, index, "--challenge-automation-mode");
|
|
7340
|
+
if (!isChallengeAutomationMode(value)) {
|
|
7341
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
7342
|
+
}
|
|
7343
|
+
parsed.challengeAutomationMode = value;
|
|
7344
|
+
index += 1;
|
|
7345
|
+
continue;
|
|
7346
|
+
}
|
|
7347
|
+
if (arg?.startsWith("--challenge-automation-mode=")) {
|
|
7348
|
+
const value = arg.split("=", 2)[1] ?? "";
|
|
7349
|
+
if (!isChallengeAutomationMode(value)) {
|
|
7350
|
+
throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
|
|
7351
|
+
}
|
|
7352
|
+
parsed.challengeAutomationMode = value;
|
|
7353
|
+
continue;
|
|
7354
|
+
}
|
|
6030
7355
|
if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
|
|
6031
|
-
const value =
|
|
7356
|
+
const value = requireValue10(rawArgs, index, arg).toLowerCase();
|
|
6032
7357
|
if (!COOKIE_POLICY_VALUES3.has(value)) {
|
|
6033
7358
|
throw createUsageError(`Invalid ${arg}: ${value}`);
|
|
6034
7359
|
}
|
|
@@ -6056,7 +7381,7 @@ async function runProductVideoCommand(args) {
|
|
|
6056
7381
|
if (!parsed.productUrl && !parsed.productName) {
|
|
6057
7382
|
throw createUsageError("Missing --product-url or --product-name");
|
|
6058
7383
|
}
|
|
6059
|
-
const timeoutMs = parsed.timeoutMs ??
|
|
7384
|
+
const timeoutMs = parsed.timeoutMs ?? DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS;
|
|
6060
7385
|
const data = await callDaemon("product.video.run", {
|
|
6061
7386
|
product_url: parsed.productUrl,
|
|
6062
7387
|
product_name: parsed.productName,
|
|
@@ -6066,12 +7391,14 @@ async function runProductVideoCommand(args) {
|
|
|
6066
7391
|
include_copy: parsed.includeCopy,
|
|
6067
7392
|
output_dir: parsed.outputDir,
|
|
6068
7393
|
ttl_hours: parsed.ttlHours,
|
|
7394
|
+
timeoutMs,
|
|
6069
7395
|
useCookies: parsed.useCookies,
|
|
7396
|
+
challengeAutomationMode: parsed.challengeAutomationMode,
|
|
6070
7397
|
cookiePolicyOverride: parsed.cookiePolicyOverride
|
|
6071
|
-
}
|
|
7398
|
+
});
|
|
6072
7399
|
return {
|
|
6073
7400
|
success: true,
|
|
6074
|
-
message: "Product video asset workflow
|
|
7401
|
+
message: buildWorkflowCompletionMessage("Product video asset workflow", data),
|
|
6075
7402
|
data
|
|
6076
7403
|
};
|
|
6077
7404
|
}
|
|
@@ -6079,8 +7406,8 @@ async function runProductVideoCommand(args) {
|
|
|
6079
7406
|
// package.json
|
|
6080
7407
|
var package_default = {
|
|
6081
7408
|
name: "opendevbrowser",
|
|
6082
|
-
version: "0.0.
|
|
6083
|
-
description: "
|
|
7409
|
+
version: "0.0.18",
|
|
7410
|
+
description: "Browser automation runtime with snapshot-refs-actions, browser replay screencasts, public read-only desktop observation, and browser-scoped computer-use orchestration",
|
|
6084
7411
|
type: "module",
|
|
6085
7412
|
main: "dist/index.js",
|
|
6086
7413
|
types: "dist/index.d.ts",
|
|
@@ -6106,7 +7433,14 @@ var package_default = {
|
|
|
6106
7433
|
"playwright",
|
|
6107
7434
|
"testing",
|
|
6108
7435
|
"web-scraping",
|
|
6109
|
-
"chrome"
|
|
7436
|
+
"chrome",
|
|
7437
|
+
"annotation",
|
|
7438
|
+
"design-canvas",
|
|
7439
|
+
"screencast",
|
|
7440
|
+
"desktop-observation",
|
|
7441
|
+
"browser-replay",
|
|
7442
|
+
"computer-use",
|
|
7443
|
+
"challenge-automation"
|
|
6110
7444
|
],
|
|
6111
7445
|
license: "MIT",
|
|
6112
7446
|
repository: {
|
|
@@ -6117,24 +7451,11 @@ var package_default = {
|
|
|
6117
7451
|
node: ">=18"
|
|
6118
7452
|
},
|
|
6119
7453
|
scripts: {
|
|
6120
|
-
build:
|
|
6121
|
-
|
|
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",
|
|
7454
|
+
build: "tsup src/index.ts src/cli/index.ts src/skills/skill-loader.ts --format esm --clean --sourcemap && tsc --emitDeclarationOnly --declaration --declarationMap -p tsconfig.json && node scripts/postbuild-dist.mjs",
|
|
7455
|
+
dev: "tsup src/index.ts src/cli/index.ts src/skills/skill-loader.ts --format esm --dts --watch",
|
|
6135
7456
|
lint: 'eslint "src/**/*.ts" "tests/**/*.ts"',
|
|
6136
7457
|
typecheck: "tsc --noEmit -p tsconfig.json",
|
|
6137
|
-
test:
|
|
7458
|
+
test: "node scripts/run-vitest-coverage.mjs",
|
|
6138
7459
|
"test:release-gate": "node scripts/release-gate-test-groups.mjs",
|
|
6139
7460
|
"test:release-gate:g1": "node scripts/release-gate-test-groups.mjs --group 1",
|
|
6140
7461
|
"test:release-gate:g2": "node scripts/release-gate-test-groups.mjs --group 2",
|
|
@@ -6149,10 +7470,11 @@ for (const [src, dst] of pairs) {
|
|
|
6149
7470
|
prepack: "npm run version:check && npm run build && npm run extension:build"
|
|
6150
7471
|
},
|
|
6151
7472
|
dependencies: {
|
|
6152
|
-
"@opencode-ai/plugin": "^1.2.
|
|
7473
|
+
"@opencode-ai/plugin": "^1.2.25",
|
|
6153
7474
|
"@puppeteer/browsers": "^2.13.0",
|
|
6154
7475
|
"async-mutex": "^0.5.0",
|
|
6155
7476
|
"jsonc-parser": "^3.2.0",
|
|
7477
|
+
parse5: "^8.0.0",
|
|
6156
7478
|
"playwright-core": "^1.58.2",
|
|
6157
7479
|
typescript: "^5.9.3",
|
|
6158
7480
|
ws: "^8.19.0",
|
|
@@ -6175,6 +7497,29 @@ for (const [src, dst] of pairs) {
|
|
|
6175
7497
|
|
|
6176
7498
|
// src/cli/index.ts
|
|
6177
7499
|
var VERSION = typeof package_default.version === "string" ? package_default.version : "0.0.0";
|
|
7500
|
+
function resolveUpdateSkillModes(args) {
|
|
7501
|
+
if (args.rawArgs.includes("--no-skills")) {
|
|
7502
|
+
return [];
|
|
7503
|
+
}
|
|
7504
|
+
if (args.rawArgs.includes("--skills-global")) {
|
|
7505
|
+
return ["global"];
|
|
7506
|
+
}
|
|
7507
|
+
if (args.rawArgs.includes("--skills-local")) {
|
|
7508
|
+
return ["local"];
|
|
7509
|
+
}
|
|
7510
|
+
if (args.mode) {
|
|
7511
|
+
return [args.mode];
|
|
7512
|
+
}
|
|
7513
|
+
const installed = findInstalledConfigs();
|
|
7514
|
+
const modes = [];
|
|
7515
|
+
if (installed.global || hasBundledSkillArtifacts("global")) {
|
|
7516
|
+
modes.push("global");
|
|
7517
|
+
}
|
|
7518
|
+
if (installed.local || hasBundledSkillArtifacts("local")) {
|
|
7519
|
+
modes.push("local");
|
|
7520
|
+
}
|
|
7521
|
+
return modes;
|
|
7522
|
+
}
|
|
6178
7523
|
async function promptInstallMode() {
|
|
6179
7524
|
if (!process.stdin.isTTY) {
|
|
6180
7525
|
console.log("Non-interactive mode detected. Using global install.");
|
|
@@ -6275,6 +7620,7 @@ async function main() {
|
|
|
6275
7620
|
const args = parseArgs(process.argv);
|
|
6276
7621
|
parseSucceeded = true;
|
|
6277
7622
|
outputFormat = args.outputFormat;
|
|
7623
|
+
setDefaultLogSink(stderrSink);
|
|
6278
7624
|
const outputOptions = { format: args.outputFormat, quiet: args.quiet };
|
|
6279
7625
|
const emitResult = (result2, payload) => {
|
|
6280
7626
|
const suppressOutput = Boolean(
|
|
@@ -6310,15 +7656,27 @@ async function main() {
|
|
|
6310
7656
|
});
|
|
6311
7657
|
registerCommand({
|
|
6312
7658
|
name: "update",
|
|
6313
|
-
description: "Clear cached plugin
|
|
7659
|
+
description: "Clear cached plugin and refresh managed skill packs",
|
|
6314
7660
|
run: () => {
|
|
6315
7661
|
const result2 = runUpdate();
|
|
6316
|
-
|
|
7662
|
+
const skillModes = result2.success ? resolveUpdateSkillModes(args) : [];
|
|
7663
|
+
const skillResults = result2.success ? skillModes.map((mode) => syncBundledSkills(mode)) : [];
|
|
7664
|
+
const skillMessage = args.rawArgs.includes("--no-skills") ? "Managed skill refresh skipped (--no-skills)." : skillResults.length > 0 ? skillResults.map((entry) => entry.message).join("\n") : result2.success ? "No managed skill packs required refresh." : "";
|
|
7665
|
+
const message = [result2.message, skillMessage].filter(Boolean).join("\n");
|
|
7666
|
+
return {
|
|
7667
|
+
success: result2.success && skillResults.every((entry) => entry.success),
|
|
7668
|
+
message,
|
|
7669
|
+
data: {
|
|
7670
|
+
cacheCleared: result2.cleared,
|
|
7671
|
+
skillModes,
|
|
7672
|
+
skills: skillResults
|
|
7673
|
+
}
|
|
7674
|
+
};
|
|
6317
7675
|
}
|
|
6318
7676
|
});
|
|
6319
7677
|
registerCommand({
|
|
6320
7678
|
name: "uninstall",
|
|
6321
|
-
description: "Remove plugin from config",
|
|
7679
|
+
description: "Remove plugin from config and clean managed skill packs",
|
|
6322
7680
|
run: async () => {
|
|
6323
7681
|
let mode = args.mode;
|
|
6324
7682
|
if (!mode && !args.noPrompt) {
|
|
@@ -6331,12 +7689,22 @@ async function main() {
|
|
|
6331
7689
|
return { success: false, message: "Error: Please specify --global or --local for uninstall.", exitCode: EXIT_USAGE };
|
|
6332
7690
|
}
|
|
6333
7691
|
const result2 = runUninstall(mode);
|
|
6334
|
-
|
|
7692
|
+
const skipSkills = args.rawArgs.includes("--no-skills");
|
|
7693
|
+
const skillsResult = result2.success && !skipSkills ? removeBundledSkills(mode) : void 0;
|
|
7694
|
+
const skillMessage = skipSkills ? "Managed skill cleanup skipped (--no-skills)." : skillsResult?.message ?? "";
|
|
7695
|
+
return {
|
|
7696
|
+
success: result2.success && (skillsResult?.success ?? true),
|
|
7697
|
+
message: [result2.message, skillMessage].filter(Boolean).join("\n"),
|
|
7698
|
+
data: {
|
|
7699
|
+
config: result2,
|
|
7700
|
+
skills: skillsResult
|
|
7701
|
+
}
|
|
7702
|
+
};
|
|
6335
7703
|
}
|
|
6336
7704
|
});
|
|
6337
7705
|
registerCommand({
|
|
6338
7706
|
name: "install",
|
|
6339
|
-
description: "Install the plugin",
|
|
7707
|
+
description: "Install the plugin and sync bundled skill packs",
|
|
6340
7708
|
run: async () => {
|
|
6341
7709
|
const log = (...values) => {
|
|
6342
7710
|
if (args.quiet) return;
|
|
@@ -6351,28 +7719,14 @@ async function main() {
|
|
|
6351
7719
|
mode = await promptInstallMode();
|
|
6352
7720
|
}
|
|
6353
7721
|
const result2 = mode === "global" ? installGlobal(args.withConfig) : installLocal(args.withConfig);
|
|
6354
|
-
const
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
return { status, installed: false, message: `Autostart not supported on ${status.platform}.` };
|
|
6358
|
-
}
|
|
6359
|
-
if (status.installed) {
|
|
6360
|
-
return { status, installed: true, message: "Autostart already installed." };
|
|
6361
|
-
}
|
|
6362
|
-
try {
|
|
6363
|
-
const result3 = installAutostart();
|
|
6364
|
-
return { status: result3, installed: result3.installed, message: `Autostart installed (${result3.platform}).` };
|
|
6365
|
-
} catch (error) {
|
|
6366
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6367
|
-
return { status, installed: false, message };
|
|
6368
|
-
}
|
|
6369
|
-
};
|
|
7722
|
+
const autostart = result2.success ? reconcileInstallAutostart(result2) : void 0;
|
|
7723
|
+
const skillsResult = result2.success && args.skillsMode !== "none" ? syncBundledSkills(args.skillsMode) : void 0;
|
|
7724
|
+
const installSuccess = result2.success && (skillsResult?.success ?? true);
|
|
6370
7725
|
if (args.outputFormat !== "text") {
|
|
6371
7726
|
const payload = {
|
|
6372
7727
|
alreadyInstalled: result2.alreadyInstalled
|
|
6373
7728
|
};
|
|
6374
|
-
if (
|
|
6375
|
-
const skillsResult = installSkills(args.skillsMode);
|
|
7729
|
+
if (skillsResult) {
|
|
6376
7730
|
payload.skills = skillsResult;
|
|
6377
7731
|
}
|
|
6378
7732
|
if (args.fullInstall && result2.success) {
|
|
@@ -6383,20 +7737,15 @@ async function main() {
|
|
|
6383
7737
|
payload.extensionError = error instanceof Error ? error.message : String(error);
|
|
6384
7738
|
}
|
|
6385
7739
|
}
|
|
6386
|
-
if (
|
|
6387
|
-
|
|
6388
|
-
payload.autostart = autostart.status;
|
|
6389
|
-
if (!autostart.installed) {
|
|
6390
|
-
payload.autostartError = autostart.message;
|
|
6391
|
-
}
|
|
7740
|
+
if (autostart) {
|
|
7741
|
+
Object.assign(payload, createInstallAutostartOutputPayload(autostart));
|
|
6392
7742
|
}
|
|
6393
|
-
return { success:
|
|
7743
|
+
return { success: installSuccess, message: result2.message, data: payload };
|
|
6394
7744
|
}
|
|
6395
7745
|
log(result2.message);
|
|
6396
7746
|
if (args.skillsMode === "none") {
|
|
6397
7747
|
log("Skill installation skipped (--no-skills).");
|
|
6398
|
-
} else if (
|
|
6399
|
-
const skillsResult = installSkills(args.skillsMode);
|
|
7748
|
+
} else if (skillsResult) {
|
|
6400
7749
|
if (skillsResult.success) {
|
|
6401
7750
|
log(skillsResult.message);
|
|
6402
7751
|
} else {
|
|
@@ -6418,21 +7767,24 @@ async function main() {
|
|
|
6418
7767
|
warn(`Extension pre-extraction failed: ${message}`);
|
|
6419
7768
|
}
|
|
6420
7769
|
}
|
|
6421
|
-
if (
|
|
6422
|
-
const
|
|
6423
|
-
if (
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
7770
|
+
if (autostart) {
|
|
7771
|
+
const autostartMessage = formatAutostartReconciliationMessage(autostart);
|
|
7772
|
+
if (autostartMessage) {
|
|
7773
|
+
if (autostart.autostartAction === "repair_failed") {
|
|
7774
|
+
warn(autostartMessage);
|
|
7775
|
+
} else {
|
|
7776
|
+
log(autostartMessage);
|
|
7777
|
+
}
|
|
6427
7778
|
}
|
|
6428
7779
|
}
|
|
6429
|
-
if (
|
|
7780
|
+
if (installSuccess && !result2.alreadyInstalled) {
|
|
6430
7781
|
log("\nNext steps:");
|
|
6431
7782
|
log(" 1. Start or restart OpenCode");
|
|
6432
|
-
log(
|
|
6433
|
-
log(
|
|
7783
|
+
log(` 2. Read npx opendevbrowser --help and start with ${onboarding_metadata_default.quickStartCommands.promptingGuide}`);
|
|
7784
|
+
log(` 3. Or load ${onboarding_metadata_default.skillName} ${onboarding_metadata_default.skillTopic} directly via ${onboarding_metadata_default.quickStartCommands.skillLoad}`);
|
|
7785
|
+
log(" 4. Use opendevbrowser_status to verify the plugin is loaded");
|
|
6434
7786
|
}
|
|
6435
|
-
return { success:
|
|
7787
|
+
return { success: installSuccess, message: result2.message };
|
|
6436
7788
|
}
|
|
6437
7789
|
});
|
|
6438
7790
|
registerCommand({
|
|
@@ -6475,6 +7827,11 @@ async function main() {
|
|
|
6475
7827
|
description: "Get daemon or session status",
|
|
6476
7828
|
run: async () => runStatus(args)
|
|
6477
7829
|
});
|
|
7830
|
+
registerCommand({
|
|
7831
|
+
name: "session-inspector",
|
|
7832
|
+
description: "Capture a session-first diagnostic summary with relay health and trace proof",
|
|
7833
|
+
run: async () => runSessionInspector(args)
|
|
7834
|
+
});
|
|
6478
7835
|
registerCommand({
|
|
6479
7836
|
name: "goto",
|
|
6480
7837
|
description: "Navigate current session to a URL",
|
|
@@ -6490,6 +7847,11 @@ async function main() {
|
|
|
6490
7847
|
description: "Capture a snapshot of the active page",
|
|
6491
7848
|
run: async () => runSnapshot(args)
|
|
6492
7849
|
});
|
|
7850
|
+
registerCommand({
|
|
7851
|
+
name: "review",
|
|
7852
|
+
description: "Capture a first-class review payload for the active page",
|
|
7853
|
+
run: async () => runReview(args)
|
|
7854
|
+
});
|
|
6493
7855
|
registerCommand({
|
|
6494
7856
|
name: "annotate",
|
|
6495
7857
|
description: "Request interactive annotations via direct or relay transport",
|
|
@@ -6550,6 +7912,31 @@ async function main() {
|
|
|
6550
7912
|
description: "Scroll an element into view by ref",
|
|
6551
7913
|
run: async () => runScrollIntoView(args)
|
|
6552
7914
|
});
|
|
7915
|
+
registerCommand({
|
|
7916
|
+
name: "upload",
|
|
7917
|
+
description: "Upload files to a file input or chooser by ref",
|
|
7918
|
+
run: async () => runUpload(args)
|
|
7919
|
+
});
|
|
7920
|
+
registerCommand({
|
|
7921
|
+
name: "pointer-move",
|
|
7922
|
+
description: "Move the pointer to viewport coordinates",
|
|
7923
|
+
run: async () => runPointerMove(args)
|
|
7924
|
+
});
|
|
7925
|
+
registerCommand({
|
|
7926
|
+
name: "pointer-down",
|
|
7927
|
+
description: "Press a mouse button at viewport coordinates",
|
|
7928
|
+
run: async () => runPointerDown(args)
|
|
7929
|
+
});
|
|
7930
|
+
registerCommand({
|
|
7931
|
+
name: "pointer-up",
|
|
7932
|
+
description: "Release a mouse button at viewport coordinates",
|
|
7933
|
+
run: async () => runPointerUp(args)
|
|
7934
|
+
});
|
|
7935
|
+
registerCommand({
|
|
7936
|
+
name: "pointer-drag",
|
|
7937
|
+
description: "Drag the pointer between two viewport coordinates",
|
|
7938
|
+
run: async () => runPointerDrag(args)
|
|
7939
|
+
});
|
|
6553
7940
|
registerCommand({
|
|
6554
7941
|
name: "targets-list",
|
|
6555
7942
|
description: "List page targets",
|
|
@@ -6640,6 +8027,21 @@ async function main() {
|
|
|
6640
8027
|
description: "Capture a screenshot",
|
|
6641
8028
|
run: async () => runScreenshot(args)
|
|
6642
8029
|
});
|
|
8030
|
+
registerCommand({
|
|
8031
|
+
name: "screencast-start",
|
|
8032
|
+
description: "Start a browser replay screencast capture",
|
|
8033
|
+
run: async () => runScreencastStart(args)
|
|
8034
|
+
});
|
|
8035
|
+
registerCommand({
|
|
8036
|
+
name: "screencast-stop",
|
|
8037
|
+
description: "Stop a browser replay screencast capture",
|
|
8038
|
+
run: async () => runScreencastStop(args)
|
|
8039
|
+
});
|
|
8040
|
+
registerCommand({
|
|
8041
|
+
name: "dialog",
|
|
8042
|
+
description: "Inspect or handle a JavaScript dialog",
|
|
8043
|
+
run: async () => runDialog(args)
|
|
8044
|
+
});
|
|
6643
8045
|
registerCommand({
|
|
6644
8046
|
name: "console-poll",
|
|
6645
8047
|
description: "Poll console events",
|
|
@@ -6655,6 +8057,36 @@ async function main() {
|
|
|
6655
8057
|
description: "Capture page + console + network + exception diagnostics",
|
|
6656
8058
|
run: async () => runDebugTraceSnapshot(args)
|
|
6657
8059
|
});
|
|
8060
|
+
registerCommand({
|
|
8061
|
+
name: "desktop-status",
|
|
8062
|
+
description: "Inspect public read-only desktop observation availability",
|
|
8063
|
+
run: async () => runDesktopStatus(args)
|
|
8064
|
+
});
|
|
8065
|
+
registerCommand({
|
|
8066
|
+
name: "desktop-windows",
|
|
8067
|
+
description: "List windows exposed by the public read-only desktop observation plane",
|
|
8068
|
+
run: async () => runDesktopWindows(args)
|
|
8069
|
+
});
|
|
8070
|
+
registerCommand({
|
|
8071
|
+
name: "desktop-active-window",
|
|
8072
|
+
description: "Inspect the active window through the public read-only desktop observation plane",
|
|
8073
|
+
run: async () => runDesktopActiveWindow(args)
|
|
8074
|
+
});
|
|
8075
|
+
registerCommand({
|
|
8076
|
+
name: "desktop-capture-desktop",
|
|
8077
|
+
description: "Capture the current desktop surface through the public read-only desktop observation plane",
|
|
8078
|
+
run: async () => runDesktopCaptureDesktop(args)
|
|
8079
|
+
});
|
|
8080
|
+
registerCommand({
|
|
8081
|
+
name: "desktop-capture-window",
|
|
8082
|
+
description: "Capture a specific window through the public read-only desktop observation plane",
|
|
8083
|
+
run: async () => runDesktopCaptureWindow(args)
|
|
8084
|
+
});
|
|
8085
|
+
registerCommand({
|
|
8086
|
+
name: "desktop-accessibility-snapshot",
|
|
8087
|
+
description: "Capture desktop accessibility state through the public read-only desktop observation plane",
|
|
8088
|
+
run: async () => runDesktopAccessibilitySnapshot(args)
|
|
8089
|
+
});
|
|
6658
8090
|
registerCommand({
|
|
6659
8091
|
name: "cookie-import",
|
|
6660
8092
|
description: "Import validated cookies into a session",
|
|
@@ -6700,17 +8132,19 @@ async function main() {
|
|
|
6700
8132
|
if (exitCode === null) {
|
|
6701
8133
|
return;
|
|
6702
8134
|
}
|
|
6703
|
-
|
|
8135
|
+
await flushOutputAndExit(exitCode);
|
|
8136
|
+
return;
|
|
6704
8137
|
} catch (error) {
|
|
6705
8138
|
const format = outputFormat ?? detectOutputFormat(process.argv);
|
|
6706
8139
|
const cliError = toCliError(error, parseSucceeded ? EXIT_EXECUTION : EXIT_USAGE);
|
|
6707
8140
|
emitFatalError(cliError, format);
|
|
6708
|
-
|
|
8141
|
+
await flushOutputAndExit(cliError.exitCode);
|
|
8142
|
+
return;
|
|
6709
8143
|
}
|
|
6710
8144
|
}
|
|
6711
|
-
main().catch((error) => {
|
|
8145
|
+
main().catch(async (error) => {
|
|
6712
8146
|
const cliError = toCliError(error, EXIT_EXECUTION);
|
|
6713
8147
|
emitFatalError(cliError, detectOutputFormat(process.argv));
|
|
6714
|
-
|
|
8148
|
+
await flushOutputAndExit(cliError.exitCode);
|
|
6715
8149
|
});
|
|
6716
8150
|
//# sourceMappingURL=index.js.map
|