forked from community-shaders/skyrim-community-shaders
-
Notifications
You must be signed in to change notification settings - Fork 6
feat(mcp): integrate devbench #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
882e497
feat(mcp): gated console output capture
alandtse b572219
feat(devbench): client-side bridge scaffold (inert until enabled)
alandtse 1057866
build(devbench): consume devbench-api vcpkg port; enable the bridge
alandtse 1774720
fix(devbench): make feature toggle reversible
alandtse dc9d4a1
fix(devbench): address review — arg parse errors, null-task, port docs
alandtse 83080c6
refactor(devbench): scope PR to the bridge; address review
alandtse cd4a910
build(devbench): gate the bridge behind a CMake option (default ON)
alandtse 3f49354
fix(build): leave RemoteControl.cpp untouched by this PR
alandtse e2137a3
build(devbench): surface DEVBENCH_BRIDGE in the user preset template
alandtse d7aa0a9
feat(devbench): emit openshaders.feature.changed; gate dep via vcpkg …
alandtse cb921c3
docs(devbench): document the feature-toggle threading contract
alandtse 482a95b
feat(devbench)!: migrate CS off its embedded MCP server to the bridge
alandtse 59b96d5
feat(devbench): migration code — bridge tools, gutted server, status …
alandtse 345d41f
Merge origin/dev into feat/devbench-bridge
alandtse 31c6aa2
Merge origin/dev into feat/devbench-bridge
alandtse 65735e4
feat(devbench): add openshaders.shadercache (clear/deleteDisk); revie…
alandtse 79df600
docs: describe present bridge/panel role, not removed server (review)
alandtse 95b9216
build(devbench-api): bump port to devbench c75e7d2
alandtse dfaf39e
fix(devbench): thread-safety + correctness from PR review
alandtse 1740a03
feat(abtest): manual variant switching for path-aligned A/B
alandtse f949ffb
fix(abtest): reset manualMode on Disable; guard reset task Save
alandtse 101a05f
feat(abtest): expose aggregated A/B timing via openshaders.abtest res…
alandtse 12e5a9c
fix(devbench): marshal feature list/get reads; drop status from abtes…
alandtse 68e6502
feat(abtest): auto-enable overlay profiling in manual mode
alandtse 63f8ae7
fix(devbench): marshal remaining loaded reads; A/B manual polish; rev…
alandtse b333e62
refactor(devbench): drop A/B/benchmark from the bridge PR
alandtse aa50d80
docs(remotecontrol): fix feature summary tool list (drop abtest)
alandtse 67bdf70
refactor(remotecontrol): own devbench install at DataLoaded
alandtse 6d236c4
refactor(remotecontrol): theme colors, QPC, drop brand from panel
alandtse 0360fc4
refactor(remotecontrol): drop redundant overrides + external refs
alandtse 4da6fc8
refactor: move DevBenchBridge out of /src
alandtse 283bbed
fix(devbench): validate set/reset + suppress post-timeout side effects
alandtse 1bc015b
docs(devbench): clarify shadercache clear vs deleteDisk
alandtse File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # devbench-api vcpkg port | ||
|
|
||
| Vendor the devbench cross-plugin API (`DevBenchAPI.h` + `.cpp`) into your SKSE plugin | ||
| via vcpkg — **do not copy the files into your tree** (they drift). Mirrors the | ||
| SkyrimVRESL port. | ||
|
|
||
| ## Consume (once devbench is published) | ||
|
|
||
| `vcpkg.json`: | ||
|
|
||
| ```json | ||
| { "dependencies": ["devbench-api"] } | ||
| ``` | ||
|
|
||
| `CMakeLists.txt`: | ||
|
|
||
| ```cmake | ||
| find_package(devbench-api CONFIG REQUIRED) | ||
| target_link_libraries(YourPlugin PRIVATE DevBench::API) | ||
| ``` | ||
|
|
||
| Then, after SKSE sends `kPostLoad`: | ||
|
|
||
| ```cpp | ||
| #include <DevBenchAPI.h> | ||
| if (auto* dvb = DevBenchAPI::GetDevBenchInterface001()) { | ||
| dvb->RegisterTool("yourmod.dothing", R"({"description":"...","inputSchema":{...}})", | ||
| &YourHandler, yourCtx); | ||
| } | ||
| ``` | ||
|
|
||
| Linking `DevBench::API` puts `DevBenchAPI.h` on the include path and compiles | ||
| `DevBenchAPI.cpp` (the messaging-handshake helper) into your plugin. The API glue is | ||
| **MIT** (`DevBenchAPI.LICENSE.txt`); the devbench plugin itself is GPL-3.0. | ||
|
|
||
| ## Pinning / bumping | ||
|
|
||
| `portfile.cmake` is pinned to a concrete devbench commit via `vcpkg_from_github` | ||
| (`REF` + `SHA512`) — no placeholders to fill in; the overlay works as-is. To pull a | ||
| newer API revision, update `REF` to the new commit and replace `SHA512` with the value | ||
| vcpkg reports on the first (failed) build, or precompute it with | ||
| `vcpkg hash <downloaded-tarball>`. The API header is ABI-versioned, so a bump is only | ||
| needed to adopt a new interface revision. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| get_filename_component(_DEVBENCH_API_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) | ||
|
|
||
| # DevBench::API — header-only-ish target. The consumer gets the include dir and | ||
| # DevBenchAPI.cpp compiled into it (the consumer-side helper that fetches the | ||
| # interface via SKSE messaging). Link this, then call | ||
| # DevBenchAPI::GetDevBenchInterface001() after kPostLoad. | ||
| if(NOT TARGET DevBench::API) | ||
| add_library(DevBench::API INTERFACE IMPORTED) | ||
| set_target_properties(DevBench::API PROPERTIES | ||
| INTERFACE_INCLUDE_DIRECTORIES "${_DEVBENCH_API_DIR}/../../include" | ||
| INTERFACE_SOURCES "${_DEVBENCH_API_DIR}/src/DevBenchAPI.cpp" | ||
| ) | ||
| endif() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # devbench-api — header-only cross-plugin API for SKSE consumers. | ||
| # Mirrors the SkyrimVRESL port: installs the MIT API header + its companion .cpp | ||
| # (compiled into the consumer via the config's INTERFACE_SOURCES). | ||
| # | ||
| # Pinned to a published commit. devbench-api isn't in the official vcpkg registry, so | ||
| # consumers add this directory to VCPKG_OVERLAY_PORTS (see README). To ship a newer API | ||
| # revision, bump REF to the new commit and SHA512 to its archive hash. | ||
|
|
||
| vcpkg_from_github( | ||
| OUT_SOURCE_PATH SOURCE_PATH | ||
| REPO alandtse/devbench | ||
| REF 2f0dac74f409f895b8b74e5440be8371e33fe0b0 | ||
| SHA512 0bc46d6a09cf0b216373b1ec09d8da8b338b58b90618f3b1b8cea07616875a7fc85c6e777166a0998213f0e73e7ea099e20142591fe3de77f36113241985ae3e | ||
| HEAD_REF main | ||
| ) | ||
|
|
||
| # MIT API glue → header to include/, source to share/ (referenced by the config target). | ||
| file(INSTALL "${SOURCE_PATH}/include/DevBenchAPI.h" | ||
| DESTINATION "${CURRENT_PACKAGES_DIR}/include") | ||
| file(INSTALL "${SOURCE_PATH}/include/DevBenchAPI.cpp" | ||
| DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/src") | ||
|
|
||
| # CMake package config — defines DevBench::API. | ||
| file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/devbench-api-config.cmake" | ||
| DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") | ||
|
|
||
| # The API glue is MIT (not the GPL-3.0 plugin) — ship that as the port copyright. | ||
| file(INSTALL "${SOURCE_PATH}/include/DevBenchAPI.LICENSE.txt" | ||
| DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "name": "devbench-api", | ||
| "version": "1.0.0", | ||
| "description": "devbench cross-plugin API header for SKSE plugin developers. Register MCP/REST tools and emit events into the devbench host. MIT-licensed glue; the devbench plugin itself is GPL-3.0.", | ||
| "homepage": "https://github.com/alandtse/devbench", | ||
| "license": "MIT" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| #include "DevBenchBridge.h" | ||
|
|
||
| // Registers our tools into the devbench test bench over its C-ABI. Gated by | ||
| // DEVBENCH_BRIDGE_ENABLED (set by CMake when the devbench-api port is available); | ||
| // otherwise this file compiles to an empty Install(). Inert at runtime when no | ||
| // devbench plugin is present (GetDevBenchInterface001() returns null). | ||
|
|
||
| #ifdef DEVBENCH_BRIDGE_ENABLED | ||
|
|
||
| # include "Feature.h" | ||
|
|
||
| # include <DevBenchAPI.h> | ||
| # include <nlohmann/json.hpp> | ||
|
|
||
| # include <stdexcept> | ||
|
|
||
| namespace | ||
| { | ||
| // Build the `feature` tool result. May throw (json type errors etc.); the C-ABI | ||
| // handler below contains every exception so none crosses the DLL boundary. | ||
| nlohmann::json BuildFeatureResult(const nlohmann::json& a_args) | ||
| { | ||
| using json = nlohmann::json; | ||
| const std::string action = a_args.value("action", std::string("list")); | ||
|
|
||
| if (action == "list") { | ||
| json out = json::array(); | ||
| for (auto* f : Feature::GetFeatureList()) { | ||
| out.push_back(json{ | ||
| { "name", f->GetName() }, | ||
| { "shortName", f->GetShortName() }, | ||
| { "loaded", f->loaded }, | ||
| { "isCore", f->IsCore() }, | ||
| { "supportsVR", f->SupportsVR() }, | ||
| }); | ||
| } | ||
| return out; | ||
| } | ||
| if (action == "toggle") { | ||
| const std::string shortName = a_args.value("shortName", std::string{}); | ||
| // Match over the full feature list (NOT Feature::FindFeatureByShortName, | ||
| // which only matches *loaded* features — that makes toggle one-way: you could | ||
| // disable a feature but never re-enable it). Mirrors the 'list' branch. | ||
| Feature* target = nullptr; | ||
| if (!shortName.empty()) { | ||
| for (auto* f : Feature::GetFeatureList()) { | ||
| if (f->GetShortName() == shortName) { | ||
| target = f; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (!target) | ||
| return json{ { "error", "unknown or missing shortName" }, { "shortName", shortName } }; | ||
| const bool desired = a_args.value("enabled", !target->loaded); | ||
|
alandtse marked this conversation as resolved.
Outdated
|
||
| auto* task = SKSE::GetTaskInterface(); | ||
| if (!task) | ||
| return json{ { "error", "SKSE task interface unavailable" }, { "shortName", shortName } }; | ||
| task->AddTask([target, desired]() { target->loaded = desired; }); | ||
| return json{ { "queued", true }, { "shortName", shortName }, { "requested", desired } }; | ||
| } | ||
| return json{ { "error", "unknown action (list|toggle)" }, { "action", action } }; | ||
| } | ||
|
|
||
| // CS `feature` tool, re-exposed through devbench. Captureless C function (the C-ABI | ||
| // forbids std::function across the DLL boundary). Runs on devbench's listener thread; | ||
| // mutations marshal to the main thread via SKSE's TaskInterface. Every exception is | ||
| // contained here and a_write is always called once — nothing escapes across the C ABI. | ||
| void FeatureToolHandler(void*, const char* a_argsJson, void* a_sink, DevBenchAPI::WriteFn a_write) | ||
| { | ||
| using json = nlohmann::json; | ||
| json out; | ||
| try { | ||
| json args = json::object(); | ||
| if (a_argsJson && *a_argsJson) | ||
| args = json::parse(a_argsJson); // throws on malformed input | ||
| if (!args.is_object()) | ||
| throw std::runtime_error("arguments must be a JSON object"); | ||
| out = BuildFeatureResult(args); | ||
| } catch (const std::exception& e) { | ||
| out = json{ { "error", "invalid request" }, { "detail", e.what() } }; | ||
| } catch (...) { | ||
| out = json{ { "error", "unknown handler error" } }; | ||
| } | ||
| const std::string dumped = out.dump(); | ||
| a_write(a_sink, dumped.c_str()); | ||
| } | ||
| } | ||
|
|
||
| namespace DevBenchBridge | ||
| { | ||
| void Install() | ||
| { | ||
| auto* dvb = DevBenchAPI::GetDevBenchInterface001(); | ||
| if (!dvb) { | ||
| logger::info("DevBenchBridge: devbench not present; CS tools not registered"); | ||
| return; | ||
| } | ||
| logger::info("DevBenchBridge: devbench build {} present — registering CS tools", dvb->GetBuildNumber()); | ||
|
|
||
| // Namespaced tool name — devbench's registry is shared across plugins, so a bare | ||
| // "feature" could collide with devbench's own or another mod's tool. | ||
| static constexpr const char* featureDesc = | ||
| R"({"description":"List or toggle Open Shaders features.","inputSchema":{"type":"object","properties":{"action":{"type":"string","enum":["list","toggle"]},"shortName":{"type":"string"},"enabled":{"type":"boolean"}}}})"; | ||
| dvb->RegisterTool("openshaders.feature", featureDesc, &FeatureToolHandler, nullptr); | ||
|
|
||
| // Further CS tools (feature set/reset, shader-cache, capture, abtest) and | ||
| // shader-recompile events register here via the same dvb->RegisterTool / EmitEvent. | ||
| } | ||
| } | ||
|
|
||
| #else | ||
|
|
||
| namespace DevBenchBridge | ||
| { | ||
| void Install() {} // inert until built with DEVBENCH_BRIDGE_ENABLED | ||
| } | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #pragma once | ||
|
|
||
| // Client-side bridge to the devbench host (https://github.com/alandtse/devbench). | ||
| // Registers Open Shaders' tools into devbench over its cross-plugin C-ABI so they are | ||
| // drivable from the shared bench (MCP + REST). | ||
| // | ||
| // The implementation compiles only with -DDEVBENCH_BRIDGE_ENABLED (set by CMake when the | ||
| // `devbench-api` port is available); otherwise this file compiles to an empty Install(). | ||
| // When built in, Install() is still a runtime no-op if no devbench host is present — so | ||
| // it is always safe to call. | ||
| namespace DevBenchBridge | ||
| { | ||
| // Fetch the devbench interface (after kPostLoad) and register our tools. No-op if | ||
| // devbench is not present or the bridge was built disabled. Safe to call always. | ||
| void Install(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.