qt-commander-mcp 0.9.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.
- qt_commander_mcp-0.9.0/.editorconfig +18 -0
- qt_commander_mcp-0.9.0/.gitattributes +18 -0
- qt_commander_mcp-0.9.0/.github/ISSUE_TEMPLATE/bug_report.yml +57 -0
- qt_commander_mcp-0.9.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- qt_commander_mcp-0.9.0/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
- qt_commander_mcp-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +21 -0
- qt_commander_mcp-0.9.0/.github/workflows/ci.yml +243 -0
- qt_commander_mcp-0.9.0/.github/workflows/release.yml +168 -0
- qt_commander_mcp-0.9.0/.gitignore +29 -0
- qt_commander_mcp-0.9.0/CHANGELOG.md +128 -0
- qt_commander_mcp-0.9.0/CMakeLists.txt +14 -0
- qt_commander_mcp-0.9.0/CODE_STANDARDS.md +238 -0
- qt_commander_mcp-0.9.0/CONTRIBUTING.md +104 -0
- qt_commander_mcp-0.9.0/LICENSE +21 -0
- qt_commander_mcp-0.9.0/PKG-INFO +452 -0
- qt_commander_mcp-0.9.0/README.md +419 -0
- qt_commander_mcp-0.9.0/README_zh.md +363 -0
- qt_commander_mcp-0.9.0/ROADMAP.md +76 -0
- qt_commander_mcp-0.9.0/SECURITY.md +79 -0
- qt_commander_mcp-0.9.0/docs/agent-eval.md +102 -0
- qt_commander_mcp-0.9.0/docs/benchmarks/large-7000.json +84 -0
- qt_commander_mcp-0.9.0/docs/benchmarks/matrix.json +61 -0
- qt_commander_mcp-0.9.0/docs/community/anti-996.md +61 -0
- qt_commander_mcp-0.9.0/docs/design.md +768 -0
- qt_commander_mcp-0.9.0/docs/release/LICENSE-NOTES.md +107 -0
- qt_commander_mcp-0.9.0/docs/release/RELEASE-CHECKLIST.md +129 -0
- qt_commander_mcp-0.9.0/docs/versioning.md +106 -0
- qt_commander_mcp-0.9.0/pyproject.toml +81 -0
- qt_commander_mcp-0.9.0/qt_commander/__init__.py +12 -0
- qt_commander_mcp-0.9.0/qt_commander/artifacts.py +500 -0
- qt_commander_mcp-0.9.0/qt_commander/cli.py +630 -0
- qt_commander_mcp-0.9.0/qt_commander/client.py +475 -0
- qt_commander_mcp-0.9.0/qt_commander/environment.py +191 -0
- qt_commander_mcp-0.9.0/qt_commander/errors.py +95 -0
- qt_commander_mcp-0.9.0/qt_commander/inject.py +135 -0
- qt_commander_mcp-0.9.0/qt_commander/launch.py +194 -0
- qt_commander_mcp-0.9.0/qt_commander/ops.py +777 -0
- qt_commander_mcp-0.9.0/qt_commander/protocol.py +181 -0
- qt_commander_mcp-0.9.0/qt_commander/server.py +2303 -0
- qt_commander_mcp-0.9.0/qt_commander/session.py +136 -0
- qt_commander_mcp-0.9.0/qt_commander/target.py +928 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/PKG-INFO +452 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/SOURCES.txt +108 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/dependency_links.txt +1 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/entry_points.txt +3 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/requires.txt +2 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/scm_file_list.json +104 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/scm_version.json +8 -0
- qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/top_level.txt +1 -0
- qt_commander_mcp-0.9.0/scripts/injection_smoke.py +41 -0
- qt_commander_mcp-0.9.0/scripts/launch_e2e.py +115 -0
- qt_commander_mcp-0.9.0/scripts/linked_smoke.py +113 -0
- qt_commander_mcp-0.9.0/scripts/mcp_linked_smoke.py +382 -0
- qt_commander_mcp-0.9.0/scripts/p0_large.py +161 -0
- qt_commander_mcp-0.9.0/scripts/p0_matrix.py +118 -0
- qt_commander_mcp-0.9.0/scripts/package_artifacts.py +153 -0
- qt_commander_mcp-0.9.0/scripts/qml_window_test.py +241 -0
- qt_commander_mcp-0.9.0/scripts/source_smoke.py +35 -0
- qt_commander_mcp-0.9.0/scripts/task_regression.py +257 -0
- qt_commander_mcp-0.9.0/scripts/window_regression.py +334 -0
- qt_commander_mcp-0.9.0/setup.cfg +4 -0
- qt_commander_mcp-0.9.0/src/CMakeLists.txt +170 -0
- qt_commander_mcp-0.9.0/src/include/qt_commander/agent.h +28 -0
- qt_commander_mcp-0.9.0/src/include/qt_commander/version.h +13 -0
- qt_commander_mcp-0.9.0/src/injector/CMakeLists.txt +28 -0
- qt_commander_mcp-0.9.0/src/injector/elf_loader.cpp +554 -0
- qt_commander_mcp-0.9.0/src/injector/elf_loader.h +24 -0
- qt_commander_mcp-0.9.0/src/injector/elf_parser.cpp +302 -0
- qt_commander_mcp-0.9.0/src/injector/elf_parser.h +47 -0
- qt_commander_mcp-0.9.0/src/injector/injector.h +57 -0
- qt_commander_mcp-0.9.0/src/injector/injector_linux.cpp +703 -0
- qt_commander_mcp-0.9.0/src/injector/injector_win_native.cpp +68 -0
- qt_commander_mcp-0.9.0/src/injector/main_native.cpp +66 -0
- qt_commander_mcp-0.9.0/src/injector/os_ops.h +210 -0
- qt_commander_mcp-0.9.0/src/injector/ptrace_ops.cpp +854 -0
- qt_commander_mcp-0.9.0/src/injector/ptrace_ops.h +70 -0
- qt_commander_mcp-0.9.0/src/library/agent.cpp +278 -0
- qt_commander_mcp-0.9.0/src/library/inject_main.cpp +108 -0
- qt_commander_mcp-0.9.0/src/library/inject_main_unix.cpp +75 -0
- qt_commander_mcp-0.9.0/src/library/protocol.cpp +90 -0
- qt_commander_mcp-0.9.0/src/library/protocol.h +34 -0
- qt_commander_mcp-0.9.0/src/library/server.cpp +6791 -0
- qt_commander_mcp-0.9.0/src/library/server.h +207 -0
- qt_commander_mcp-0.9.0/tests/test-apps/injected/CMakeLists.txt +12 -0
- qt_commander_mcp-0.9.0/tests/test-apps/injected/main.cpp +40 -0
- qt_commander_mcp-0.9.0/tests/test-apps/large/CMakeLists.txt +18 -0
- qt_commander_mcp-0.9.0/tests/test-apps/large/main.cpp +174 -0
- qt_commander_mcp-0.9.0/tests/test-apps/linked/CMakeLists.txt +20 -0
- qt_commander_mcp-0.9.0/tests/test-apps/linked/main.cpp +160 -0
- qt_commander_mcp-0.9.0/tests/test-apps/matrix/CMakeLists.txt +27 -0
- qt_commander_mcp-0.9.0/tests/test-apps/matrix/main.cpp +298 -0
- qt_commander_mcp-0.9.0/tests/test-apps/matrix/main.qml +44 -0
- qt_commander_mcp-0.9.0/tests/test-apps/modal/CMakeLists.txt +19 -0
- qt_commander_mcp-0.9.0/tests/test-apps/modal/main.cpp +109 -0
- qt_commander_mcp-0.9.0/tests/test-apps/qmlwindow/CMakeLists.txt +24 -0
- qt_commander_mcp-0.9.0/tests/test-apps/qmlwindow/main.cpp +29 -0
- qt_commander_mcp-0.9.0/tests/test-apps/qmlwindow/main.qml +123 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_artifacts.py +328 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_cli.py +269 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_client.py +459 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_environment.py +57 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_launch.py +162 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_packaging.py +110 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_prompts.py +129 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_protocol.py +145 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_server.py +502 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_session.py +547 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_target.py +320 -0
- qt_commander_mcp-0.9.0/tests/unit_server/test_version.py +62 -0
- qt_commander_mcp-0.9.0/uv.lock +2071 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.{yml,yaml,json,md,toml}]
|
|
12
|
+
indent_size = 2
|
|
13
|
+
|
|
14
|
+
[*.{bat,cmd}]
|
|
15
|
+
end_of_line = crlf
|
|
16
|
+
|
|
17
|
+
[*.{h,cpp}]
|
|
18
|
+
indent_size = 4
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Normalize on checkout so Windows and Linux contributors produce identical
|
|
2
|
+
# diffs; the repository stores LF.
|
|
3
|
+
* text=auto eol=lf
|
|
4
|
+
|
|
5
|
+
*.bat text eol=crlf
|
|
6
|
+
*.cmd text eol=crlf
|
|
7
|
+
*.ps1 text eol=crlf
|
|
8
|
+
|
|
9
|
+
*.dll binary
|
|
10
|
+
*.exe binary
|
|
11
|
+
*.so binary
|
|
12
|
+
*.dylib binary
|
|
13
|
+
*.png binary
|
|
14
|
+
*.jpg binary
|
|
15
|
+
*.jpeg binary
|
|
16
|
+
*.gif binary
|
|
17
|
+
*.zip binary
|
|
18
|
+
*.ico binary
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Attach failed, a tool returned something wrong, or the build broke
|
|
3
|
+
title: "[bug] "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Before filing, run `qt-commander doctor --json` and paste the output
|
|
10
|
+
below. Most "cannot attach" reports are answered by it already.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: what-happened
|
|
13
|
+
attributes:
|
|
14
|
+
label: What happened
|
|
15
|
+
description: What you ran, and the full error/tool output (JSON preferred).
|
|
16
|
+
placeholder: |
|
|
17
|
+
qt_attach(pid=1234, mode="injection") returned
|
|
18
|
+
{"error": {"code": "E_INJECTION_FAILED", "reason": "...", ...}}
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: expected
|
|
23
|
+
attributes:
|
|
24
|
+
label: What you expected
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: dropdown
|
|
28
|
+
id: mode
|
|
29
|
+
attributes:
|
|
30
|
+
label: Attach mode
|
|
31
|
+
options:
|
|
32
|
+
- injection (closed-source target)
|
|
33
|
+
- linked (qt_commander::start() in the app)
|
|
34
|
+
- not attached yet (build/install problem)
|
|
35
|
+
validations:
|
|
36
|
+
required: true
|
|
37
|
+
- type: textarea
|
|
38
|
+
id: doctor
|
|
39
|
+
attributes:
|
|
40
|
+
label: "`qt-commander doctor --json`"
|
|
41
|
+
description: Paste the whole JSON. Redact paths if you must.
|
|
42
|
+
render: json
|
|
43
|
+
validations:
|
|
44
|
+
required: true
|
|
45
|
+
- type: input
|
|
46
|
+
id: versions
|
|
47
|
+
attributes:
|
|
48
|
+
label: Versions
|
|
49
|
+
description: qt-commander, Qt version, target architecture, OS, MCP client
|
|
50
|
+
placeholder: "qt-commander 2.1.0, Qt 5.15.2, x64, Windows 11, Claude Code"
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
- type: textarea
|
|
54
|
+
id: extra
|
|
55
|
+
attributes:
|
|
56
|
+
label: Anything else
|
|
57
|
+
description: Logs, screenshots, whether an injector was already loaded, recent rebuilds.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Usage questions and ideas
|
|
4
|
+
url: https://github.com/tiefeiyu/qt-commander/discussions
|
|
5
|
+
about: Ask how to automate a specific Qt app, share recipes, or discuss the roadmap.
|
|
6
|
+
- name: Security issue
|
|
7
|
+
url: https://github.com/tiefeiyu/qt-commander/security/policy
|
|
8
|
+
about: Please report vulnerabilities privately, not as a public issue.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: A tool, argument or behaviour you need for your Qt application
|
|
3
|
+
title: "[feature] "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Describe the task an agent was trying to do, not the API you have in
|
|
10
|
+
mind — the driver is what an agent needs to accomplish.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: task
|
|
13
|
+
attributes:
|
|
14
|
+
label: The task
|
|
15
|
+
description: What should an agent be able to do that it cannot do today?
|
|
16
|
+
placeholder: |
|
|
17
|
+
"Open the Settings dialog, switch the theme, and confirm it survived a restart."
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: blocked
|
|
22
|
+
attributes:
|
|
23
|
+
label: What blocks it today
|
|
24
|
+
description: Which tool, error or missing information gets in the way?
|
|
25
|
+
- type: dropdown
|
|
26
|
+
id: area
|
|
27
|
+
attributes:
|
|
28
|
+
label: Area
|
|
29
|
+
options:
|
|
30
|
+
- attach / inject / artifacts
|
|
31
|
+
- query / items / get / set
|
|
32
|
+
- act / call / batch / wait / expect
|
|
33
|
+
- screenshot / annotate
|
|
34
|
+
- source mapping
|
|
35
|
+
- MCP surface (tools, resources, prompts)
|
|
36
|
+
- docs / packaging
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: context
|
|
41
|
+
attributes:
|
|
42
|
+
label: Target application
|
|
43
|
+
description: Framework (QWidget / QML / mixed), Qt version, closed or open source, platform.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. Link the issue if there is one. -->
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
<!-- The behaviour or bug that motivated it. "Because it is cleaner" is fine if true. -->
|
|
8
|
+
|
|
9
|
+
## Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] `uv run pytest -q` passes locally
|
|
12
|
+
- [ ] New behaviour has a test (unit test, or an E2E script entry if it needs a real target)
|
|
13
|
+
- [ ] Tool descriptions / `INSTRUCTIONS` updated if the agent-facing contract changed
|
|
14
|
+
- [ ] `CHANGELOG.md` has an entry under `## [Unreleased]` for user-visible changes
|
|
15
|
+
- [ ] Docs updated (README / docs/design.md / ROADMAP.md) where behaviour is described
|
|
16
|
+
- [ ] No binaries or build output committed (`artifacts/`, `build/`, `dist/`)
|
|
17
|
+
- [ ] If a tool response grew, it is still budgeted (limits, `compact`, truncation signals)
|
|
18
|
+
|
|
19
|
+
## Notes for the reviewer
|
|
20
|
+
|
|
21
|
+
<!-- Anything subtle: Windows/Linux differences, C++ changes, compatibility of artifact/manifest fields. -->
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
python:
|
|
15
|
+
name: python ${{ matrix.python }} / ${{ matrix.os }}
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, windows-latest]
|
|
21
|
+
python: ["3.10", "3.13"]
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0 # git describe needs the tags for the version
|
|
26
|
+
- uses: astral-sh/setup-uv@v5
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
- name: Install
|
|
30
|
+
run: uv sync --python ${{ matrix.python }}
|
|
31
|
+
- name: Tests
|
|
32
|
+
run: uv run pytest -q
|
|
33
|
+
- name: CLI smoke
|
|
34
|
+
run: |
|
|
35
|
+
uv run qt-commander --version
|
|
36
|
+
uv run qt-commander doctor --json
|
|
37
|
+
|
|
38
|
+
package:
|
|
39
|
+
name: wheel
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
with:
|
|
44
|
+
fetch-depth: 0 # git describe needs the tags for the version
|
|
45
|
+
- uses: astral-sh/setup-uv@v5
|
|
46
|
+
with:
|
|
47
|
+
enable-cache: true
|
|
48
|
+
- name: Build
|
|
49
|
+
run: uv build
|
|
50
|
+
- name: Install the wheel into a clean environment
|
|
51
|
+
run: |
|
|
52
|
+
uv venv .venv-check
|
|
53
|
+
uv pip install --python .venv-check/bin/python dist/*.whl
|
|
54
|
+
.venv-check/bin/qt-commander --version
|
|
55
|
+
.venv-check/bin/qt-commander doctor --json
|
|
56
|
+
- uses: actions/upload-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: python-packages
|
|
59
|
+
path: dist/*
|
|
60
|
+
if-no-files-found: error
|
|
61
|
+
|
|
62
|
+
# Builds the injector/runtime for the platforms we can install Qt for on CI
|
|
63
|
+
# runners. First run will need tuning: pin the kits, and check that
|
|
64
|
+
# `scripts/package_artifacts.py` names the archive exactly as
|
|
65
|
+
# `qt-commander install-artifacts` expects.
|
|
66
|
+
cpp:
|
|
67
|
+
name: cpp / qt ${{ matrix.qt }} / ${{ matrix.os }}
|
|
68
|
+
runs-on: ${{ matrix.os }}
|
|
69
|
+
strategy:
|
|
70
|
+
fail-fast: false
|
|
71
|
+
matrix:
|
|
72
|
+
include:
|
|
73
|
+
# Linux Qt 5.15.2 is deliberately absent: aqtinstall cannot resolve
|
|
74
|
+
# the 5.15.2 packages for linux ("packages ['qt_base'] were not
|
|
75
|
+
# found"). A Qt 5 linux runtime can be built locally with
|
|
76
|
+
# scripts/package_artifacts.py.
|
|
77
|
+
- os: ubuntu-latest
|
|
78
|
+
qt: "6.8.3"
|
|
79
|
+
qt_major: "6"
|
|
80
|
+
arch: linux_gcc_64
|
|
81
|
+
toolchain: gcc
|
|
82
|
+
- os: windows-latest
|
|
83
|
+
qt: "5.15.2"
|
|
84
|
+
qt_major: "5"
|
|
85
|
+
arch: win64_msvc2019_64
|
|
86
|
+
toolchain: msvc
|
|
87
|
+
- os: windows-latest
|
|
88
|
+
qt: "6.8.3"
|
|
89
|
+
qt_major: "6"
|
|
90
|
+
arch: win64_msvc2022_64
|
|
91
|
+
toolchain: msvc
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/checkout@v4
|
|
94
|
+
with:
|
|
95
|
+
fetch-depth: 0 # git describe needs the tags for the version
|
|
96
|
+
- name: MSVC environment
|
|
97
|
+
if: runner.os == 'Windows'
|
|
98
|
+
uses: ilammy/msvc-dev-cmd@v1
|
|
99
|
+
- uses: jurplel/install-qt-action@v4
|
|
100
|
+
with:
|
|
101
|
+
version: ${{ matrix.qt }}
|
|
102
|
+
host: ${{ runner.os == 'Windows' && 'windows' || 'linux' }}
|
|
103
|
+
target: desktop
|
|
104
|
+
arch: ${{ matrix.arch }}
|
|
105
|
+
cache: true
|
|
106
|
+
- name: Build dependencies
|
|
107
|
+
if: runner.os == 'Linux'
|
|
108
|
+
run: |
|
|
109
|
+
sudo apt-get update
|
|
110
|
+
sudo apt-get install -y ninja-build libgl1-mesa-dev libxkbcommon-x11-0
|
|
111
|
+
- name: Configure
|
|
112
|
+
run: >
|
|
113
|
+
cmake -S . -B build/ci -G Ninja
|
|
114
|
+
-DCMAKE_BUILD_TYPE=Release
|
|
115
|
+
-DQT_MAJOR_VERSION=${{ matrix.qt_major }}
|
|
116
|
+
- name: Build
|
|
117
|
+
run: cmake --build build/ci
|
|
118
|
+
- name: Package artifact layout
|
|
119
|
+
run: >
|
|
120
|
+
python scripts/package_artifacts.py
|
|
121
|
+
--build-dir build/ci
|
|
122
|
+
--qt-version ${{ matrix.qt }}
|
|
123
|
+
--toolchain ${{ matrix.toolchain }}
|
|
124
|
+
--build-type Release
|
|
125
|
+
--qt-release
|
|
126
|
+
--archive-dir dist/artifacts
|
|
127
|
+
--github-output
|
|
128
|
+
- uses: actions/upload-artifact@v4
|
|
129
|
+
with:
|
|
130
|
+
name: artifacts-${{ matrix.os }}-qt${{ matrix.qt }}
|
|
131
|
+
path: dist/artifacts/*.zip
|
|
132
|
+
if-no-files-found: error
|
|
133
|
+
# Launch-time injection (LD_PRELOAD) is a Linux-only path here: Windows
|
|
134
|
+
# has no preload hook and does not register the qt_launch tool.
|
|
135
|
+
- uses: astral-sh/setup-uv@v5
|
|
136
|
+
if: runner.os == 'Linux'
|
|
137
|
+
with:
|
|
138
|
+
enable-cache: true
|
|
139
|
+
- name: Build the injection test app
|
|
140
|
+
if: runner.os == 'Linux'
|
|
141
|
+
run: |
|
|
142
|
+
cmake -S tests/test-apps/injected -B build/injected \
|
|
143
|
+
-DQT_MAJOR_VERSION=${{ matrix.qt_major }}
|
|
144
|
+
cmake --build build/injected
|
|
145
|
+
- name: Launch-time injection e2e
|
|
146
|
+
if: runner.os == 'Linux'
|
|
147
|
+
env:
|
|
148
|
+
QT_QPA_PLATFORM: offscreen
|
|
149
|
+
run: |
|
|
150
|
+
uv sync --quiet
|
|
151
|
+
export QT_COMMANDER_RENDEZVOUS="$RUNNER_TEMP/rendezvous-launch"
|
|
152
|
+
mkdir -p "$QT_COMMANDER_RENDEZVOUS"
|
|
153
|
+
library=$(ls artifacts/*/*/*/lib/libqt_commander_inject.so | head -1)
|
|
154
|
+
echo "library: $library"
|
|
155
|
+
uv run python scripts/launch_e2e.py \
|
|
156
|
+
--program build/injected/qt-injected-test \
|
|
157
|
+
--library "$library"
|
|
158
|
+
|
|
159
|
+
# macOS has no injector (linked mode only — see docs/design.md §8), so there
|
|
160
|
+
# is no artifact to package here. This job builds the static runtime plus the
|
|
161
|
+
# linked test app and drives it through the real session path, which is the
|
|
162
|
+
# only macOS code path the project claims to support.
|
|
163
|
+
macos-linked:
|
|
164
|
+
name: macos / linked e2e
|
|
165
|
+
runs-on: macos-latest
|
|
166
|
+
steps:
|
|
167
|
+
- uses: actions/checkout@v4
|
|
168
|
+
with:
|
|
169
|
+
fetch-depth: 0 # git describe needs the tags for the version
|
|
170
|
+
- uses: jurplel/install-qt-action@v4
|
|
171
|
+
with:
|
|
172
|
+
version: "6.8.3"
|
|
173
|
+
host: mac
|
|
174
|
+
target: desktop
|
|
175
|
+
arch: clang_64
|
|
176
|
+
cache: true
|
|
177
|
+
- uses: astral-sh/setup-uv@v5
|
|
178
|
+
with:
|
|
179
|
+
enable-cache: true
|
|
180
|
+
- name: Install
|
|
181
|
+
run: uv sync --python 3.13
|
|
182
|
+
- name: Work around Qt 6.8.3 linking a framework macOS removed
|
|
183
|
+
run: |
|
|
184
|
+
# Qt 6.8.3's FindWrapOpenGL.cmake emits "-framework AGL" even when AGL
|
|
185
|
+
# is absent, and the macOS 26 SDK no longer ships AGL. Upstream fixed
|
|
186
|
+
# this in 6.8.4 / 6.9, so this step becomes a no-op once the kit moves.
|
|
187
|
+
python3 - "$QT_ROOT_DIR/lib/cmake/Qt6/FindWrapOpenGL.cmake" <<'PY'
|
|
188
|
+
import pathlib
|
|
189
|
+
import sys
|
|
190
|
+
|
|
191
|
+
path = pathlib.Path(sys.argv[1])
|
|
192
|
+
text = path.read_text()
|
|
193
|
+
needle = (
|
|
194
|
+
" target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE "
|
|
195
|
+
"${__opengl_agl_fw_path})\n"
|
|
196
|
+
)
|
|
197
|
+
if needle in text:
|
|
198
|
+
path.write_text(text.replace(needle, ""))
|
|
199
|
+
print("patched AGL link out of", path)
|
|
200
|
+
else:
|
|
201
|
+
print("no AGL link line in", path, "- nothing to do")
|
|
202
|
+
PY
|
|
203
|
+
- name: Build runtime, injection library and linked test app
|
|
204
|
+
run: |
|
|
205
|
+
cmake -S tests/test-apps/linked -B build/linked \
|
|
206
|
+
-DCMAKE_BUILD_TYPE=Release -DQT_MAJOR_VERSION=6
|
|
207
|
+
cmake --build build/linked
|
|
208
|
+
ls -l build/linked/qt-commander/*.dylib
|
|
209
|
+
- name: Drive the linked app
|
|
210
|
+
env:
|
|
211
|
+
QT_QPA_PLATFORM: offscreen
|
|
212
|
+
run: |
|
|
213
|
+
set -euo pipefail
|
|
214
|
+
export QT_COMMANDER_RENDEZVOUS="$RUNNER_TEMP/rendezvous"
|
|
215
|
+
mkdir -p "$QT_COMMANDER_RENDEZVOUS"
|
|
216
|
+
./build/linked/qt-linked-test &
|
|
217
|
+
APP_PID=$!
|
|
218
|
+
trap 'kill "$APP_PID" 2>/dev/null || true' EXIT
|
|
219
|
+
descriptor=""
|
|
220
|
+
for _ in $(seq 1 100); do
|
|
221
|
+
descriptor=$(ls "$QT_COMMANDER_RENDEZVOUS"/descriptor-*.json 2>/dev/null | head -1 || true)
|
|
222
|
+
[ -n "$descriptor" ] && break
|
|
223
|
+
sleep 0.2
|
|
224
|
+
done
|
|
225
|
+
if [ -z "$descriptor" ]; then
|
|
226
|
+
echo "no descriptor appeared; is the app running?" >&2
|
|
227
|
+
exit 1
|
|
228
|
+
fi
|
|
229
|
+
uv run python scripts/linked_smoke.py --descriptor "$descriptor"
|
|
230
|
+
- name: Build the injection test app
|
|
231
|
+
run: |
|
|
232
|
+
cmake -S tests/test-apps/injected -B build/injected \
|
|
233
|
+
-DCMAKE_BUILD_TYPE=Release -DQT_MAJOR_VERSION=6
|
|
234
|
+
cmake --build build/injected
|
|
235
|
+
- name: Launch-time injection e2e (DYLD_INSERT_LIBRARIES)
|
|
236
|
+
env:
|
|
237
|
+
QT_QPA_PLATFORM: offscreen
|
|
238
|
+
run: |
|
|
239
|
+
export QT_COMMANDER_RENDEZVOUS="$RUNNER_TEMP/rendezvous-launch"
|
|
240
|
+
mkdir -p "$QT_COMMANDER_RENDEZVOUS"
|
|
241
|
+
uv run python scripts/launch_e2e.py \
|
|
242
|
+
--program build/injected/qt-injected-test \
|
|
243
|
+
--library build/linked/qt-commander/libqt_commander_inject.dylib
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build-python:
|
|
13
|
+
name: python packages
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0 # git describe needs the tags for the version
|
|
19
|
+
- uses: astral-sh/setup-uv@v5
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
- run: uv build
|
|
23
|
+
- name: Verify the wheel installs and runs
|
|
24
|
+
run: |
|
|
25
|
+
uv venv .venv-check
|
|
26
|
+
uv pip install --python .venv-check/bin/python dist/*.whl
|
|
27
|
+
.venv-check/bin/qt-commander --version
|
|
28
|
+
.venv-check/bin/qt-commander doctor --json
|
|
29
|
+
- uses: actions/upload-artifact@v4
|
|
30
|
+
with:
|
|
31
|
+
name: python-packages
|
|
32
|
+
path: dist/*
|
|
33
|
+
if-no-files-found: error
|
|
34
|
+
|
|
35
|
+
artifacts:
|
|
36
|
+
name: artifact / qt ${{ matrix.qt }} / ${{ matrix.os }}
|
|
37
|
+
runs-on: ${{ matrix.os }}
|
|
38
|
+
strategy:
|
|
39
|
+
fail-fast: false
|
|
40
|
+
matrix:
|
|
41
|
+
include:
|
|
42
|
+
# Linux Qt 5.15.2 is deliberately absent: aqtinstall cannot resolve
|
|
43
|
+
# the 5.15.2 packages for linux ("packages ['qt_base'] were not
|
|
44
|
+
# found"). Build a Qt 5 linux runtime locally with
|
|
45
|
+
# scripts/package_artifacts.py.
|
|
46
|
+
- os: ubuntu-latest
|
|
47
|
+
qt: "6.8.3"
|
|
48
|
+
qt_major: "6"
|
|
49
|
+
arch: linux_gcc_64
|
|
50
|
+
toolchain: gcc
|
|
51
|
+
- os: windows-latest
|
|
52
|
+
qt: "5.15.2"
|
|
53
|
+
qt_major: "5"
|
|
54
|
+
arch: win64_msvc2019_64
|
|
55
|
+
toolchain: msvc
|
|
56
|
+
- os: windows-latest
|
|
57
|
+
qt: "6.8.3"
|
|
58
|
+
qt_major: "6"
|
|
59
|
+
arch: win64_msvc2022_64
|
|
60
|
+
toolchain: msvc
|
|
61
|
+
steps:
|
|
62
|
+
- uses: actions/checkout@v4
|
|
63
|
+
with:
|
|
64
|
+
fetch-depth: 0 # git describe needs the tags for the version
|
|
65
|
+
- name: MSVC environment
|
|
66
|
+
if: runner.os == 'Windows'
|
|
67
|
+
uses: ilammy/msvc-dev-cmd@v1
|
|
68
|
+
- uses: jurplel/install-qt-action@v4
|
|
69
|
+
with:
|
|
70
|
+
version: ${{ matrix.qt }}
|
|
71
|
+
host: ${{ runner.os == 'Windows' && 'windows' || 'linux' }}
|
|
72
|
+
target: desktop
|
|
73
|
+
arch: ${{ matrix.arch }}
|
|
74
|
+
cache: true
|
|
75
|
+
- name: Build dependencies
|
|
76
|
+
if: runner.os == 'Linux'
|
|
77
|
+
run: |
|
|
78
|
+
sudo apt-get update
|
|
79
|
+
sudo apt-get install -y ninja-build libgl1-mesa-dev libxkbcommon-x11-0
|
|
80
|
+
- name: Configure
|
|
81
|
+
run: >
|
|
82
|
+
cmake -S . -B build/rel -G Ninja
|
|
83
|
+
-DCMAKE_BUILD_TYPE=Release
|
|
84
|
+
-DQT_MAJOR_VERSION=${{ matrix.qt_major }}
|
|
85
|
+
- name: Build
|
|
86
|
+
run: cmake --build build/rel
|
|
87
|
+
- name: Package artifact archive
|
|
88
|
+
id: package
|
|
89
|
+
run: >
|
|
90
|
+
python scripts/package_artifacts.py
|
|
91
|
+
--build-dir build/rel
|
|
92
|
+
--qt-version ${{ matrix.qt }}
|
|
93
|
+
--toolchain ${{ matrix.toolchain }}
|
|
94
|
+
--build-type Release
|
|
95
|
+
--qt-release
|
|
96
|
+
--archive-dir dist/assets
|
|
97
|
+
--github-output
|
|
98
|
+
- uses: actions/upload-artifact@v4
|
|
99
|
+
with:
|
|
100
|
+
name: artifact-${{ matrix.os }}-qt${{ matrix.qt }}
|
|
101
|
+
path: dist/assets/*.zip
|
|
102
|
+
if-no-files-found: error
|
|
103
|
+
|
|
104
|
+
checksums:
|
|
105
|
+
name: SHA256SUMS
|
|
106
|
+
needs: artifacts
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
steps:
|
|
109
|
+
- uses: actions/download-artifact@v4
|
|
110
|
+
with:
|
|
111
|
+
pattern: artifact-*
|
|
112
|
+
path: assets
|
|
113
|
+
merge-multiple: true
|
|
114
|
+
- name: Generate sums
|
|
115
|
+
working-directory: assets
|
|
116
|
+
run: |
|
|
117
|
+
python -c "import hashlib,pathlib; [print(hashlib.sha256(p.read_bytes()).hexdigest() + ' ' + p.name) for p in sorted(pathlib.Path('.').glob('*.zip'))]" > SHA256SUMS
|
|
118
|
+
cat SHA256SUMS
|
|
119
|
+
- uses: actions/upload-artifact@v4
|
|
120
|
+
with:
|
|
121
|
+
name: artifact-sums
|
|
122
|
+
path: assets/SHA256SUMS
|
|
123
|
+
if-no-files-found: error
|
|
124
|
+
|
|
125
|
+
github-release:
|
|
126
|
+
name: GitHub release
|
|
127
|
+
needs: [build-python, artifacts, checksums]
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
permissions:
|
|
130
|
+
contents: write
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/download-artifact@v4
|
|
133
|
+
with:
|
|
134
|
+
pattern: "*"
|
|
135
|
+
path: assets
|
|
136
|
+
merge-multiple: true
|
|
137
|
+
- name: Publish
|
|
138
|
+
env:
|
|
139
|
+
GH_TOKEN: ${{ github.token }}
|
|
140
|
+
run: |
|
|
141
|
+
tag="${GITHUB_REF_NAME}"
|
|
142
|
+
if [ -z "$tag" ] || [ "$tag" = "master" ]; then
|
|
143
|
+
echo "workflow_dispatch without a tag ref; nothing to publish"
|
|
144
|
+
exit 0
|
|
145
|
+
fi
|
|
146
|
+
gh release view "$tag" >/dev/null 2>&1 || \
|
|
147
|
+
gh release create "$tag" --generate-notes --title "qt-commander $tag"
|
|
148
|
+
gh release upload "$tag" assets/* --clobber
|
|
149
|
+
|
|
150
|
+
# Trusted Publishing; no API token is stored in the repository. Set the
|
|
151
|
+
# repository variable PYPI_PUBLISH=true once the publisher is configured on
|
|
152
|
+
# PyPI, otherwise this job is a no-op (see docs/release/RELEASE-CHECKLIST.md).
|
|
153
|
+
pypi:
|
|
154
|
+
name: PyPI
|
|
155
|
+
needs: build-python
|
|
156
|
+
if: vars.PYPI_PUBLISH == 'true'
|
|
157
|
+
runs-on: ubuntu-latest
|
|
158
|
+
environment:
|
|
159
|
+
name: pypi
|
|
160
|
+
url: https://pypi.org/p/qt-commander-mcp
|
|
161
|
+
permissions:
|
|
162
|
+
id-token: write
|
|
163
|
+
steps:
|
|
164
|
+
- uses: actions/download-artifact@v4
|
|
165
|
+
with:
|
|
166
|
+
name: python-packages
|
|
167
|
+
path: dist
|
|
168
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
artifacts/
|
|
7
|
+
.venv/
|
|
8
|
+
.test-venv/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
.test-workspace/
|
|
11
|
+
.codegraph/
|
|
12
|
+
.portal/
|
|
13
|
+
# Local triage notes and feedback: useful while working, not part of the
|
|
14
|
+
# published documentation (that lives in docs/).
|
|
15
|
+
dev-docs/
|
|
16
|
+
*.o
|
|
17
|
+
*.obj
|
|
18
|
+
*.exe
|
|
19
|
+
*.dll
|
|
20
|
+
*.so
|
|
21
|
+
*.dylib
|
|
22
|
+
.superpowers/
|
|
23
|
+
*.gcov
|
|
24
|
+
*.gcda
|
|
25
|
+
*.gcno
|
|
26
|
+
.coverage
|
|
27
|
+
*.tmp
|
|
28
|
+
.vscode/
|
|
29
|
+
portal.db
|