forge-cpp-mcp 0.2.3__tar.gz → 0.2.4__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.
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/PKG-INFO +32 -5
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/README.md +31 -4
- forge_cpp_mcp-0.2.4/frontend/cmake-run-test.html +12 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/package.json +1 -1
- forge_cpp_mcp-0.2.4/frontend/src/cmake-run-test.js +8 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/vite.config.js +1 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/hatch_build.py +1 -1
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/pyproject.toml +1 -1
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/__init__.py +1 -1
- forge_cpp_mcp-0.2.4/src/forgemcp/cmake/errors.py +5 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/cmake/models.py +13 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/cmake/service.py +95 -2
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/cmake/text.py +19 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/process/service.py +2 -1
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/server.py +1 -0
- forge_cpp_mcp-0.2.3/src/forgemcp/cmake/errors.py +0 -5
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/.gitignore +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/LICENSE +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/clangd-result.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/cmake-build.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/cmake-configure.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/cmake-profiles.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/cmake-test.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/package-lock.json +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/process-details.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/process-overview.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/clangd-navigation-view.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/clangd-result.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/clangd-view.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/cmake-build.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/cmake-configure.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/cmake-profiles.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/cmake-test.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/cmake-view.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/process-details.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/process-overview.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/process-status.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/process.css +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/shared/app.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/shared/copy-icon.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/shared/presentation.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/shared/result-resources.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/shared/result-view.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/shared/widget.css +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/source-view.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/toolsets.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/workspace-file.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/workspace-result.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/workspace-search.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/workspace-tree.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/src/workspace-view.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/tests/result-resources.test.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/tests/result-view.test.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/tests/workspace.test.js +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/toolsets.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/workspace-file.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/workspace-result.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/workspace-search.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/frontend/workspace-tree.html +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/assets.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/clangd/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/clangd/errors.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/clangd/models.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/clangd/service.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/clangd/session.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/clangd/text.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/cmake/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/cmake/profiles.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/completion.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/clangd.LICENSE +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/clangd.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/cmake.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/process.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/toolchain.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/workspace-edit.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/workspace-file.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/workspace-search.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/icons/workspace.svg +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/markdown.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/process/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/process/errors.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/process/models.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/process/text.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/process/transcript.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/progress.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/text.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/discovery.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/errors.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/loader.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/providers/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/providers/system.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/providers/user.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/providers/visual_studio.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/service.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/spec.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/clang.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/clang_cl.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/clangd.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/clangxx.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/cmake.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/cppvsdbg.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/ctest.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/gcc.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/gdb.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/git.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/gxx.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/link.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/lld.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/lld_link.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/lldb_dap.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/make.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/msbuild.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/msvc.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/tools/ninja.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/__init__.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/diff.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/errors.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/metadata.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/models.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/path.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/providers.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/service.py +0 -0
- {forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/workspace/text.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: forge-cpp-mcp
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: A safe MCP server for structured C++ project development workflows.
|
|
5
5
|
Project-URL: Homepage, https://github.com/hardened-steel/ForgeMCP
|
|
6
6
|
Project-URL: Repository, https://github.com/hardened-steel/ForgeMCP
|
|
@@ -44,7 +44,8 @@ debugger modules are planned.
|
|
|
44
44
|
configuration selections use all available contexts.
|
|
45
45
|
- No prompts are currently registered.
|
|
46
46
|
- CMake tools list operator profiles, configure projects, build targets, and run
|
|
47
|
-
CTest.
|
|
47
|
+
CTest. `cmake_run_test` directly runs a project/storage test executable with
|
|
48
|
+
literal command-line arguments. Each tool has its own widget with Fields/JSON views,
|
|
48
49
|
copying and per-test results. Command logs are available through `process_get`. CMake syntax highlighting remains deferred.
|
|
49
50
|
- Tool `processes_overview` shows running and completed external development tools,
|
|
50
51
|
including exit codes and timeout interruptions. `process_get(process_id)` returns
|
|
@@ -75,7 +76,9 @@ without making additional tool calls. Process times are readable to seconds; JSO
|
|
|
75
76
|
copying preserve the original precision. A toolsets list shows summaries, while a
|
|
76
77
|
`toolset_get` result shows the details returned by that call.
|
|
77
78
|
|
|
78
|
-
ForgeMCP
|
|
79
|
+
ForgeMCP can directly run an explicitly selected test executable inside the
|
|
80
|
+
project or storage root; it does not expose shell commands or external executable
|
|
81
|
+
paths over MCP. Feature services use
|
|
79
82
|
the shared process service internally; its public MCP surface is read-only.
|
|
80
83
|
|
|
81
84
|
## Requirements
|
|
@@ -93,7 +96,7 @@ and install it in a virtual environment:
|
|
|
93
96
|
|
|
94
97
|
```powershell
|
|
95
98
|
python -m venv .venv
|
|
96
|
-
.\.venv\Scripts\python.exe -m pip install .\forge_cpp_mcp-0.2.
|
|
99
|
+
.\.venv\Scripts\python.exe -m pip install .\forge_cpp_mcp-0.2.4-py3-none-any.whl
|
|
97
100
|
.\.venv\Scripts\forgemcp.exe --help
|
|
98
101
|
```
|
|
99
102
|
|
|
@@ -105,7 +108,7 @@ The distribution name is `forge-cpp-mcp`; the Python module and server command a
|
|
|
105
108
|
After the package is published to PyPI, the install command can instead be:
|
|
106
109
|
|
|
107
110
|
```powershell
|
|
108
|
-
.\.venv\Scripts\python.exe -m pip install forge-cpp-mcp==0.2.
|
|
111
|
+
.\.venv\Scripts\python.exe -m pip install forge-cpp-mcp==0.2.4
|
|
109
112
|
```
|
|
110
113
|
|
|
111
114
|
## Setup from source
|
|
@@ -332,6 +335,30 @@ Full process transcripts remain in the process module; CMake results contain no
|
|
|
332
335
|
transcript links. The default command timeout is 600 seconds per execution and
|
|
333
336
|
can be overridden with the existing `ProcessTimeout` shape (`total`, `idle`).
|
|
334
337
|
|
|
338
|
+
`cmake_run_test(executable, arguments=null, cwd="project/", timeout={"total":600})`
|
|
339
|
+
runs one already-built test executable directly, without a profile or CTest
|
|
340
|
+
registration. Executable and working-directory paths use `project/...` or
|
|
341
|
+
`storage/...` and must resolve inside their respective roots. The working directory
|
|
342
|
+
must exist; storage is not created automatically. On Windows, batch files are not
|
|
343
|
+
supported. Arguments are a list of literal strings, preserving spaces and empty
|
|
344
|
+
strings; NUL is rejected. For example:
|
|
345
|
+
|
|
346
|
+
```json
|
|
347
|
+
{
|
|
348
|
+
"executable": "project/build/ninja-debug/fixture_tests.exe",
|
|
349
|
+
"arguments": ["--fail"],
|
|
350
|
+
"cwd": "project/build/ninja-debug",
|
|
351
|
+
"timeout": {"total": 30}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The process inherits the server environment, closes stdin, and waits for completion.
|
|
356
|
+
It does not replay toolset/preset environments or CTest properties such as
|
|
357
|
+
`WILL_FAIL`, fixtures, or per-test timeouts. Exit zero means success; a nonzero
|
|
358
|
+
exit or process failure is reported in `error`. The single structured result
|
|
359
|
+
contains `executable`, `arguments`, `cwd`, `error`, and `process_id`; logs are read
|
|
360
|
+
through `process_get`. No JUnit or framework case report is inferred from output.
|
|
361
|
+
|
|
335
362
|
With no explicit profiles:
|
|
336
363
|
|
|
337
364
|
- If `CMakePresets.json` or `CMakeUserPresets.json` exists, the automatic `presets`
|
|
@@ -19,7 +19,8 @@ debugger modules are planned.
|
|
|
19
19
|
configuration selections use all available contexts.
|
|
20
20
|
- No prompts are currently registered.
|
|
21
21
|
- CMake tools list operator profiles, configure projects, build targets, and run
|
|
22
|
-
CTest.
|
|
22
|
+
CTest. `cmake_run_test` directly runs a project/storage test executable with
|
|
23
|
+
literal command-line arguments. Each tool has its own widget with Fields/JSON views,
|
|
23
24
|
copying and per-test results. Command logs are available through `process_get`. CMake syntax highlighting remains deferred.
|
|
24
25
|
- Tool `processes_overview` shows running and completed external development tools,
|
|
25
26
|
including exit codes and timeout interruptions. `process_get(process_id)` returns
|
|
@@ -50,7 +51,9 @@ without making additional tool calls. Process times are readable to seconds; JSO
|
|
|
50
51
|
copying preserve the original precision. A toolsets list shows summaries, while a
|
|
51
52
|
`toolset_get` result shows the details returned by that call.
|
|
52
53
|
|
|
53
|
-
ForgeMCP
|
|
54
|
+
ForgeMCP can directly run an explicitly selected test executable inside the
|
|
55
|
+
project or storage root; it does not expose shell commands or external executable
|
|
56
|
+
paths over MCP. Feature services use
|
|
54
57
|
the shared process service internally; its public MCP surface is read-only.
|
|
55
58
|
|
|
56
59
|
## Requirements
|
|
@@ -68,7 +71,7 @@ and install it in a virtual environment:
|
|
|
68
71
|
|
|
69
72
|
```powershell
|
|
70
73
|
python -m venv .venv
|
|
71
|
-
.\.venv\Scripts\python.exe -m pip install .\forge_cpp_mcp-0.2.
|
|
74
|
+
.\.venv\Scripts\python.exe -m pip install .\forge_cpp_mcp-0.2.4-py3-none-any.whl
|
|
72
75
|
.\.venv\Scripts\forgemcp.exe --help
|
|
73
76
|
```
|
|
74
77
|
|
|
@@ -80,7 +83,7 @@ The distribution name is `forge-cpp-mcp`; the Python module and server command a
|
|
|
80
83
|
After the package is published to PyPI, the install command can instead be:
|
|
81
84
|
|
|
82
85
|
```powershell
|
|
83
|
-
.\.venv\Scripts\python.exe -m pip install forge-cpp-mcp==0.2.
|
|
86
|
+
.\.venv\Scripts\python.exe -m pip install forge-cpp-mcp==0.2.4
|
|
84
87
|
```
|
|
85
88
|
|
|
86
89
|
## Setup from source
|
|
@@ -307,6 +310,30 @@ Full process transcripts remain in the process module; CMake results contain no
|
|
|
307
310
|
transcript links. The default command timeout is 600 seconds per execution and
|
|
308
311
|
can be overridden with the existing `ProcessTimeout` shape (`total`, `idle`).
|
|
309
312
|
|
|
313
|
+
`cmake_run_test(executable, arguments=null, cwd="project/", timeout={"total":600})`
|
|
314
|
+
runs one already-built test executable directly, without a profile or CTest
|
|
315
|
+
registration. Executable and working-directory paths use `project/...` or
|
|
316
|
+
`storage/...` and must resolve inside their respective roots. The working directory
|
|
317
|
+
must exist; storage is not created automatically. On Windows, batch files are not
|
|
318
|
+
supported. Arguments are a list of literal strings, preserving spaces and empty
|
|
319
|
+
strings; NUL is rejected. For example:
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"executable": "project/build/ninja-debug/fixture_tests.exe",
|
|
324
|
+
"arguments": ["--fail"],
|
|
325
|
+
"cwd": "project/build/ninja-debug",
|
|
326
|
+
"timeout": {"total": 30}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
The process inherits the server environment, closes stdin, and waits for completion.
|
|
331
|
+
It does not replay toolset/preset environments or CTest properties such as
|
|
332
|
+
`WILL_FAIL`, fixtures, or per-test timeouts. Exit zero means success; a nonzero
|
|
333
|
+
exit or process failure is reported in `error`. The single structured result
|
|
334
|
+
contains `executable`, `arguments`, `cwd`, `error`, and `process_id`; logs are read
|
|
335
|
+
through `process_get`. No JUnit or framework case report is inferred from output.
|
|
336
|
+
|
|
310
337
|
With no explicit profiles:
|
|
311
338
|
|
|
312
339
|
- If `CMakePresets.json` or `CMakeUserPresets.json` exists, the automatic `presets`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Test executable result</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<main id="widget" aria-label="Test executable result"></main>
|
|
10
|
+
<script type="module" src="/src/cmake-run-test.js"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "vite build --mode workspace && vite build --mode file && vite build --mode search && vite build --mode result && vite build --mode process && vite build --mode process-details && vite build --mode toolsets && vite build --mode cmake-profiles && vite build --mode cmake-configure && vite build --mode cmake-build && vite build --mode cmake-test && vite build --mode clangd",
|
|
6
|
+
"build": "vite build --mode workspace && vite build --mode file && vite build --mode search && vite build --mode result && vite build --mode process && vite build --mode process-details && vite build --mode toolsets && vite build --mode cmake-profiles && vite build --mode cmake-configure && vite build --mode cmake-build && vite build --mode cmake-test && vite build --mode cmake-run-test && vite build --mode clangd",
|
|
7
7
|
"test": "node --test tests/*.test.js"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { connectWidget } from "./shared/app.js";
|
|
2
|
+
import { cmakePresentation, renderCMakeValue } from "./cmake-view.js";
|
|
3
|
+
|
|
4
|
+
await connectWidget({
|
|
5
|
+
toolName: "cmake_run_test",
|
|
6
|
+
describe: (data) => cmakePresentation(data, "cmake_run_test"),
|
|
7
|
+
renderValue: renderCMakeValue,
|
|
8
|
+
});
|
|
@@ -31,7 +31,7 @@ class CustomBuildHook(BuildHookInterface):
|
|
|
31
31
|
Path(self.root) / "src" / "forgemcp" / "assets" / "clangd-result.html",
|
|
32
32
|
*(
|
|
33
33
|
Path(self.root) / "src" / "forgemcp" / "assets" / f"cmake-{kind}.html"
|
|
34
|
-
for kind in ("profiles", "configure", "build", "test")
|
|
34
|
+
for kind in ("profiles", "configure", "build", "test", "run-test")
|
|
35
35
|
),
|
|
36
36
|
]
|
|
37
37
|
artifacts = build_data.setdefault("artifacts", [])
|
|
@@ -72,3 +72,16 @@ class CMakeTestResult(BaseModel):
|
|
|
72
72
|
description="Null on success; failure explanation otherwise.",
|
|
73
73
|
)
|
|
74
74
|
process_id: int | None = None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class CMakeRunTestResult(BaseModel):
|
|
78
|
+
"""One direct executable run with its command inputs, error, and process reference."""
|
|
79
|
+
|
|
80
|
+
executable: WorkspacePath
|
|
81
|
+
arguments: list[str] = Field(default_factory=list)
|
|
82
|
+
cwd: WorkspacePath
|
|
83
|
+
error: str | None = Field(
|
|
84
|
+
default=None,
|
|
85
|
+
description="Null on success; failure explanation otherwise.",
|
|
86
|
+
)
|
|
87
|
+
process_id: int | None = None
|
|
@@ -20,8 +20,9 @@ from pydantic import Field
|
|
|
20
20
|
|
|
21
21
|
from forgemcp.assets import IconFile, Widget
|
|
22
22
|
from forgemcp.completion import Complete
|
|
23
|
-
from forgemcp.process.errors import ProcessError
|
|
23
|
+
from forgemcp.process.errors import ProcessError, ProcessStartError
|
|
24
24
|
from forgemcp.process.models import ProcessTimeout
|
|
25
|
+
from forgemcp.process.service import ProcessService
|
|
25
26
|
from forgemcp.progress import progress
|
|
26
27
|
from forgemcp.text import tool_result
|
|
27
28
|
from forgemcp.toolchain.errors import ToolchainError
|
|
@@ -38,8 +39,9 @@ from .models import (
|
|
|
38
39
|
CMakeConfigureResult,
|
|
39
40
|
CMakeBuildResult,
|
|
40
41
|
CMakeTestResult,
|
|
42
|
+
CMakeRunTestResult,
|
|
41
43
|
)
|
|
42
|
-
from .text import render_executions, render_profiles
|
|
44
|
+
from .text import render_executions, render_profiles, render_run_test
|
|
43
45
|
|
|
44
46
|
|
|
45
47
|
class CMakeService:
|
|
@@ -57,6 +59,11 @@ class CMakeService:
|
|
|
57
59
|
Configure before building; build before testing. Diagnose with a subset,
|
|
58
60
|
then verify all profiles. Each execution reports error (null means success)
|
|
59
61
|
and, when launched, process_id for its command log.
|
|
62
|
+
|
|
63
|
+
cmake_run_test runs an explicit project/storage test executable with literal
|
|
64
|
+
arguments and a working directory, inheriting the server environment.
|
|
65
|
+
It requires no profile or CTest registration. Zero exit means success;
|
|
66
|
+
CTest properties, preset environments, and framework case reports do not apply.
|
|
60
67
|
"""
|
|
61
68
|
|
|
62
69
|
ICON = IconFile("icons/cmake.svg")
|
|
@@ -64,10 +71,12 @@ class CMakeService:
|
|
|
64
71
|
CONFIGURE_WIDGET = Widget("assets/cmake-configure.html")
|
|
65
72
|
BUILD_WIDGET = Widget("assets/cmake-build.html")
|
|
66
73
|
TEST_WIDGET = Widget("assets/cmake-test.html")
|
|
74
|
+
RUN_TEST_WIDGET = Widget("assets/cmake-run-test.html")
|
|
67
75
|
|
|
68
76
|
def __init__(
|
|
69
77
|
self,
|
|
70
78
|
toolchains: ToolchainService,
|
|
79
|
+
processes: ProcessService,
|
|
71
80
|
profiles: tuple[ProfileDefinition, ...] = (),
|
|
72
81
|
*,
|
|
73
82
|
project_root: Path,
|
|
@@ -81,6 +90,7 @@ class CMakeService:
|
|
|
81
90
|
self.storage_root = storage_root.resolve()
|
|
82
91
|
self.protected_paths = protected_paths
|
|
83
92
|
self.toolchains = toolchains
|
|
93
|
+
self.processes = processes
|
|
84
94
|
self.definitions = profiles
|
|
85
95
|
self.default_toolset = default_toolset
|
|
86
96
|
self.progress_interval = progress_interval
|
|
@@ -477,6 +487,23 @@ class CMakeService:
|
|
|
477
487
|
queue.put_nowait(snapshot)
|
|
478
488
|
self.configuration_subscribers[queue] = signature
|
|
479
489
|
|
|
490
|
+
def execution_path(self, reference: WorkspacePath) -> Path:
|
|
491
|
+
"""Resolve a test executable or working directory without escaping its managed root."""
|
|
492
|
+
if reference.area == "root":
|
|
493
|
+
raise CMakeError("Test execution paths must be inside project/ or storage/.")
|
|
494
|
+
base = self.project_root if reference.area == "project" else self.storage_root
|
|
495
|
+
try:
|
|
496
|
+
if os.name == "nt" and any(
|
|
497
|
+
os.path.isreserved(part) for part in Path(reference.relative).parts
|
|
498
|
+
):
|
|
499
|
+
raise CMakeError(f"Test execution path contains a reserved name: {reference}.")
|
|
500
|
+
path = (base / reference.relative).resolve()
|
|
501
|
+
if not path.is_relative_to(base):
|
|
502
|
+
raise CMakeError(f"Test execution path resolves outside its root: {reference}.")
|
|
503
|
+
return path
|
|
504
|
+
except OSError as error:
|
|
505
|
+
raise CMakeError(f"Cannot resolve test execution path: {reference}.") from error
|
|
506
|
+
|
|
480
507
|
def register(self, mcp: MCPServer, apps: Apps, complete: Complete) -> None:
|
|
481
508
|
"""Register profile inspection, configure, build, and test tools with their widgets."""
|
|
482
509
|
icon = self.ICON.icon
|
|
@@ -862,10 +889,76 @@ class CMakeService:
|
|
|
862
889
|
await report_status(result.error or "Completed successfully")
|
|
863
890
|
return tool_result(results, render_executions(results, "CTest"))
|
|
864
891
|
|
|
892
|
+
@apps.tool(
|
|
893
|
+
resource_uri=self.RUN_TEST_WIDGET.uri,
|
|
894
|
+
icons=[icon],
|
|
895
|
+
annotations=changes_files,
|
|
896
|
+
)
|
|
897
|
+
async def cmake_run_test(
|
|
898
|
+
executable: WorkspacePath,
|
|
899
|
+
ctx: Context,
|
|
900
|
+
arguments: list[str] | None = None,
|
|
901
|
+
cwd: WorkspacePath = WorkspacePath("project/"),
|
|
902
|
+
timeout: ProcessTimeout = ProcessTimeout(total=600),
|
|
903
|
+
) -> Annotated[CallToolResult, CMakeRunTestResult]:
|
|
904
|
+
"""Run one project/storage test executable directly with literal command-line arguments.
|
|
905
|
+
|
|
906
|
+
Inherits the server environment; cwd defaults to project/. Zero exit
|
|
907
|
+
means success. No profiles, CTest properties, or case reports are used.
|
|
908
|
+
Read output through process_get with the returned process_id.
|
|
909
|
+
"""
|
|
910
|
+
report = progress(ctx, interval=self.progress_interval)
|
|
911
|
+
await report(0, message="Preparing test executable")
|
|
912
|
+
values = arguments if arguments is not None else []
|
|
913
|
+
if any("\0" in value for value in values):
|
|
914
|
+
raise ToolError("Test arguments cannot contain NUL.")
|
|
915
|
+
try:
|
|
916
|
+
program = self.execution_path(executable)
|
|
917
|
+
directory = self.execution_path(cwd)
|
|
918
|
+
if not program.is_file():
|
|
919
|
+
raise CMakeError(f"Test executable is not a file: {executable}.")
|
|
920
|
+
if not directory.is_dir():
|
|
921
|
+
raise CMakeError(f"Test working directory does not exist: {cwd}.")
|
|
922
|
+
if os.name == "nt" and program.suffix.lower() in (".bat", ".cmd"):
|
|
923
|
+
raise CMakeError("Test executable must be a native program, not a batch file.")
|
|
924
|
+
except CMakeError as error:
|
|
925
|
+
raise ToolError(str(error)) from error
|
|
926
|
+
except OSError as error:
|
|
927
|
+
raise ToolError("Cannot inspect test executable or working directory.") from error
|
|
928
|
+
result = CMakeRunTestResult(
|
|
929
|
+
executable=executable,
|
|
930
|
+
arguments=values,
|
|
931
|
+
cwd=cwd,
|
|
932
|
+
)
|
|
933
|
+
updates = 1
|
|
934
|
+
await report(updates, message="Starting test executable")
|
|
935
|
+
try:
|
|
936
|
+
async with await self.processes.launch(
|
|
937
|
+
program,
|
|
938
|
+
values,
|
|
939
|
+
cwd=directory,
|
|
940
|
+
timeout=timeout,
|
|
941
|
+
) as session:
|
|
942
|
+
result.process_id = session.process_id
|
|
943
|
+
await session.close_stdin()
|
|
944
|
+
async for _ in session.output():
|
|
945
|
+
updates += 1
|
|
946
|
+
await report(updates, message="Receiving test output")
|
|
947
|
+
code = await session.wait()
|
|
948
|
+
if code != 0:
|
|
949
|
+
result.error = f"Test executable exited with {code}."
|
|
950
|
+
except ProcessStartError:
|
|
951
|
+
result.error = f"Cannot start test executable: {executable}."
|
|
952
|
+
except ProcessError as error:
|
|
953
|
+
result.error = str(error)
|
|
954
|
+
await report(updates + 1, message=result.error or "Completed successfully")
|
|
955
|
+
return tool_result(result, render_run_test(result))
|
|
956
|
+
|
|
865
957
|
for widget in (
|
|
866
958
|
self.PROFILES_WIDGET,
|
|
867
959
|
self.CONFIGURE_WIDGET,
|
|
868
960
|
self.BUILD_WIDGET,
|
|
869
961
|
self.TEST_WIDGET,
|
|
962
|
+
self.RUN_TEST_WIDGET,
|
|
870
963
|
):
|
|
871
964
|
apps.add_html_resource(widget.uri, widget.content)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Plain-text CMake settings, execution outcomes, and complete CTest cases."""
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
from typing import Literal
|
|
4
5
|
|
|
5
6
|
from forgemcp.toolchain.tools import ctest
|
|
@@ -9,6 +10,7 @@ from .models import (
|
|
|
9
10
|
CMakeConfigureResult,
|
|
10
11
|
CMakeBuildResult,
|
|
11
12
|
CMakeTestResult,
|
|
13
|
+
CMakeRunTestResult,
|
|
12
14
|
)
|
|
13
15
|
|
|
14
16
|
|
|
@@ -96,3 +98,20 @@ def render_test_cases(tests: list[ctest.TestCase]) -> list[str]:
|
|
|
96
98
|
if test.message is not None:
|
|
97
99
|
lines.append(" " + test.message.replace("\n", "\n "))
|
|
98
100
|
return lines
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def render_run_test(result: CMakeRunTestResult) -> str:
|
|
104
|
+
"""Describe a direct run and preserve argument boundaries without copying its transcript."""
|
|
105
|
+
lines = [
|
|
106
|
+
f"Test executable: {result.executable}",
|
|
107
|
+
f" Arguments: {json.dumps(result.arguments, ensure_ascii=False)}",
|
|
108
|
+
f" Working directory: {result.cwd}",
|
|
109
|
+
f" Outcome: {'Succeeded' if result.error is None else 'Failed'}",
|
|
110
|
+
]
|
|
111
|
+
if result.error is not None:
|
|
112
|
+
lines.append(" Error: " + result.error.replace("\n", "\n "))
|
|
113
|
+
if result.process_id is not None:
|
|
114
|
+
lines.append(f" Command output: process_get(process_id={result.process_id})")
|
|
115
|
+
else:
|
|
116
|
+
lines.append(" Process: not available")
|
|
117
|
+
return "\n".join(lines)
|
|
@@ -324,7 +324,8 @@ class ProcessService:
|
|
|
324
324
|
|
|
325
325
|
Feature results identify commands by process_id. Process state and ordered
|
|
326
326
|
stdin/stdout/stderr logs are retained in memory until the server stops.
|
|
327
|
-
|
|
327
|
+
This service exposes no command execution tools. cmake_run_test can launch an
|
|
328
|
+
explicit test executable inside project/storage through the CMake surface.
|
|
328
329
|
"""
|
|
329
330
|
|
|
330
331
|
WIDGET = Widget("assets/process-overview.html")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{forge_cpp_mcp-0.2.3 → forge_cpp_mcp-0.2.4}/src/forgemcp/toolchain/providers/visual_studio.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|