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.
Files changed (110) hide show
  1. qt_commander_mcp-0.9.0/.editorconfig +18 -0
  2. qt_commander_mcp-0.9.0/.gitattributes +18 -0
  3. qt_commander_mcp-0.9.0/.github/ISSUE_TEMPLATE/bug_report.yml +57 -0
  4. qt_commander_mcp-0.9.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  5. qt_commander_mcp-0.9.0/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
  6. qt_commander_mcp-0.9.0/.github/PULL_REQUEST_TEMPLATE.md +21 -0
  7. qt_commander_mcp-0.9.0/.github/workflows/ci.yml +243 -0
  8. qt_commander_mcp-0.9.0/.github/workflows/release.yml +168 -0
  9. qt_commander_mcp-0.9.0/.gitignore +29 -0
  10. qt_commander_mcp-0.9.0/CHANGELOG.md +128 -0
  11. qt_commander_mcp-0.9.0/CMakeLists.txt +14 -0
  12. qt_commander_mcp-0.9.0/CODE_STANDARDS.md +238 -0
  13. qt_commander_mcp-0.9.0/CONTRIBUTING.md +104 -0
  14. qt_commander_mcp-0.9.0/LICENSE +21 -0
  15. qt_commander_mcp-0.9.0/PKG-INFO +452 -0
  16. qt_commander_mcp-0.9.0/README.md +419 -0
  17. qt_commander_mcp-0.9.0/README_zh.md +363 -0
  18. qt_commander_mcp-0.9.0/ROADMAP.md +76 -0
  19. qt_commander_mcp-0.9.0/SECURITY.md +79 -0
  20. qt_commander_mcp-0.9.0/docs/agent-eval.md +102 -0
  21. qt_commander_mcp-0.9.0/docs/benchmarks/large-7000.json +84 -0
  22. qt_commander_mcp-0.9.0/docs/benchmarks/matrix.json +61 -0
  23. qt_commander_mcp-0.9.0/docs/community/anti-996.md +61 -0
  24. qt_commander_mcp-0.9.0/docs/design.md +768 -0
  25. qt_commander_mcp-0.9.0/docs/release/LICENSE-NOTES.md +107 -0
  26. qt_commander_mcp-0.9.0/docs/release/RELEASE-CHECKLIST.md +129 -0
  27. qt_commander_mcp-0.9.0/docs/versioning.md +106 -0
  28. qt_commander_mcp-0.9.0/pyproject.toml +81 -0
  29. qt_commander_mcp-0.9.0/qt_commander/__init__.py +12 -0
  30. qt_commander_mcp-0.9.0/qt_commander/artifacts.py +500 -0
  31. qt_commander_mcp-0.9.0/qt_commander/cli.py +630 -0
  32. qt_commander_mcp-0.9.0/qt_commander/client.py +475 -0
  33. qt_commander_mcp-0.9.0/qt_commander/environment.py +191 -0
  34. qt_commander_mcp-0.9.0/qt_commander/errors.py +95 -0
  35. qt_commander_mcp-0.9.0/qt_commander/inject.py +135 -0
  36. qt_commander_mcp-0.9.0/qt_commander/launch.py +194 -0
  37. qt_commander_mcp-0.9.0/qt_commander/ops.py +777 -0
  38. qt_commander_mcp-0.9.0/qt_commander/protocol.py +181 -0
  39. qt_commander_mcp-0.9.0/qt_commander/server.py +2303 -0
  40. qt_commander_mcp-0.9.0/qt_commander/session.py +136 -0
  41. qt_commander_mcp-0.9.0/qt_commander/target.py +928 -0
  42. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/PKG-INFO +452 -0
  43. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/SOURCES.txt +108 -0
  44. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/dependency_links.txt +1 -0
  45. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/entry_points.txt +3 -0
  46. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/requires.txt +2 -0
  47. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/scm_file_list.json +104 -0
  48. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/scm_version.json +8 -0
  49. qt_commander_mcp-0.9.0/qt_commander_mcp.egg-info/top_level.txt +1 -0
  50. qt_commander_mcp-0.9.0/scripts/injection_smoke.py +41 -0
  51. qt_commander_mcp-0.9.0/scripts/launch_e2e.py +115 -0
  52. qt_commander_mcp-0.9.0/scripts/linked_smoke.py +113 -0
  53. qt_commander_mcp-0.9.0/scripts/mcp_linked_smoke.py +382 -0
  54. qt_commander_mcp-0.9.0/scripts/p0_large.py +161 -0
  55. qt_commander_mcp-0.9.0/scripts/p0_matrix.py +118 -0
  56. qt_commander_mcp-0.9.0/scripts/package_artifacts.py +153 -0
  57. qt_commander_mcp-0.9.0/scripts/qml_window_test.py +241 -0
  58. qt_commander_mcp-0.9.0/scripts/source_smoke.py +35 -0
  59. qt_commander_mcp-0.9.0/scripts/task_regression.py +257 -0
  60. qt_commander_mcp-0.9.0/scripts/window_regression.py +334 -0
  61. qt_commander_mcp-0.9.0/setup.cfg +4 -0
  62. qt_commander_mcp-0.9.0/src/CMakeLists.txt +170 -0
  63. qt_commander_mcp-0.9.0/src/include/qt_commander/agent.h +28 -0
  64. qt_commander_mcp-0.9.0/src/include/qt_commander/version.h +13 -0
  65. qt_commander_mcp-0.9.0/src/injector/CMakeLists.txt +28 -0
  66. qt_commander_mcp-0.9.0/src/injector/elf_loader.cpp +554 -0
  67. qt_commander_mcp-0.9.0/src/injector/elf_loader.h +24 -0
  68. qt_commander_mcp-0.9.0/src/injector/elf_parser.cpp +302 -0
  69. qt_commander_mcp-0.9.0/src/injector/elf_parser.h +47 -0
  70. qt_commander_mcp-0.9.0/src/injector/injector.h +57 -0
  71. qt_commander_mcp-0.9.0/src/injector/injector_linux.cpp +703 -0
  72. qt_commander_mcp-0.9.0/src/injector/injector_win_native.cpp +68 -0
  73. qt_commander_mcp-0.9.0/src/injector/main_native.cpp +66 -0
  74. qt_commander_mcp-0.9.0/src/injector/os_ops.h +210 -0
  75. qt_commander_mcp-0.9.0/src/injector/ptrace_ops.cpp +854 -0
  76. qt_commander_mcp-0.9.0/src/injector/ptrace_ops.h +70 -0
  77. qt_commander_mcp-0.9.0/src/library/agent.cpp +278 -0
  78. qt_commander_mcp-0.9.0/src/library/inject_main.cpp +108 -0
  79. qt_commander_mcp-0.9.0/src/library/inject_main_unix.cpp +75 -0
  80. qt_commander_mcp-0.9.0/src/library/protocol.cpp +90 -0
  81. qt_commander_mcp-0.9.0/src/library/protocol.h +34 -0
  82. qt_commander_mcp-0.9.0/src/library/server.cpp +6791 -0
  83. qt_commander_mcp-0.9.0/src/library/server.h +207 -0
  84. qt_commander_mcp-0.9.0/tests/test-apps/injected/CMakeLists.txt +12 -0
  85. qt_commander_mcp-0.9.0/tests/test-apps/injected/main.cpp +40 -0
  86. qt_commander_mcp-0.9.0/tests/test-apps/large/CMakeLists.txt +18 -0
  87. qt_commander_mcp-0.9.0/tests/test-apps/large/main.cpp +174 -0
  88. qt_commander_mcp-0.9.0/tests/test-apps/linked/CMakeLists.txt +20 -0
  89. qt_commander_mcp-0.9.0/tests/test-apps/linked/main.cpp +160 -0
  90. qt_commander_mcp-0.9.0/tests/test-apps/matrix/CMakeLists.txt +27 -0
  91. qt_commander_mcp-0.9.0/tests/test-apps/matrix/main.cpp +298 -0
  92. qt_commander_mcp-0.9.0/tests/test-apps/matrix/main.qml +44 -0
  93. qt_commander_mcp-0.9.0/tests/test-apps/modal/CMakeLists.txt +19 -0
  94. qt_commander_mcp-0.9.0/tests/test-apps/modal/main.cpp +109 -0
  95. qt_commander_mcp-0.9.0/tests/test-apps/qmlwindow/CMakeLists.txt +24 -0
  96. qt_commander_mcp-0.9.0/tests/test-apps/qmlwindow/main.cpp +29 -0
  97. qt_commander_mcp-0.9.0/tests/test-apps/qmlwindow/main.qml +123 -0
  98. qt_commander_mcp-0.9.0/tests/unit_server/test_artifacts.py +328 -0
  99. qt_commander_mcp-0.9.0/tests/unit_server/test_cli.py +269 -0
  100. qt_commander_mcp-0.9.0/tests/unit_server/test_client.py +459 -0
  101. qt_commander_mcp-0.9.0/tests/unit_server/test_environment.py +57 -0
  102. qt_commander_mcp-0.9.0/tests/unit_server/test_launch.py +162 -0
  103. qt_commander_mcp-0.9.0/tests/unit_server/test_packaging.py +110 -0
  104. qt_commander_mcp-0.9.0/tests/unit_server/test_prompts.py +129 -0
  105. qt_commander_mcp-0.9.0/tests/unit_server/test_protocol.py +145 -0
  106. qt_commander_mcp-0.9.0/tests/unit_server/test_server.py +502 -0
  107. qt_commander_mcp-0.9.0/tests/unit_server/test_session.py +547 -0
  108. qt_commander_mcp-0.9.0/tests/unit_server/test_target.py +320 -0
  109. qt_commander_mcp-0.9.0/tests/unit_server/test_version.py +62 -0
  110. 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