ui-locator-cli 0.1.0__tar.gz
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.
- ui_locator_cli-0.1.0/.env.example +30 -0
- ui_locator_cli-0.1.0/.github/workflows/publish.yml +138 -0
- ui_locator_cli-0.1.0/.gitignore +48 -0
- ui_locator_cli-0.1.0/.python-version +1 -0
- ui_locator_cli-0.1.0/LICENSE +17 -0
- ui_locator_cli-0.1.0/PKG-INFO +498 -0
- ui_locator_cli-0.1.0/README.md +450 -0
- ui_locator_cli-0.1.0/bench/__init__.py +1 -0
- ui_locator_cli-0.1.0/bench/benchmark.py +196 -0
- ui_locator_cli-0.1.0/bench/compare_models.py +192 -0
- ui_locator_cli-0.1.0/bench/fixtures/benchmark.json +72 -0
- ui_locator_cli-0.1.0/bench/fixtures/login.png +0 -0
- ui_locator_cli-0.1.0/bench/fixtures/model_matrix.json +37 -0
- ui_locator_cli-0.1.0/bench/fixtures/settings.png +0 -0
- ui_locator_cli-0.1.0/bench/fixtures/toolbar.png +0 -0
- ui_locator_cli-0.1.0/bench/make_fixtures.py +122 -0
- ui_locator_cli-0.1.0/bench/model_matrix.py +82 -0
- ui_locator_cli-0.1.0/bench/scoring.py +99 -0
- ui_locator_cli-0.1.0/examples/annotate_demo.py +63 -0
- ui_locator_cli-0.1.0/examples/demo.py +104 -0
- ui_locator_cli-0.1.0/examples/locate_button.py +63 -0
- ui_locator_cli-0.1.0/examples/serve_mlx.py +94 -0
- ui_locator_cli-0.1.0/pyproject.toml +147 -0
- ui_locator_cli-0.1.0/src/ui_locator/__init__.py +54 -0
- ui_locator_cli-0.1.0/src/ui_locator/__main__.py +6 -0
- ui_locator_cli-0.1.0/src/ui_locator/api.py +329 -0
- ui_locator_cli-0.1.0/src/ui_locator/cli.py +765 -0
- ui_locator_cli-0.1.0/src/ui_locator/config.py +125 -0
- ui_locator_cli-0.1.0/src/ui_locator/coords.py +333 -0
- ui_locator_cli-0.1.0/src/ui_locator/errors.py +29 -0
- ui_locator_cli-0.1.0/src/ui_locator/image.py +59 -0
- ui_locator_cli-0.1.0/src/ui_locator/mapstore.py +313 -0
- ui_locator_cli-0.1.0/src/ui_locator/project.py +379 -0
- ui_locator_cli-0.1.0/src/ui_locator/prompting.py +113 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/__init__.py +7 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/_mlx_utils.py +91 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/base.py +31 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/cloud_cua.py +225 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/mlx_qwen.py +96 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/mlx_uitars.py +91 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/omniparser.py +26 -0
- ui_locator_cli-0.1.0/src/ui_locator/providers/openai_compat.py +184 -0
- ui_locator_cli-0.1.0/src/ui_locator/skill/SKILL.md +148 -0
- ui_locator_cli-0.1.0/src/ui_locator/skillcmd.py +222 -0
- ui_locator_cli-0.1.0/src/ui_locator/types.py +128 -0
- ui_locator_cli-0.1.0/tests/conftest.py +133 -0
- ui_locator_cli-0.1.0/tests/test_api.py +97 -0
- ui_locator_cli-0.1.0/tests/test_bench_scoring.py +87 -0
- ui_locator_cli-0.1.0/tests/test_benchmark_models.py +101 -0
- ui_locator_cli-0.1.0/tests/test_cli.py +71 -0
- ui_locator_cli-0.1.0/tests/test_cli_config.py +129 -0
- ui_locator_cli-0.1.0/tests/test_cli_map.py +197 -0
- ui_locator_cli-0.1.0/tests/test_coords.py +174 -0
- ui_locator_cli-0.1.0/tests/test_integration.py +38 -0
- ui_locator_cli-0.1.0/tests/test_map_api.py +177 -0
- ui_locator_cli-0.1.0/tests/test_mapstore.py +224 -0
- ui_locator_cli-0.1.0/tests/test_project.py +281 -0
- ui_locator_cli-0.1.0/tests/test_prompting.py +46 -0
- ui_locator_cli-0.1.0/tests/test_provider_choice.py +89 -0
- ui_locator_cli-0.1.0/tests/test_skill.py +286 -0
- ui_locator_cli-0.1.0/ui-locator-qwen.sh +28 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# ui-locator secrets.
|
|
2
|
+
#
|
|
3
|
+
# Non-secret settings (provider, endpoint, model, prompt style) belong in
|
|
4
|
+
# .ui-locator/config.toml, where they can be committed and switched with
|
|
5
|
+
# `--use <profile>`. Run `ui-locator init` to create it, then keep only keys
|
|
6
|
+
# here (this file, or .ui-locator/.env, is gitignored by that template).
|
|
7
|
+
#
|
|
8
|
+
# Check what actually resolved with: ui-locator config show
|
|
9
|
+
|
|
10
|
+
UI_LOCATOR_OPENAI_API_KEY=<your-api-key>
|
|
11
|
+
# UI_LOCATOR_ANTHROPIC_API_KEY=<your-anthropic-api-key>
|
|
12
|
+
|
|
13
|
+
# Everything below can equally live in .ui-locator/config.toml; environment
|
|
14
|
+
# variables win over it, which makes them handy for one-off overrides.
|
|
15
|
+
|
|
16
|
+
# UI_LOCATOR_USE=qwen-cloud # pick a [models.<name>] profile
|
|
17
|
+
# UI_LOCATOR_PROVIDER=openai
|
|
18
|
+
# UI_LOCATOR_OPENAI_BASE_URL=https://api.fireworks.ai/inference/v1
|
|
19
|
+
# UI_LOCATOR_OPENAI_MODEL=accounts/fireworks/models/qwen3p7-plus
|
|
20
|
+
# UI_LOCATOR_OPENAI_PROMPT=qwen # required for Qwen: parses <box>, not <point>
|
|
21
|
+
|
|
22
|
+
# Element map
|
|
23
|
+
# UI_LOCATOR_MAP_DIR=/path/to/map # default: <project>/.ui-locator/map
|
|
24
|
+
# UI_LOCATOR_SESSION=run-42 # tag learned entries
|
|
25
|
+
# UI_LOCATOR_USE_MAP=false # ignore stored positions
|
|
26
|
+
# UI_LOCATOR_VERIFY=true # re-check a crop before trusting one
|
|
27
|
+
|
|
28
|
+
# Misc
|
|
29
|
+
# UI_LOCATOR_THINK=true
|
|
30
|
+
# UI_LOCATOR_MAX_TOKENS=512
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when a GitHub release is published, so the release notes
|
|
4
|
+
# and the uploaded version are always the same event. Can also be run by hand
|
|
5
|
+
# against TestPyPI to rehearse.
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
target:
|
|
12
|
+
description: Index to upload to
|
|
13
|
+
type: choice
|
|
14
|
+
default: testpypi
|
|
15
|
+
options: [testpypi, pypi]
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
# uv.lock is not committed, so CI resolves dependencies fresh -- exactly how a
|
|
22
|
+
# user installing from PyPI does. Both ends of the supported range are tested
|
|
23
|
+
# because typer 0.27 stopped being click-based, which a single "latest" job
|
|
24
|
+
# caught only by accident.
|
|
25
|
+
test:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
strategy:
|
|
28
|
+
fail-fast: false
|
|
29
|
+
matrix:
|
|
30
|
+
typer: ["typer", "typer==0.16.0"]
|
|
31
|
+
name: test (${{ matrix.typer }})
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v7
|
|
34
|
+
|
|
35
|
+
- name: Install uv
|
|
36
|
+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
37
|
+
|
|
38
|
+
- name: Install the project
|
|
39
|
+
run: |
|
|
40
|
+
uv sync --extra dev
|
|
41
|
+
uv pip install '${{ matrix.typer }}'
|
|
42
|
+
|
|
43
|
+
- name: Lint
|
|
44
|
+
run: uv run --no-sync ruff check src tests bench
|
|
45
|
+
|
|
46
|
+
- name: Type-check
|
|
47
|
+
run: uv run --no-sync mypy
|
|
48
|
+
|
|
49
|
+
- name: Test
|
|
50
|
+
run: uv run --no-sync pytest -q
|
|
51
|
+
|
|
52
|
+
build:
|
|
53
|
+
needs: test
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/checkout@v7
|
|
57
|
+
|
|
58
|
+
- name: Install uv
|
|
59
|
+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
60
|
+
|
|
61
|
+
- name: Install the project
|
|
62
|
+
run: uv sync --extra dev
|
|
63
|
+
|
|
64
|
+
# A tag that disagrees with pyproject.toml would publish a version nobody
|
|
65
|
+
# asked for, and PyPI never lets a version be reused.
|
|
66
|
+
- name: Check the tag matches the project version
|
|
67
|
+
if: github.event_name == 'release'
|
|
68
|
+
run: |
|
|
69
|
+
version=$(uv run python -c "import tomllib,pathlib;print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
|
|
70
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
71
|
+
echo "pyproject: $version — tag: $tag"
|
|
72
|
+
if [ "$version" != "$tag" ]; then
|
|
73
|
+
echo "::error::tag '$GITHUB_REF_NAME' does not match version '$version' in pyproject.toml"
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
- name: Build sdist and wheel
|
|
78
|
+
run: uv build
|
|
79
|
+
|
|
80
|
+
# The skill is package data; if it ever falls out of the wheel,
|
|
81
|
+
# `ui-locator skill install` silently has nothing to install.
|
|
82
|
+
- name: Check the bundled skill is in the wheel
|
|
83
|
+
run: |
|
|
84
|
+
uv run python - <<'PY'
|
|
85
|
+
import glob, sys, zipfile
|
|
86
|
+
wheel = glob.glob("dist/*.whl")[0]
|
|
87
|
+
names = zipfile.ZipFile(wheel).namelist()
|
|
88
|
+
if "ui_locator/skill/SKILL.md" not in names:
|
|
89
|
+
sys.exit(f"SKILL.md missing from {wheel}")
|
|
90
|
+
print(f"ok: SKILL.md present in {wheel}")
|
|
91
|
+
PY
|
|
92
|
+
|
|
93
|
+
- uses: actions/upload-artifact@v7
|
|
94
|
+
with:
|
|
95
|
+
name: dist
|
|
96
|
+
path: dist/
|
|
97
|
+
|
|
98
|
+
publish:
|
|
99
|
+
needs: build
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
environment:
|
|
102
|
+
name: ${{ github.event_name == 'release' && 'pypi' || inputs.target }}
|
|
103
|
+
permissions:
|
|
104
|
+
id-token: write # PEP 740 attestations (and Trusted Publishing, see below)
|
|
105
|
+
env:
|
|
106
|
+
HAS_TEST_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN != '' }}
|
|
107
|
+
steps:
|
|
108
|
+
- uses: actions/download-artifact@v8
|
|
109
|
+
with:
|
|
110
|
+
name: dist
|
|
111
|
+
path: dist/
|
|
112
|
+
|
|
113
|
+
- name: Publish to TestPyPI
|
|
114
|
+
if: >-
|
|
115
|
+
github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
|
|
116
|
+
&& env.HAS_TEST_TOKEN == 'true'
|
|
117
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
118
|
+
with:
|
|
119
|
+
repository-url: https://test.pypi.org/legacy/
|
|
120
|
+
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
|
121
|
+
|
|
122
|
+
- name: Note a skipped TestPyPI upload
|
|
123
|
+
if: >-
|
|
124
|
+
github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
|
|
125
|
+
&& env.HAS_TEST_TOKEN != 'true'
|
|
126
|
+
run: |
|
|
127
|
+
echo "::notice::Built and round-tripped the artifacts; TestPyPI upload"\
|
|
128
|
+
" skipped because TEST_PYPI_API_TOKEN is not set."
|
|
129
|
+
|
|
130
|
+
- name: Publish to PyPI
|
|
131
|
+
if: github.event_name == 'release' || inputs.target == 'pypi'
|
|
132
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
133
|
+
with:
|
|
134
|
+
# Prefer Trusted Publishing: configure a publisher for this repo and
|
|
135
|
+
# workflow at https://pypi.org/manage/project/ui-locator-cli/settings/publishing/
|
|
136
|
+
# then delete the line below — GitHub mints a short-lived OIDC token
|
|
137
|
+
# per run and there is no long-lived secret to leak or rotate.
|
|
138
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
*.egg
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
.eggs/
|
|
10
|
+
|
|
11
|
+
# Virtual environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
|
|
16
|
+
# uv
|
|
17
|
+
uv.lock
|
|
18
|
+
|
|
19
|
+
# Local secrets / environment
|
|
20
|
+
.env
|
|
21
|
+
.env.*
|
|
22
|
+
!.env.example
|
|
23
|
+
|
|
24
|
+
# Local ui-locator project (config + element map) used while developing.
|
|
25
|
+
# In a real automation repo you *would* commit .ui-locator/config.toml and
|
|
26
|
+
# .ui-locator/map/ -- here it is just scratch, and .env holds a live API key.
|
|
27
|
+
.ui-locator/
|
|
28
|
+
|
|
29
|
+
# Annotated output of --annotate, and local working screenshots
|
|
30
|
+
*_test.png
|
|
31
|
+
/screen.png
|
|
32
|
+
|
|
33
|
+
# Tooling
|
|
34
|
+
.mypy_cache/
|
|
35
|
+
.ruff_cache/
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.coverage
|
|
38
|
+
htmlcov/
|
|
39
|
+
|
|
40
|
+
# Editor / OS
|
|
41
|
+
.DS_Store
|
|
42
|
+
.vscode/
|
|
43
|
+
.idea/
|
|
44
|
+
|
|
45
|
+
# Models / data (local caches)
|
|
46
|
+
weights/
|
|
47
|
+
*.pt
|
|
48
|
+
*.safetensors
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 ui-locator contributors
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|