@zenalexa/unicli 0.213.1 → 0.215.0
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/AGENTS.md +10 -10
- package/README.md +40 -27
- package/README.zh-CN.md +36 -36
- package/dist/adapters/_electron/desktop-shared.d.ts +12 -0
- package/dist/adapters/_electron/desktop-shared.d.ts.map +1 -0
- package/dist/adapters/_electron/desktop-shared.js +312 -0
- package/dist/adapters/_electron/desktop-shared.js.map +1 -0
- package/dist/adapters/electron-desktop/electron-desktop.d.ts +9 -0
- package/dist/adapters/electron-desktop/electron-desktop.d.ts.map +1 -0
- package/dist/adapters/electron-desktop/electron-desktop.js +56 -0
- package/dist/adapters/electron-desktop/electron-desktop.js.map +1 -0
- package/dist/browser/adapter-authoring.d.ts +20 -0
- package/dist/browser/adapter-authoring.d.ts.map +1 -0
- package/dist/browser/adapter-authoring.js +68 -0
- package/dist/browser/adapter-authoring.js.map +1 -0
- package/dist/browser/analyze.d.ts +54 -0
- package/dist/browser/analyze.d.ts.map +1 -0
- package/dist/browser/analyze.js +205 -0
- package/dist/browser/analyze.js.map +1 -0
- package/dist/browser/bridge.d.ts +1 -1
- package/dist/browser/bridge.d.ts.map +1 -1
- package/dist/browser/bridge.js +2 -0
- package/dist/browser/bridge.js.map +1 -1
- package/dist/browser/daemon-client.d.ts.map +1 -1
- package/dist/browser/daemon-client.js +12 -1
- package/dist/browser/daemon-client.js.map +1 -1
- package/dist/browser/network-cache.d.ts +58 -0
- package/dist/browser/network-cache.d.ts.map +1 -0
- package/dist/browser/network-cache.js +146 -0
- package/dist/browser/network-cache.js.map +1 -0
- package/dist/browser/page.d.ts +1 -1
- package/dist/browser/page.d.ts.map +1 -1
- package/dist/browser/page.js +2 -1
- package/dist/browser/page.js.map +1 -1
- package/dist/browser/protocol.d.ts +6 -2
- package/dist/browser/protocol.d.ts.map +1 -1
- package/dist/browser/site-memory.d.ts +57 -0
- package/dist/browser/site-memory.d.ts.map +1 -0
- package/dist/browser/site-memory.js +127 -0
- package/dist/browser/site-memory.js.map +1 -0
- package/dist/browser/verify-fixture.d.ts +30 -0
- package/dist/browser/verify-fixture.d.ts.map +1 -0
- package/dist/browser/verify-fixture.js +168 -0
- package/dist/browser/verify-fixture.js.map +1 -0
- package/dist/browser/workspace.d.ts +8 -0
- package/dist/browser/workspace.d.ts.map +1 -0
- package/dist/browser/workspace.js +15 -0
- package/dist/browser/workspace.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/browser-adapter-authoring.d.ts +3 -0
- package/dist/commands/browser-adapter-authoring.d.ts.map +1 -0
- package/dist/commands/browser-adapter-authoring.js +206 -0
- package/dist/commands/browser-adapter-authoring.js.map +1 -0
- package/dist/commands/browser-authoring-operator.d.ts +3 -0
- package/dist/commands/browser-authoring-operator.d.ts.map +1 -0
- package/dist/commands/browser-authoring-operator.js +110 -0
- package/dist/commands/browser-authoring-operator.js.map +1 -0
- package/dist/commands/browser-operator-runtime.d.ts +38 -0
- package/dist/commands/browser-operator-runtime.d.ts.map +1 -0
- package/dist/commands/browser-operator-runtime.js +281 -0
- package/dist/commands/browser-operator-runtime.js.map +1 -0
- package/dist/commands/browser-operator.d.ts +6 -0
- package/dist/commands/browser-operator.d.ts.map +1 -0
- package/dist/commands/browser-operator.js +374 -0
- package/dist/commands/browser-operator.js.map +1 -0
- package/dist/commands/browser.d.ts.map +1 -1
- package/dist/commands/browser.js +72 -1
- package/dist/commands/browser.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +40 -4
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/describe.d.ts +26 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/describe.js +230 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/dev.js +1 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/dispatch.d.ts +14 -3
- package/dist/commands/dispatch.d.ts.map +1 -1
- package/dist/commands/dispatch.js +141 -81
- package/dist/commands/dispatch.js.map +1 -1
- package/dist/commands/explore.d.ts.map +1 -1
- package/dist/commands/explore.js +4 -1
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +4 -1
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +14 -14
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/migrate-schema.d.ts.map +1 -1
- package/dist/commands/migrate-schema.js +10 -0
- package/dist/commands/migrate-schema.js.map +1 -1
- package/dist/commands/operate.d.ts +4 -3
- package/dist/commands/operate.d.ts.map +1 -1
- package/dist/commands/operate.js +8 -483
- package/dist/commands/operate.js.map +1 -1
- package/dist/commands/record.d.ts.map +1 -1
- package/dist/commands/record.js +2 -1
- package/dist/commands/record.js.map +1 -1
- package/dist/commands/search.js +1 -1
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +2 -2
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/synthesize.d.ts.map +1 -1
- package/dist/commands/synthesize.js +33 -3
- package/dist/commands/synthesize.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -1
- package/dist/discovery/aliases.d.ts.map +1 -1
- package/dist/discovery/aliases.js +76 -1
- package/dist/discovery/aliases.js.map +1 -1
- package/dist/discovery/loader.d.ts +8 -0
- package/dist/discovery/loader.d.ts.map +1 -1
- package/dist/discovery/loader.js +25 -2
- package/dist/discovery/loader.js.map +1 -1
- package/dist/electron-apps.d.ts +22 -0
- package/dist/electron-apps.d.ts.map +1 -1
- package/dist/electron-apps.js +324 -0
- package/dist/electron-apps.js.map +1 -1
- package/dist/engine/args.d.ts +83 -0
- package/dist/engine/args.d.ts.map +1 -0
- package/dist/engine/args.js +260 -0
- package/dist/engine/args.js.map +1 -0
- package/dist/engine/download.d.ts.map +1 -1
- package/dist/engine/download.js +12 -5
- package/dist/engine/download.js.map +1 -1
- package/dist/engine/executor.d.ts +20 -1
- package/dist/engine/executor.d.ts.map +1 -1
- package/dist/engine/executor.js +11 -2
- package/dist/engine/executor.js.map +1 -1
- package/dist/engine/harden.d.ts +48 -0
- package/dist/engine/harden.d.ts.map +1 -0
- package/dist/engine/harden.js +327 -0
- package/dist/engine/harden.js.map +1 -0
- package/dist/engine/invoke.d.ts +16 -0
- package/dist/engine/invoke.d.ts.map +1 -0
- package/dist/engine/invoke.js +15 -0
- package/dist/engine/invoke.js.map +1 -0
- package/dist/engine/kernel/compile.d.ts +30 -0
- package/dist/engine/kernel/compile.d.ts.map +1 -0
- package/dist/engine/kernel/compile.js +167 -0
- package/dist/engine/kernel/compile.js.map +1 -0
- package/dist/engine/kernel/execute.d.ts +35 -0
- package/dist/engine/kernel/execute.d.ts.map +1 -0
- package/dist/engine/kernel/execute.js +221 -0
- package/dist/engine/kernel/execute.js.map +1 -0
- package/dist/engine/kernel/types.d.ts +49 -0
- package/dist/engine/kernel/types.d.ts.map +1 -0
- package/dist/engine/kernel/types.js +9 -0
- package/dist/engine/kernel/types.js.map +1 -0
- package/dist/engine/kernel/ulid.d.ts +21 -0
- package/dist/engine/kernel/ulid.d.ts.map +1 -0
- package/dist/engine/kernel/ulid.js +76 -0
- package/dist/engine/kernel/ulid.js.map +1 -0
- package/dist/engine/repair/engine.js +2 -2
- package/dist/engine/repair/engine.js.map +1 -1
- package/dist/engine/steps/desktop-ax.d.ts +10 -0
- package/dist/engine/steps/desktop-ax.d.ts.map +1 -1
- package/dist/engine/steps/desktop-ax.js +20 -0
- package/dist/engine/steps/desktop-ax.js.map +1 -1
- package/dist/engine/steps/exec.d.ts +1 -1
- package/dist/engine/steps/exec.d.ts.map +1 -1
- package/dist/engine/steps/exec.js +20 -1
- package/dist/engine/steps/exec.js.map +1 -1
- package/dist/engine/steps/write-temp.js +1 -1
- package/dist/engine/steps/write-temp.js.map +1 -1
- package/dist/engine/template.d.ts.map +1 -1
- package/dist/engine/template.js +21 -2
- package/dist/engine/template.js.map +1 -1
- package/dist/manifest-compact.txt +8 -7
- package/dist/manifest-search.json +1 -1
- package/dist/manifest.json +2161 -171
- package/dist/mcp/dispatch.d.ts +46 -0
- package/dist/mcp/dispatch.d.ts.map +1 -0
- package/dist/mcp/dispatch.js +109 -0
- package/dist/mcp/dispatch.js.map +1 -0
- package/dist/mcp/handler.d.ts +30 -0
- package/dist/mcp/handler.d.ts.map +1 -0
- package/dist/mcp/handler.js +293 -0
- package/dist/mcp/handler.js.map +1 -0
- package/dist/mcp/http-transport.d.ts +16 -0
- package/dist/mcp/http-transport.d.ts.map +1 -0
- package/dist/mcp/http-transport.js +121 -0
- package/dist/mcp/http-transport.js.map +1 -0
- package/dist/mcp/server.d.ts +17 -33
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +31 -742
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/sse-transport.js.map +1 -1
- package/dist/mcp/streamable-http/handle-post.d.ts +23 -0
- package/dist/mcp/streamable-http/handle-post.d.ts.map +1 -0
- package/dist/mcp/streamable-http/handle-post.js +357 -0
- package/dist/mcp/streamable-http/handle-post.js.map +1 -0
- package/dist/mcp/streamable-http/index.d.ts +45 -0
- package/dist/mcp/streamable-http/index.d.ts.map +1 -0
- package/dist/mcp/streamable-http/index.js +150 -0
- package/dist/mcp/streamable-http/index.js.map +1 -0
- package/dist/mcp/streamable-http/session.d.ts +85 -0
- package/dist/mcp/streamable-http/session.d.ts.map +1 -0
- package/dist/mcp/streamable-http/session.js +104 -0
- package/dist/mcp/streamable-http/session.js.map +1 -0
- package/dist/mcp/streamable-http.d.ts +7 -85
- package/dist/mcp/streamable-http.d.ts.map +1 -1
- package/dist/mcp/streamable-http.js +6 -568
- package/dist/mcp/streamable-http.js.map +1 -1
- package/dist/mcp/tools.d.ts +58 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +241 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/output/envelope.d.ts +30 -5
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +7 -5
- package/dist/output/envelope.js.map +1 -1
- package/dist/output/formatter.d.ts +2 -2
- package/dist/output/formatter.js +3 -3
- package/dist/output/formatter.js.map +1 -1
- package/dist/output/next-actions.d.ts +18 -0
- package/dist/output/next-actions.d.ts.map +1 -0
- package/dist/output/next-actions.js +64 -0
- package/dist/output/next-actions.js.map +1 -0
- package/dist/output/projection.d.ts +93 -0
- package/dist/output/projection.d.ts.map +1 -0
- package/dist/output/projection.js +255 -0
- package/dist/output/projection.js.map +1 -0
- package/dist/protocol/acp-helpers.d.ts +32 -0
- package/dist/protocol/acp-helpers.d.ts.map +1 -0
- package/dist/protocol/acp-helpers.js +175 -0
- package/dist/protocol/acp-helpers.js.map +1 -0
- package/dist/protocol/acp.d.ts +2 -27
- package/dist/protocol/acp.d.ts.map +1 -1
- package/dist/protocol/acp.js +7 -170
- package/dist/protocol/acp.js.map +1 -1
- package/dist/transport/adapters/cua.d.ts +9 -10
- package/dist/transport/adapters/cua.d.ts.map +1 -1
- package/dist/transport/adapters/cua.js +22 -24
- package/dist/transport/adapters/cua.js.map +1 -1
- package/dist/transport/adapters/desktop-atspi.d.ts +1 -1
- package/dist/transport/adapters/desktop-atspi.js +2 -2
- package/dist/transport/adapters/desktop-atspi.js.map +1 -1
- package/dist/transport/adapters/desktop-ax-background-click-swift.d.ts +11 -0
- package/dist/transport/adapters/desktop-ax-background-click-swift.d.ts.map +1 -0
- package/dist/transport/adapters/desktop-ax-background-click-swift.js +136 -0
- package/dist/transport/adapters/desktop-ax-background-click-swift.js.map +1 -0
- package/dist/transport/adapters/desktop-ax-background-click.d.ts +4 -0
- package/dist/transport/adapters/desktop-ax-background-click.d.ts.map +1 -0
- package/dist/transport/adapters/desktop-ax-background-click.js +70 -0
- package/dist/transport/adapters/desktop-ax-background-click.js.map +1 -0
- package/dist/transport/adapters/desktop-ax-swift.d.ts +56 -0
- package/dist/transport/adapters/desktop-ax-swift.d.ts.map +1 -0
- package/dist/transport/adapters/desktop-ax-swift.js +458 -0
- package/dist/transport/adapters/desktop-ax-swift.js.map +1 -0
- package/dist/transport/adapters/desktop-ax.d.ts +14 -0
- package/dist/transport/adapters/desktop-ax.d.ts.map +1 -1
- package/dist/transport/adapters/desktop-ax.js +262 -32
- package/dist/transport/adapters/desktop-ax.js.map +1 -1
- package/dist/transport/adapters/desktop-uia.d.ts +1 -1
- package/dist/transport/adapters/desktop-uia.js +2 -2
- package/dist/transport/adapters/desktop-uia.js.map +1 -1
- package/dist/transport/adapters/http.js +1 -1
- package/dist/transport/adapters/http.js.map +1 -1
- package/dist/transport/capability.d.ts +1 -1
- package/dist/transport/capability.d.ts.map +1 -1
- package/dist/transport/capability.js +6 -1
- package/dist/transport/capability.js.map +1 -1
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +14 -3
- package/src/adapters/1688/item.yaml +1 -0
- package/src/adapters/1688/store.yaml +1 -0
- package/src/adapters/36kr/article.yaml +1 -0
- package/src/adapters/_electron/desktop-shared.ts +383 -0
- package/src/adapters/amazon/bestsellers.yaml +2 -0
- package/src/adapters/amazon/movers-shakers.yaml +2 -0
- package/src/adapters/amazon/new-releases.yaml +2 -0
- package/src/adapters/amazon/rankings.yaml +1 -0
- package/src/adapters/apple-podcasts/episodes.yaml +1 -0
- package/src/adapters/arxiv/paper.yaml +1 -0
- package/src/adapters/audacity/convert.yaml +1 -0
- package/src/adapters/audacity/effects.yaml +1 -0
- package/src/adapters/audacity/info.yaml +1 -0
- package/src/adapters/audacity/mix.yaml +1 -0
- package/src/adapters/audacity/normalize.yaml +1 -0
- package/src/adapters/audacity/spectrogram.yaml +1 -0
- package/src/adapters/audacity/split-channels.yaml +1 -0
- package/src/adapters/audacity/trim.yaml +1 -0
- package/src/adapters/bilibili/favorites.yaml +1 -0
- package/src/adapters/blender/animation.yaml +2 -0
- package/src/adapters/blender/camera.yaml +1 -0
- package/src/adapters/blender/convert.yaml +1 -0
- package/src/adapters/blender/export.yaml +1 -0
- package/src/adapters/blender/import.yaml +1 -0
- package/src/adapters/blender/info.yaml +1 -0
- package/src/adapters/blender/lighting.yaml +1 -0
- package/src/adapters/blender/materials.yaml +1 -0
- package/src/adapters/blender/objects.yaml +1 -0
- package/src/adapters/blender/render.yaml +2 -0
- package/src/adapters/blender/scene.yaml +1 -0
- package/src/adapters/blender/screenshot.yaml +2 -0
- package/src/adapters/blender/script.yaml +1 -0
- package/src/adapters/boss/detail.yaml +2 -0
- package/src/adapters/cloudcompare/info.yaml +1 -0
- package/src/adapters/coupang/add-to-cart.yaml +1 -0
- package/src/adapters/ctrip/search.yaml +1 -0
- package/src/adapters/docker/build.yaml +1 -1
- package/src/adapters/docker/images.yaml +1 -1
- package/src/adapters/docker/logs.yaml +1 -1
- package/src/adapters/docker/networks.yaml +1 -1
- package/src/adapters/docker/ps.yaml +1 -1
- package/src/adapters/docker/run.yaml +1 -1
- package/src/adapters/docker/volumes.yaml +1 -1
- package/src/adapters/douban/download.yaml +1 -0
- package/src/adapters/douban/photos.yaml +1 -0
- package/src/adapters/douban/subject.yaml +2 -0
- package/src/adapters/doubao-web/detail.yaml +1 -0
- package/src/adapters/doubao-web/meeting-summary.yaml +1 -0
- package/src/adapters/doubao-web/meeting-transcript.yaml +1 -0
- package/src/adapters/drawio/export.yaml +2 -0
- package/src/adapters/electron-desktop/electron-desktop.ts +57 -0
- package/src/adapters/facebook/join-group.yaml +2 -0
- package/src/adapters/ffmpeg/compress.yaml +2 -0
- package/src/adapters/ffmpeg/concat.yaml +1 -0
- package/src/adapters/ffmpeg/convert.yaml +1 -0
- package/src/adapters/ffmpeg/extract-audio.yaml +2 -0
- package/src/adapters/ffmpeg/gif.yaml +2 -0
- package/src/adapters/ffmpeg/normalize.yaml +2 -0
- package/src/adapters/ffmpeg/probe.yaml +1 -0
- package/src/adapters/ffmpeg/resize.yaml +2 -0
- package/src/adapters/ffmpeg/subtitles.yaml +2 -0
- package/src/adapters/ffmpeg/thumbnail.yaml +2 -0
- package/src/adapters/ffmpeg/trim.yaml +2 -0
- package/src/adapters/freecad/assembly.yaml +1 -0
- package/src/adapters/freecad/bom.yaml +1 -0
- package/src/adapters/freecad/boolean.yaml +1 -0
- package/src/adapters/freecad/check.yaml +1 -0
- package/src/adapters/freecad/convert.yaml +1 -0
- package/src/adapters/freecad/export-stl.yaml +1 -0
- package/src/adapters/freecad/import.yaml +1 -0
- package/src/adapters/freecad/info.yaml +1 -0
- package/src/adapters/freecad/macro.yaml +1 -0
- package/src/adapters/freecad/measure.yaml +1 -0
- package/src/adapters/freecad/mesh.yaml +1 -0
- package/src/adapters/freecad/properties.yaml +1 -0
- package/src/adapters/freecad/render.yaml +1 -0
- package/src/adapters/freecad/section.yaml +1 -0
- package/src/adapters/freecad/sketch.yaml +1 -0
- package/src/adapters/gimp/adjust.yaml +1 -0
- package/src/adapters/gimp/batch.yaml +1 -0
- package/src/adapters/gimp/convert.yaml +1 -0
- package/src/adapters/gimp/crop.yaml +1 -0
- package/src/adapters/gimp/filter.yaml +1 -0
- package/src/adapters/gimp/flip.yaml +1 -0
- package/src/adapters/gimp/info.yaml +1 -0
- package/src/adapters/gimp/layers.yaml +1 -0
- package/src/adapters/gimp/merge-layers.yaml +1 -0
- package/src/adapters/gimp/resize.yaml +1 -0
- package/src/adapters/gimp/rotate.yaml +1 -0
- package/src/adapters/gimp/text.yaml +1 -0
- package/src/adapters/godot/scene-export.yaml +1 -0
- package/src/adapters/hackernews/comments.yaml +1 -0
- package/src/adapters/hackernews/item.yaml +1 -0
- package/src/adapters/hf/top.yaml +1 -0
- package/src/adapters/imagemagick/composite.yaml +1 -0
- package/src/adapters/imagemagick/convert.yaml +1 -0
- package/src/adapters/imagemagick/identify.yaml +1 -0
- package/src/adapters/imagemagick/montage.yaml +1 -0
- package/src/adapters/imagemagick/resize.yaml +1 -0
- package/src/adapters/imdb/person.yaml +1 -0
- package/src/adapters/imdb/reviews.yaml +1 -0
- package/src/adapters/imdb/title.yaml +1 -0
- package/src/adapters/inkscape/convert.yaml +2 -0
- package/src/adapters/inkscape/export.yaml +2 -0
- package/src/adapters/inkscape/optimize.yaml +2 -0
- package/src/adapters/instagram/stories.yaml +1 -0
- package/src/adapters/jd/item.yaml +1 -0
- package/src/adapters/jike/post.yaml +2 -0
- package/src/adapters/jike/topic.yaml +2 -0
- package/src/adapters/kdenlive/info.yaml +1 -0
- package/src/adapters/kdenlive/render.yaml +1 -0
- package/src/adapters/krita/batch.yaml +1 -0
- package/src/adapters/krita/convert.yaml +1 -0
- package/src/adapters/krita/export.yaml +1 -0
- package/src/adapters/krita/info.yaml +1 -0
- package/src/adapters/libreoffice/convert.yaml +1 -0
- package/src/adapters/libreoffice/print.yaml +1 -0
- package/src/adapters/linear/issue-update.yaml +1 -0
- package/src/adapters/linux-do/category.yaml +1 -0
- package/src/adapters/linux-do/topic.yaml +1 -0
- package/src/adapters/macos/caffeinate.yaml +2 -2
- package/src/adapters/macos/calendar-create.yaml +1 -0
- package/src/adapters/macos/finder-copy.yaml +1 -0
- package/src/adapters/macos/finder-move.yaml +1 -0
- package/src/adapters/macos/finder-new-folder.yaml +1 -0
- package/src/adapters/macos/finder-tags.yaml +1 -0
- package/src/adapters/macos/open.yaml +2 -0
- package/src/adapters/macos/processes.yaml +3 -3
- package/src/adapters/macos/screen-recording.yaml +3 -2
- package/src/adapters/macos/screenshot.yaml +1 -0
- package/src/adapters/macos/spotlight.yaml +1 -0
- package/src/adapters/macos/wallpaper.yaml +1 -0
- package/src/adapters/medium/article.yaml +1 -0
- package/src/adapters/mermaid/render.yaml +1 -0
- package/src/adapters/minimax/tts.yaml +1 -0
- package/src/adapters/motion-studio/component-get.yaml +1 -0
- package/src/adapters/musescore/convert.yaml +2 -0
- package/src/adapters/musescore/export.yaml +2 -0
- package/src/adapters/musescore/info.yaml +1 -0
- package/src/adapters/musescore/instruments.yaml +1 -0
- package/src/adapters/musescore/transpose.yaml +1 -0
- package/src/adapters/netease-music/playlist.yaml +1 -0
- package/src/adapters/netease-music/top.yaml +1 -0
- package/src/adapters/notebooklm/get.yaml +1 -0
- package/src/adapters/notebooklm/history.yaml +1 -0
- package/src/adapters/notebooklm/note-list.yaml +1 -0
- package/src/adapters/notebooklm/notes-get.yaml +1 -0
- package/src/adapters/notebooklm/open.yaml +1 -0
- package/src/adapters/notebooklm/source-fulltext.yaml +1 -0
- package/src/adapters/notebooklm/source-get.yaml +1 -0
- package/src/adapters/notebooklm/source-guide.yaml +1 -0
- package/src/adapters/notebooklm/source-list.yaml +1 -0
- package/src/adapters/notebooklm/summary.yaml +1 -0
- package/src/adapters/novita/status.yaml +1 -0
- package/src/adapters/obs/screenshot.yaml +1 -0
- package/src/adapters/obsidian/open.yaml +1 -0
- package/src/adapters/ones/login.yaml +1 -0
- package/src/adapters/ones/task.yaml +1 -0
- package/src/adapters/pandoc/convert.yaml +1 -0
- package/src/adapters/paperreview/feedback.yaml +2 -0
- package/src/adapters/paperreview/review.yaml +2 -0
- package/src/adapters/paperreview/submit.yaml +2 -0
- package/src/adapters/pixiv/detail.yaml +1 -0
- package/src/adapters/pixiv/download.yaml +2 -0
- package/src/adapters/quark/ls.yaml +1 -0
- package/src/adapters/reddit/comments.yaml +2 -0
- package/src/adapters/renderdoc/capture-list.yaml +1 -0
- package/src/adapters/renderdoc/frame-export.yaml +1 -0
- package/src/adapters/reuters/article.yaml +2 -0
- package/src/adapters/shotcut/info.yaml +1 -0
- package/src/adapters/shotcut/render.yaml +1 -0
- package/src/adapters/sinablog/article.yaml +1 -0
- package/src/adapters/sinablog/user.yaml +1 -0
- package/src/adapters/sketch/artboards.yaml +1 -0
- package/src/adapters/sketch/export.yaml +1 -0
- package/src/adapters/sketch/symbols.yaml +1 -0
- package/src/adapters/smzdm/article.yaml +1 -0
- package/src/adapters/stackoverflow/question.yaml +1 -0
- package/src/adapters/stagehand/wrap-observe.yaml +1 -0
- package/src/adapters/steam/wishlist.yaml +1 -0
- package/src/adapters/substack/trending.yaml +2 -1
- package/src/adapters/tieba/read.yaml +1 -0
- package/src/adapters/tiktok/comment.yaml +1 -0
- package/src/adapters/tiktok/like.yaml +1 -0
- package/src/adapters/tiktok/save.yaml +1 -0
- package/src/adapters/tiktok/unlike.yaml +1 -0
- package/src/adapters/tiktok/unsave.yaml +1 -0
- package/src/adapters/twitch/streams.yaml +1 -0
- package/src/adapters/twitter/quotes.yaml +2 -0
- package/src/adapters/twitter/retweets.yaml +1 -0
- package/src/adapters/v2ex/replies.yaml +1 -0
- package/src/adapters/v2ex/topic.yaml +1 -0
- package/src/adapters/vscode/install-ext.yaml +1 -0
- package/src/adapters/vscode/open.yaml +1 -0
- package/src/adapters/web/read.yaml +1 -0
- package/src/adapters/weibo/comments.yaml +1 -0
- package/src/adapters/weibo/post.yaml +1 -0
- package/src/adapters/weixin/download.yaml +1 -0
- package/src/adapters/wiremock/create-stub.yaml +2 -0
- package/src/adapters/wiremock/delete-stub.yaml +1 -0
- package/src/adapters/wiremock/verify.yaml +1 -0
- package/src/adapters/xianyu/item.yaml +1 -0
- package/src/adapters/xiaoe/catalog.yaml +1 -0
- package/src/adapters/xiaoe/content.yaml +1 -0
- package/src/adapters/xiaoe/detail.yaml +1 -0
- package/src/adapters/xiaoe/play-url.yaml +1 -0
- package/src/adapters/xiaoyuzhou/podcast.yaml +2 -0
- package/src/adapters/yollomi/edit.yaml +2 -0
- package/src/adapters/yollomi/remove-bg.yaml +2 -0
- package/src/adapters/yollomi/restore.yaml +2 -0
- package/src/adapters/yollomi/upload.yaml +2 -0
- package/src/adapters/yollomi/upscale.yaml +2 -0
- package/src/adapters/youtube/playlist.yaml +1 -0
- package/src/adapters/yt-dlp/download.yaml +2 -0
- package/src/adapters/yt-dlp/extract-audio.yaml +2 -0
- package/src/adapters/yt-dlp/info.yaml +1 -0
- package/src/adapters/zhihu/answer.yaml +1 -0
- package/src/adapters/zhihu/answers.yaml +2 -0
- package/src/adapters/zhihu/article.yaml +1 -0
- package/src/adapters/zhihu/articles.yaml +2 -0
- package/src/adapters/zhihu/collections.yaml +2 -0
- package/src/adapters/zhihu/columns.yaml +2 -0
- package/src/adapters/zhihu/comment.yaml +1 -0
- package/src/adapters/zhihu/download.yaml +1 -0
- package/src/adapters/zhihu/followers.yaml +2 -0
- package/src/adapters/zhihu/following.yaml +2 -0
- package/src/adapters/zhihu/pins.yaml +2 -0
- package/src/adapters/zhihu/question.yaml +1 -0
- package/src/adapters/zhihu/topic.yaml +1 -0
- package/src/adapters/zhihu/topics.yaml +1 -0
- package/src/adapters/zhihu/user.yaml +2 -0
- package/src/adapters/zoom/join.yaml +1 -0
- package/src/adapters/zsxq/search.yaml +1 -0
- package/src/adapters/zsxq/topic.yaml +1 -0
- package/src/adapters/zsxq/topics.yaml +1 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
import { BrowserBridge } from "../browser/bridge.js";
|
|
4
|
+
import { resolveBrowserWorkspace } from "../browser/workspace.js";
|
|
5
|
+
import { generateInterceptorJs, generateReadInterceptedJs, } from "../engine/interceptor.js";
|
|
6
|
+
import { buildSensitivePathDenial, isSensitivePathRealpath, } from "../permissions/sensitive-paths.js";
|
|
7
|
+
import { detectFormat, format } from "../output/formatter.js";
|
|
8
|
+
import { makeCtx } from "../output/envelope.js";
|
|
9
|
+
import { errorTypeToCode, mapErrorToExitCode } from "../output/error-map.js";
|
|
10
|
+
export function validateRef(ref) {
|
|
11
|
+
if (!/^\d+$/.test(ref)) {
|
|
12
|
+
throw new Error(`Invalid ref "${ref}". Expected a number from the state output.`);
|
|
13
|
+
}
|
|
14
|
+
return ref;
|
|
15
|
+
}
|
|
16
|
+
function getRootOpts(root) {
|
|
17
|
+
return root.opts();
|
|
18
|
+
}
|
|
19
|
+
export function resolveWorkspace(root, namespace) {
|
|
20
|
+
const opts = getRootOpts(root);
|
|
21
|
+
return resolveBrowserWorkspace(namespace, {
|
|
22
|
+
workspace: opts.workspace,
|
|
23
|
+
isolated: opts.isolated,
|
|
24
|
+
sharedSession: opts.sharedSession,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export async function withBrowserOperatorEnv(root, fn) {
|
|
28
|
+
const opts = getRootOpts(root);
|
|
29
|
+
const prevPort = process.env.UNICLI_DAEMON_PORT;
|
|
30
|
+
const prevFocus = process.env.UNICLI_WINDOW_FOCUSED;
|
|
31
|
+
if (opts.daemonPort) {
|
|
32
|
+
process.env.UNICLI_DAEMON_PORT = opts.daemonPort;
|
|
33
|
+
}
|
|
34
|
+
if (opts.focus) {
|
|
35
|
+
process.env.UNICLI_WINDOW_FOCUSED = "1";
|
|
36
|
+
}
|
|
37
|
+
else if (opts.background) {
|
|
38
|
+
process.env.UNICLI_WINDOW_FOCUSED = "0";
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return await fn();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
if (opts.daemonPort) {
|
|
45
|
+
if (prevPort === undefined)
|
|
46
|
+
delete process.env.UNICLI_DAEMON_PORT;
|
|
47
|
+
else
|
|
48
|
+
process.env.UNICLI_DAEMON_PORT = prevPort;
|
|
49
|
+
}
|
|
50
|
+
if (opts.focus || opts.background) {
|
|
51
|
+
if (prevFocus === undefined)
|
|
52
|
+
delete process.env.UNICLI_WINDOW_FOCUSED;
|
|
53
|
+
else
|
|
54
|
+
process.env.UNICLI_WINDOW_FOCUSED = prevFocus;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function getOperatorPage(root, namespace) {
|
|
59
|
+
const bridge = new BrowserBridge();
|
|
60
|
+
const page = await bridge.connect({
|
|
61
|
+
timeout: 30_000,
|
|
62
|
+
workspace: resolveWorkspace(root, namespace),
|
|
63
|
+
});
|
|
64
|
+
return page;
|
|
65
|
+
}
|
|
66
|
+
export async function operatorAction(program, root, namespace, name, fn) {
|
|
67
|
+
const startedAt = Date.now();
|
|
68
|
+
const ctx = makeCtx(`${namespace}.${name.split(" ").join("_")}`, startedAt);
|
|
69
|
+
const fmt = detectFormat(program.opts().format);
|
|
70
|
+
try {
|
|
71
|
+
const result = await withBrowserOperatorEnv(root, fn);
|
|
72
|
+
let data;
|
|
73
|
+
if (result === undefined || result === null) {
|
|
74
|
+
data = { ok: true };
|
|
75
|
+
}
|
|
76
|
+
else if (typeof result === "string") {
|
|
77
|
+
data = { value: result };
|
|
78
|
+
}
|
|
79
|
+
else if (Array.isArray(result)) {
|
|
80
|
+
data = result;
|
|
81
|
+
}
|
|
82
|
+
else if (typeof result === "object") {
|
|
83
|
+
data = result;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
data = { value: String(result) };
|
|
87
|
+
}
|
|
88
|
+
ctx.duration_ms = Date.now() - startedAt;
|
|
89
|
+
console.log(format(data, undefined, fmt, ctx));
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
93
|
+
const tagged = err;
|
|
94
|
+
ctx.error = {
|
|
95
|
+
code: tagged.code ?? errorTypeToCode(err),
|
|
96
|
+
message,
|
|
97
|
+
...(tagged.suggestion ? { suggestion: tagged.suggestion } : {}),
|
|
98
|
+
retryable: /timeout|ETIMEDOUT|ECONNREFUSED|ECONNRESET|daemon failed/i.test(message),
|
|
99
|
+
};
|
|
100
|
+
ctx.duration_ms = Date.now() - startedAt;
|
|
101
|
+
console.error(format(null, undefined, fmt, ctx));
|
|
102
|
+
process.exitCode = mapErrorToExitCode(err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export async function ensureNetworkCapture(page) {
|
|
106
|
+
const pageAny = page;
|
|
107
|
+
let captureStarted = false;
|
|
108
|
+
if (typeof pageAny.startNetworkCapture === "function") {
|
|
109
|
+
captureStarted = (await pageAny.startNetworkCapture()) !== false;
|
|
110
|
+
}
|
|
111
|
+
if (!captureStarted) {
|
|
112
|
+
try {
|
|
113
|
+
await page.evaluate(generateInterceptorJs("", { captureText: true }));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Best effort only.
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export async function readNetworkEntries(page) {
|
|
121
|
+
const pageAny = page;
|
|
122
|
+
if (typeof pageAny.readNetworkCapture === "function") {
|
|
123
|
+
const rawEntries = (await pageAny.readNetworkCapture()) ?? [];
|
|
124
|
+
if (rawEntries.length > 0) {
|
|
125
|
+
return {
|
|
126
|
+
raw: rawEntries,
|
|
127
|
+
normalized: rawEntries.map((entry) => ({
|
|
128
|
+
url: entry.url,
|
|
129
|
+
method: entry.method,
|
|
130
|
+
status: entry.status,
|
|
131
|
+
contentType: entry.contentType,
|
|
132
|
+
bodySize: entry.size,
|
|
133
|
+
...(entry.responseBody ? { body: entry.responseBody } : {}),
|
|
134
|
+
})),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const raw = (await page.evaluate(generateReadInterceptedJs()));
|
|
140
|
+
const parsed = JSON.parse(raw);
|
|
141
|
+
if (parsed.length > 0) {
|
|
142
|
+
return {
|
|
143
|
+
raw: parsed,
|
|
144
|
+
normalized: parsed.map((entry) => ({
|
|
145
|
+
url: entry.url,
|
|
146
|
+
method: entry.method ?? "GET",
|
|
147
|
+
status: entry.status ?? 200,
|
|
148
|
+
contentType: entry.type === "text" ? "text/plain" : "application/json",
|
|
149
|
+
bodySize: entry.data == null ? 0 : JSON.stringify(entry.data).length,
|
|
150
|
+
...(entry.data !== undefined ? { body: entry.data } : {}),
|
|
151
|
+
})),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Interceptor not installed or buffer malformed.
|
|
157
|
+
}
|
|
158
|
+
const requests = await page.networkRequests();
|
|
159
|
+
return {
|
|
160
|
+
raw: requests,
|
|
161
|
+
normalized: requests.map((request) => ({
|
|
162
|
+
url: request.url,
|
|
163
|
+
method: request.method,
|
|
164
|
+
status: request.status,
|
|
165
|
+
contentType: request.type,
|
|
166
|
+
bodySize: request.size,
|
|
167
|
+
})),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export async function readFrames(page) {
|
|
171
|
+
const raw = (await page.sendCDP("Page.getFrameTree"));
|
|
172
|
+
const frames = [];
|
|
173
|
+
function walk(tree, includeSelf) {
|
|
174
|
+
if (!tree)
|
|
175
|
+
return;
|
|
176
|
+
if (includeSelf && tree.frame?.id) {
|
|
177
|
+
frames.push({
|
|
178
|
+
index: frames.length,
|
|
179
|
+
frameId: tree.frame.id,
|
|
180
|
+
parentFrameId: tree.frame.parentId,
|
|
181
|
+
url: tree.frame.url ?? "",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
for (const child of tree.childFrames ?? []) {
|
|
185
|
+
walk(child, true);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
walk(raw.frameTree ?? null, false);
|
|
189
|
+
return frames;
|
|
190
|
+
}
|
|
191
|
+
export function buildFindJs(selector, limit, textMax) {
|
|
192
|
+
const selectorJson = JSON.stringify(selector);
|
|
193
|
+
return `(() => {
|
|
194
|
+
const matches = Array.from(document.querySelectorAll(${selectorJson})).slice(0, ${String(limit)});
|
|
195
|
+
let maxRef = 0;
|
|
196
|
+
for (const node of document.querySelectorAll('[data-unicli-ref]')) {
|
|
197
|
+
const value = parseInt(node.getAttribute('data-unicli-ref') || '0', 10);
|
|
198
|
+
if (!Number.isNaN(value) && value > maxRef) maxRef = value;
|
|
199
|
+
}
|
|
200
|
+
return matches.map((el, index) => {
|
|
201
|
+
let ref = el.getAttribute('data-unicli-ref');
|
|
202
|
+
if (!ref) {
|
|
203
|
+
ref = String(++maxRef);
|
|
204
|
+
el.setAttribute('data-unicli-ref', ref);
|
|
205
|
+
}
|
|
206
|
+
const style = window.getComputedStyle(el);
|
|
207
|
+
const rect = el.getBoundingClientRect();
|
|
208
|
+
const visible =
|
|
209
|
+
style.display !== 'none' &&
|
|
210
|
+
style.visibility !== 'hidden' &&
|
|
211
|
+
rect.width > 0 &&
|
|
212
|
+
rect.height > 0;
|
|
213
|
+
const attrs = {};
|
|
214
|
+
for (const name of ['id', 'name', 'type', 'href', 'src', 'placeholder', 'role', 'aria-label', 'data-testid']) {
|
|
215
|
+
const value = el.getAttribute(name);
|
|
216
|
+
if (value) attrs[name] = value;
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
nth: index,
|
|
220
|
+
ref,
|
|
221
|
+
tag: el.tagName.toLowerCase(),
|
|
222
|
+
role: el.getAttribute('role') || el.tagName.toLowerCase(),
|
|
223
|
+
text: (el.innerText || el.textContent || '').trim().slice(0, ${String(textMax)}),
|
|
224
|
+
visible,
|
|
225
|
+
attrs,
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
})()`;
|
|
229
|
+
}
|
|
230
|
+
export function buildExtractJs(selector) {
|
|
231
|
+
const selectorJson = selector && selector.trim() ? JSON.stringify(selector.trim()) : "null";
|
|
232
|
+
return `(() => {
|
|
233
|
+
const picks = [];
|
|
234
|
+
const explicit = ${selectorJson};
|
|
235
|
+
if (explicit) picks.push(explicit);
|
|
236
|
+
picks.push('main', 'article', '[role="main"]', 'body');
|
|
237
|
+
let target = null;
|
|
238
|
+
let resolved = 'body';
|
|
239
|
+
for (const pick of picks) {
|
|
240
|
+
const node = document.querySelector(pick);
|
|
241
|
+
if (node) {
|
|
242
|
+
target = node;
|
|
243
|
+
resolved = pick;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const text = (target?.innerText || document.body?.innerText || '').replace(/\\u00a0/g, ' ').trim();
|
|
248
|
+
return {
|
|
249
|
+
selector: resolved,
|
|
250
|
+
title: document.title || '',
|
|
251
|
+
url: location.href,
|
|
252
|
+
content: text,
|
|
253
|
+
};
|
|
254
|
+
})()`;
|
|
255
|
+
}
|
|
256
|
+
function isSameOrDescendantPath(parent, candidate) {
|
|
257
|
+
const rel = relative(parent, candidate);
|
|
258
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
259
|
+
}
|
|
260
|
+
export function resolveAllowedUploadPath(filePath) {
|
|
261
|
+
const absolutePath = resolve(filePath);
|
|
262
|
+
if (isSensitivePathRealpath(absolutePath)) {
|
|
263
|
+
const denial = buildSensitivePathDenial(absolutePath);
|
|
264
|
+
const err = new Error("upload blocked by sensitive-path guard");
|
|
265
|
+
err.code = "permission_denied";
|
|
266
|
+
err.suggestion = denial.hint;
|
|
267
|
+
throw err;
|
|
268
|
+
}
|
|
269
|
+
const cwd = process.cwd();
|
|
270
|
+
const home = homedir();
|
|
271
|
+
if (!isSameOrDescendantPath(cwd, absolutePath) &&
|
|
272
|
+
!isSameOrDescendantPath(home, absolutePath)) {
|
|
273
|
+
const err = new Error(`upload blocked: path ${absolutePath} is outside workspace and home directory`);
|
|
274
|
+
err.code = "permission_denied";
|
|
275
|
+
err.suggestion =
|
|
276
|
+
"Copy the file under the current working directory or $HOME before uploading.";
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
return absolutePath;
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=browser-operator-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-operator-runtime.js","sourceRoot":"","sources":["../../src/commands/browser-operator-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { withBrowserOperatorEnv } from "./browser-operator-runtime.js";
|
|
3
|
+
export { withBrowserOperatorEnv };
|
|
4
|
+
export declare function applyBrowserOperatorRootOptions(command: Command): void;
|
|
5
|
+
export declare function registerBrowserOperatorSubcommands(root: Command, program: Command, namespace: "browser" | "operate"): void;
|
|
6
|
+
//# sourceMappingURL=browser-operator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-operator.d.ts","sourceRoot":"","sources":["../../src/commands/browser-operator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,OAAO,EAUL,sBAAsB,EACvB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoBtE;AAED,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,GAAG,SAAS,GAC/B,IAAI,CAodN"}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname as pathDirname, join } from "node:path";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { FINGERPRINT_PERSIST_JS, verifyRef, } from "../browser/snapshot-identity.js";
|
|
6
|
+
import { rankCandidates } from "../browser/observe.js";
|
|
7
|
+
import { buildExtractJs, buildFindJs, ensureNetworkCapture, getOperatorPage, operatorAction, readFrames, resolveAllowedUploadPath, resolveWorkspace, validateRef, withBrowserOperatorEnv, } from "./browser-operator-runtime.js";
|
|
8
|
+
import { sendCommand } from "../browser/daemon-client.js";
|
|
9
|
+
import { registerBrowserAuthoringSubcommands } from "./browser-authoring-operator.js";
|
|
10
|
+
export { withBrowserOperatorEnv };
|
|
11
|
+
export function applyBrowserOperatorRootOptions(command) {
|
|
12
|
+
command
|
|
13
|
+
.option("--workspace <name>", "Reuse a named automation workspace instead of the default shared session")
|
|
14
|
+
.option("--isolated", "Use a unique per-command workspace to avoid cross-command interference")
|
|
15
|
+
.option("--shared-session", "Force the default shared browser workspace")
|
|
16
|
+
.option("--daemon-port <port>", "Route through a specific daemon port for multi-profile setups")
|
|
17
|
+
.option("--focus", "Allow the automation window to take focus")
|
|
18
|
+
.option("--background", "Prefer background operation and avoid focus-stealing where possible");
|
|
19
|
+
}
|
|
20
|
+
export function registerBrowserOperatorSubcommands(root, program, namespace) {
|
|
21
|
+
root
|
|
22
|
+
.command("open <url>")
|
|
23
|
+
.description("Navigate to URL in daemon browser")
|
|
24
|
+
.action((url) => operatorAction(program, root, namespace, "open", async () => {
|
|
25
|
+
const page = await getOperatorPage(root, namespace);
|
|
26
|
+
await ensureNetworkCapture(page);
|
|
27
|
+
await page.goto(url, { settleMs: 2000 });
|
|
28
|
+
const title = await page.title();
|
|
29
|
+
return {
|
|
30
|
+
ok: true,
|
|
31
|
+
url,
|
|
32
|
+
title,
|
|
33
|
+
workspace: resolveWorkspace(root, namespace),
|
|
34
|
+
};
|
|
35
|
+
}));
|
|
36
|
+
root
|
|
37
|
+
.command("back")
|
|
38
|
+
.description("Navigate back in history")
|
|
39
|
+
.action(() => operatorAction(program, root, namespace, "back", async () => {
|
|
40
|
+
const page = await getOperatorPage(root, namespace);
|
|
41
|
+
await page.evaluate("history.back()");
|
|
42
|
+
await page.wait(2);
|
|
43
|
+
return { ok: true, url: await page.url() };
|
|
44
|
+
}));
|
|
45
|
+
root
|
|
46
|
+
.command("state")
|
|
47
|
+
.description("Get DOM accessibility tree snapshot")
|
|
48
|
+
.option("--interactive", "only show interactive elements")
|
|
49
|
+
.option("--compact", "omit decorative nodes")
|
|
50
|
+
.action((opts) => operatorAction(program, root, namespace, "state", async () => {
|
|
51
|
+
const page = await getOperatorPage(root, namespace);
|
|
52
|
+
const url = await page.url();
|
|
53
|
+
const snapshot = await page.snapshot({
|
|
54
|
+
interactive: opts.interactive,
|
|
55
|
+
compact: opts.compact,
|
|
56
|
+
});
|
|
57
|
+
console.error(chalk.dim(`URL: ${url}`));
|
|
58
|
+
return { url, snapshot };
|
|
59
|
+
}));
|
|
60
|
+
root
|
|
61
|
+
.command("screenshot [path]")
|
|
62
|
+
.description("Capture page screenshot")
|
|
63
|
+
.option("--full-page", "capture full scrollable page")
|
|
64
|
+
.action((path, opts) => operatorAction(program, root, namespace, "screenshot", async () => {
|
|
65
|
+
const page = await getOperatorPage(root, namespace);
|
|
66
|
+
const buf = await page.screenshot({
|
|
67
|
+
fullPage: opts.fullPage,
|
|
68
|
+
path: path ?? undefined,
|
|
69
|
+
});
|
|
70
|
+
if (path) {
|
|
71
|
+
return { ok: true, path, size: buf.length };
|
|
72
|
+
}
|
|
73
|
+
return buf.toString("base64");
|
|
74
|
+
}));
|
|
75
|
+
root
|
|
76
|
+
.command("click <ref>")
|
|
77
|
+
.description("Click element by ref number from state")
|
|
78
|
+
.action((ref) => operatorAction(program, root, namespace, "click", async () => {
|
|
79
|
+
validateRef(ref);
|
|
80
|
+
const page = await getOperatorPage(root, namespace);
|
|
81
|
+
const selector = `[data-unicli-ref="${ref}"]`;
|
|
82
|
+
await verifyRef(page, selector);
|
|
83
|
+
await page.click(selector);
|
|
84
|
+
return { ok: true, clicked: ref };
|
|
85
|
+
}));
|
|
86
|
+
root
|
|
87
|
+
.command("type <ref> <text>")
|
|
88
|
+
.description("Type text into element by ref number")
|
|
89
|
+
.action((ref, text) => operatorAction(program, root, namespace, "type", async () => {
|
|
90
|
+
validateRef(ref);
|
|
91
|
+
const page = await getOperatorPage(root, namespace);
|
|
92
|
+
const selector = `[data-unicli-ref="${ref}"]`;
|
|
93
|
+
await verifyRef(page, selector);
|
|
94
|
+
await page.click(selector);
|
|
95
|
+
await page.wait(0.3);
|
|
96
|
+
await page.insertText(text);
|
|
97
|
+
return { ok: true, ref, text };
|
|
98
|
+
}));
|
|
99
|
+
root
|
|
100
|
+
.command("keys <key>")
|
|
101
|
+
.description("Press keyboard key (e.g., Enter, Escape, Control+a)")
|
|
102
|
+
.action((key) => operatorAction(program, root, namespace, "keys", async () => {
|
|
103
|
+
const page = await getOperatorPage(root, namespace);
|
|
104
|
+
if (key.includes("+")) {
|
|
105
|
+
const parts = key.split("+");
|
|
106
|
+
const actualKey = parts.pop();
|
|
107
|
+
await page.press(actualKey, parts.map((modifier) => modifier.toLowerCase()));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
await page.press(key);
|
|
111
|
+
}
|
|
112
|
+
return { ok: true, key };
|
|
113
|
+
}));
|
|
114
|
+
root
|
|
115
|
+
.command("scroll [direction]")
|
|
116
|
+
.description("Scroll page (down, up, bottom, top)")
|
|
117
|
+
.option("--auto", "auto-scroll to bottom")
|
|
118
|
+
.option("--max <n>", "max scroll iterations for auto", "10")
|
|
119
|
+
.action((direction, opts) => operatorAction(program, root, namespace, "scroll", async () => {
|
|
120
|
+
const page = await getOperatorPage(root, namespace);
|
|
121
|
+
if (opts.auto) {
|
|
122
|
+
await page.autoScroll({
|
|
123
|
+
maxScrolls: parseInt(opts.max, 10),
|
|
124
|
+
delay: 1000,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
await page.scroll((direction ?? "down"));
|
|
129
|
+
}
|
|
130
|
+
return { ok: true, direction: direction ?? "down" };
|
|
131
|
+
}));
|
|
132
|
+
const get = root
|
|
133
|
+
.command("get")
|
|
134
|
+
.description("Get page data (title, url, text, value, html, attributes)");
|
|
135
|
+
get
|
|
136
|
+
.command("title")
|
|
137
|
+
.description("Get page title")
|
|
138
|
+
.action(() => operatorAction(program, root, namespace, "get title", async () => {
|
|
139
|
+
const page = await getOperatorPage(root, namespace);
|
|
140
|
+
return await page.title();
|
|
141
|
+
}));
|
|
142
|
+
get
|
|
143
|
+
.command("url")
|
|
144
|
+
.description("Get current URL")
|
|
145
|
+
.action(() => operatorAction(program, root, namespace, "get url", async () => {
|
|
146
|
+
const page = await getOperatorPage(root, namespace);
|
|
147
|
+
return await page.url();
|
|
148
|
+
}));
|
|
149
|
+
get
|
|
150
|
+
.command("text <ref>")
|
|
151
|
+
.description("Get text content of element by ref")
|
|
152
|
+
.action((ref) => operatorAction(program, root, namespace, "get text", async () => {
|
|
153
|
+
validateRef(ref);
|
|
154
|
+
const page = await getOperatorPage(root, namespace);
|
|
155
|
+
return await page.evaluate(`document.querySelector('[data-unicli-ref="${ref}"]')?.textContent?.trim() ?? null`);
|
|
156
|
+
}));
|
|
157
|
+
get
|
|
158
|
+
.command("value <ref>")
|
|
159
|
+
.description("Get value of input element by ref")
|
|
160
|
+
.action((ref) => operatorAction(program, root, namespace, "get value", async () => {
|
|
161
|
+
validateRef(ref);
|
|
162
|
+
const page = await getOperatorPage(root, namespace);
|
|
163
|
+
return await page.evaluate(`document.querySelector('[data-unicli-ref="${ref}"]')?.value ?? null`);
|
|
164
|
+
}));
|
|
165
|
+
get
|
|
166
|
+
.command("html [selector]")
|
|
167
|
+
.description("Get outerHTML of element (or full page)")
|
|
168
|
+
.action((selector) => operatorAction(program, root, namespace, "get html", async () => {
|
|
169
|
+
const page = await getOperatorPage(root, namespace);
|
|
170
|
+
if (selector) {
|
|
171
|
+
const selectorStr = JSON.stringify(selector);
|
|
172
|
+
return await page.evaluate(`document.querySelector(${selectorStr})?.outerHTML?.slice(0, 50000) ?? null`);
|
|
173
|
+
}
|
|
174
|
+
return await page.evaluate("document.documentElement.outerHTML.slice(0, 50000)");
|
|
175
|
+
}));
|
|
176
|
+
get
|
|
177
|
+
.command("attributes <ref>")
|
|
178
|
+
.description("Get all attributes of element by ref")
|
|
179
|
+
.action((ref) => operatorAction(program, root, namespace, "get attributes", async () => {
|
|
180
|
+
validateRef(ref);
|
|
181
|
+
const page = await getOperatorPage(root, namespace);
|
|
182
|
+
return await page.evaluate(`(() => { const el = document.querySelector('[data-unicli-ref="${ref}"]'); if (!el) return null; const attrs = {}; for (const a of el.attributes) attrs[a.name] = a.value; return attrs; })()`);
|
|
183
|
+
}));
|
|
184
|
+
root
|
|
185
|
+
.command("wait <type> [value]")
|
|
186
|
+
.description("Wait for condition (time <ms>, selector <sel>, text <str>)")
|
|
187
|
+
.option("--timeout <ms>", "timeout in ms", "10000")
|
|
188
|
+
.action((type, value, opts) => operatorAction(program, root, namespace, "wait", async () => {
|
|
189
|
+
const page = await getOperatorPage(root, namespace);
|
|
190
|
+
const timeout = parseInt(opts.timeout, 10);
|
|
191
|
+
switch (type) {
|
|
192
|
+
case "time":
|
|
193
|
+
await page.wait(parseInt(value ?? "1000", 10) / 1000);
|
|
194
|
+
break;
|
|
195
|
+
case "selector":
|
|
196
|
+
if (!value)
|
|
197
|
+
throw new Error("selector value required");
|
|
198
|
+
await page.waitForSelector(value, timeout);
|
|
199
|
+
break;
|
|
200
|
+
case "text": {
|
|
201
|
+
if (!value)
|
|
202
|
+
throw new Error("text value required");
|
|
203
|
+
const deadline = Date.now() + timeout;
|
|
204
|
+
const valueStr = JSON.stringify(value);
|
|
205
|
+
while (Date.now() < deadline) {
|
|
206
|
+
const found = await page.evaluate(`document.body.innerText.includes(${valueStr})`);
|
|
207
|
+
if (found)
|
|
208
|
+
return { ok: true, found: true };
|
|
209
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
210
|
+
}
|
|
211
|
+
throw new Error(`Text "${value}" not found within ${String(timeout)}ms`);
|
|
212
|
+
}
|
|
213
|
+
default:
|
|
214
|
+
throw new Error(`Unknown wait type: ${type}. Use: time, selector, text`);
|
|
215
|
+
}
|
|
216
|
+
return { ok: true };
|
|
217
|
+
}));
|
|
218
|
+
root
|
|
219
|
+
.command("eval <js>")
|
|
220
|
+
.description("Execute JavaScript in page context")
|
|
221
|
+
.action((js) => operatorAction(program, root, namespace, "eval", async () => {
|
|
222
|
+
const page = await getOperatorPage(root, namespace);
|
|
223
|
+
return await page.evaluate(js);
|
|
224
|
+
}));
|
|
225
|
+
registerBrowserAuthoringSubcommands(root, program, namespace);
|
|
226
|
+
root
|
|
227
|
+
.command("select <ref> <option>")
|
|
228
|
+
.description("Select option in dropdown by ref")
|
|
229
|
+
.action((ref, option) => operatorAction(program, root, namespace, "select", async () => {
|
|
230
|
+
validateRef(ref);
|
|
231
|
+
const page = await getOperatorPage(root, namespace);
|
|
232
|
+
const optionStr = JSON.stringify(option);
|
|
233
|
+
await page.evaluate(`(() => {
|
|
234
|
+
const el = document.querySelector('[data-unicli-ref="${ref}"]');
|
|
235
|
+
if (!el || el.tagName !== 'SELECT') throw new Error('Not a <select> element');
|
|
236
|
+
el.value = ${optionStr};
|
|
237
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
238
|
+
})()`);
|
|
239
|
+
return { ok: true, ref, option };
|
|
240
|
+
}));
|
|
241
|
+
root
|
|
242
|
+
.command("upload <ref> <path>")
|
|
243
|
+
.description("Upload file to file input element by ref number")
|
|
244
|
+
.action((ref, filePath) => operatorAction(program, root, namespace, "upload", async () => {
|
|
245
|
+
validateRef(ref);
|
|
246
|
+
const selector = `[data-unicli-ref="${ref}"]`;
|
|
247
|
+
const absolutePath = resolveAllowedUploadPath(filePath);
|
|
248
|
+
const page = await getOperatorPage(root, namespace);
|
|
249
|
+
await page.setFileInput(selector, [absolutePath]);
|
|
250
|
+
return { ok: true, ref, path: absolutePath };
|
|
251
|
+
}));
|
|
252
|
+
root
|
|
253
|
+
.command("hover <ref>")
|
|
254
|
+
.description("Hover over element by ref number")
|
|
255
|
+
.action((ref) => operatorAction(program, root, namespace, "hover", async () => {
|
|
256
|
+
validateRef(ref);
|
|
257
|
+
const selector = `[data-unicli-ref="${ref}"]`;
|
|
258
|
+
const selectorJson = JSON.stringify(selector);
|
|
259
|
+
const page = await getOperatorPage(root, namespace);
|
|
260
|
+
await page.evaluate(`(() => {
|
|
261
|
+
const el = document.querySelector(${selectorJson});
|
|
262
|
+
if (!el) throw new Error('Element not found: ' + ${selectorJson});
|
|
263
|
+
el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
|
|
264
|
+
el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
|
|
265
|
+
})()`);
|
|
266
|
+
return { ok: true, ref };
|
|
267
|
+
}));
|
|
268
|
+
root
|
|
269
|
+
.command("observe <query>")
|
|
270
|
+
.description("Preview ranked candidate actions for a natural-language goal")
|
|
271
|
+
.option("--top-k <n>", "Number of candidates to return", "5")
|
|
272
|
+
.option("--cache <path>", "Cache file (default ~/.unicli/observe-cache.jsonl)")
|
|
273
|
+
.action((query, opts) => operatorAction(program, root, namespace, "observe", async () => {
|
|
274
|
+
const page = await getOperatorPage(root, namespace);
|
|
275
|
+
const rawSnapshot = await page.snapshot({
|
|
276
|
+
interactive: true,
|
|
277
|
+
raw: true,
|
|
278
|
+
});
|
|
279
|
+
let parsed = { refs: [] };
|
|
280
|
+
if (typeof rawSnapshot === "string") {
|
|
281
|
+
try {
|
|
282
|
+
parsed = JSON.parse(rawSnapshot);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
// Ignore malformed raw snapshot payloads.
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
parsed = rawSnapshot;
|
|
290
|
+
}
|
|
291
|
+
const refs = Array.isArray(parsed.refs) ? parsed.refs : [];
|
|
292
|
+
const topK = parseInt(opts.topK ?? "5", 10) || 5;
|
|
293
|
+
const candidates = rankCandidates(refs, query, topK);
|
|
294
|
+
const cachePath = opts.cache ?? join(homedir(), ".unicli", "observe-cache.jsonl");
|
|
295
|
+
try {
|
|
296
|
+
mkdirSync(pathDirname(cachePath), { recursive: true });
|
|
297
|
+
appendFileSync(cachePath, JSON.stringify({
|
|
298
|
+
ts: new Date().toISOString(),
|
|
299
|
+
url: await page.url(),
|
|
300
|
+
query,
|
|
301
|
+
candidates,
|
|
302
|
+
}) + "\n", "utf-8");
|
|
303
|
+
}
|
|
304
|
+
catch {
|
|
305
|
+
// Cache failures are non-fatal.
|
|
306
|
+
}
|
|
307
|
+
return { query, candidates };
|
|
308
|
+
}));
|
|
309
|
+
root
|
|
310
|
+
.command("find")
|
|
311
|
+
.description("Find elements by CSS selector and allocate refs on demand")
|
|
312
|
+
.requiredOption("--css <selector>", "CSS selector to query")
|
|
313
|
+
.option("--limit <n>", "Maximum matches to return", "20")
|
|
314
|
+
.option("--text-max <n>", "Maximum text length per row", "120")
|
|
315
|
+
.action((opts) => operatorAction(program, root, namespace, "find", async () => {
|
|
316
|
+
const page = await getOperatorPage(root, namespace);
|
|
317
|
+
const results = (await page.evaluate(buildFindJs(opts.css, parseInt(opts.limit, 10) || 20, parseInt(opts.textMax, 10) || 120)));
|
|
318
|
+
try {
|
|
319
|
+
await page.evaluate(FINGERPRINT_PERSIST_JS);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// Best-effort only.
|
|
323
|
+
}
|
|
324
|
+
return results;
|
|
325
|
+
}));
|
|
326
|
+
root
|
|
327
|
+
.command("frames")
|
|
328
|
+
.description("List iframe frame tree entries for the current page")
|
|
329
|
+
.action(() => operatorAction(program, root, namespace, "frames", async () => {
|
|
330
|
+
const page = await getOperatorPage(root, namespace);
|
|
331
|
+
return await readFrames(page);
|
|
332
|
+
}));
|
|
333
|
+
root
|
|
334
|
+
.command("extract")
|
|
335
|
+
.description("Extract long-form page text with chunked pagination")
|
|
336
|
+
.option("--selector <css>", "Optional content root selector")
|
|
337
|
+
.option("--chunk-size <n>", "Maximum chars to return", "8000")
|
|
338
|
+
.option("--start <n>", "Start offset", "0")
|
|
339
|
+
.action((opts) => operatorAction(program, root, namespace, "extract", async () => {
|
|
340
|
+
const page = await getOperatorPage(root, namespace);
|
|
341
|
+
const result = (await page.evaluate(buildExtractJs(opts.selector)));
|
|
342
|
+
const start = Math.max(0, parseInt(opts.start, 10) || 0);
|
|
343
|
+
const chunkSize = Math.max(256, parseInt(opts.chunkSize, 10) || 8000);
|
|
344
|
+
const end = Math.min(result.content.length, start + chunkSize);
|
|
345
|
+
return {
|
|
346
|
+
url: result.url,
|
|
347
|
+
title: result.title,
|
|
348
|
+
selector: result.selector,
|
|
349
|
+
total_chars: result.content.length,
|
|
350
|
+
chunk_size: chunkSize,
|
|
351
|
+
start,
|
|
352
|
+
end,
|
|
353
|
+
next_start_char: end < result.content.length ? end : null,
|
|
354
|
+
content: result.content.slice(start, end),
|
|
355
|
+
};
|
|
356
|
+
}));
|
|
357
|
+
root
|
|
358
|
+
.command("tabs")
|
|
359
|
+
.description("List tabs for the current browser workspace")
|
|
360
|
+
.action(() => operatorAction(program, root, namespace, "tabs", async () => {
|
|
361
|
+
const workspace = resolveWorkspace(root, namespace);
|
|
362
|
+
const result = await sendCommand("tabs", { workspace });
|
|
363
|
+
return Array.isArray(result) ? result : [];
|
|
364
|
+
}));
|
|
365
|
+
root
|
|
366
|
+
.command("close")
|
|
367
|
+
.description("Close the automation browser window")
|
|
368
|
+
.action(() => operatorAction(program, root, namespace, "close", async () => {
|
|
369
|
+
const page = await getOperatorPage(root, namespace);
|
|
370
|
+
await page.closeWindow();
|
|
371
|
+
return { ok: true, workspace: resolveWorkspace(root, namespace) };
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=browser-operator.js.map
|