Step 639: project skeleton generator

This commit is contained in:
Bill
2026-02-17 21:42:38 -07:00
parent 9e30117aa1
commit 106f5a45bd
4 changed files with 228 additions and 0 deletions

View File

@@ -4630,4 +4630,13 @@ target_link_libraries(step638_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step639_test tests/step639_test.cpp)
target_include_directories(step639_test PRIVATE src)
target_link_libraries(step639_test PRIVATE
nlohmann_json::nlohmann_json
unofficial::tree-sitter::tree-sitter
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)

View File

@@ -0,0 +1,67 @@
#pragma once
// Step 639: whetstone_generate_project MCP tool model
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
using json = nlohmann::json;
struct GeneratedProjectSkeleton {
bool success = false;
std::string name;
std::string cmakeLists;
std::string mainCpp;
std::vector<std::string> moduleHeaders;
std::vector<std::string> dependencies;
std::vector<std::string> errors;
};
class ProjectSkeletonGenerator {
public:
static std::string toolName() { return "whetstone_generate_project"; }
static GeneratedProjectSkeleton generate(const std::string& name,
const std::string& description,
const std::vector<std::string>& dependencies) {
GeneratedProjectSkeleton out;
if (name.empty()) {
out.errors.push_back("name_required");
return out;
}
out.success = true;
out.name = name;
out.dependencies = dependencies;
out.moduleHeaders = {
"include/AppCore.h",
"include/TaskRouter.h"
};
out.cmakeLists = "cmake_minimum_required(VERSION 3.24)\n"
"project(" + name + " LANGUAGES CXX)\n"
"set(CMAKE_CXX_STANDARD 20)\n"
"add_executable(" + name + " src/main.cpp)\n";
for (const auto& dep : dependencies) {
out.cmakeLists += "find_package(" + dep + " CONFIG REQUIRED)\n";
}
out.cmakeLists += "target_include_directories(" + name + " PRIVATE include)\n";
out.mainCpp = "#include <iostream>\n"
"int main(){ std::cout << \"" + description + "\\n\"; return 0; }\n";
return out;
}
static json asToolResponse(const GeneratedProjectSkeleton& out) {
return {
{"success", out.success},
{"name", out.name},
{"cmakeLists", out.cmakeLists},
{"mainCpp", out.mainCpp},
{"moduleHeaders", out.moduleHeaders},
{"dependencies", out.dependencies},
{"errors", out.errors}
};
}
};

View File

@@ -0,0 +1,121 @@
// Step 639: whetstone_generate_project MCP tool (12 tests)
#include "ProjectSkeletonGenerator.h"
#include <iostream>
static int passed = 0, failed = 0;
#define TEST(name) { std::cout << " " << #name << "... "; }
#define PASS() { std::cout << "PASS\n"; ++passed; }
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; }
void test_tool_name_matches_spec() {
TEST(tool_name_matches_spec);
CHECK(ProjectSkeletonGenerator::toolName() == "whetstone_generate_project", "tool name mismatch");
PASS();
}
void test_generate_rejects_empty_name() {
TEST(generate_rejects_empty_name);
auto out = ProjectSkeletonGenerator::generate("", "desc", {});
CHECK(!out.success, "empty name should fail");
CHECK(!out.errors.empty(), "error expected");
PASS();
}
void test_generate_sets_project_name() {
TEST(generate_sets_project_name);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
CHECK(out.success, "generation should succeed");
CHECK(out.name == "drone", "name mismatch");
PASS();
}
void test_generate_emits_cmake_project_line() {
TEST(generate_emits_cmake_project_line);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
CHECK(out.cmakeLists.find("project(drone") != std::string::npos, "project line missing");
PASS();
}
void test_generate_emits_executable_target() {
TEST(generate_emits_executable_target);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
CHECK(out.cmakeLists.find("add_executable(drone") != std::string::npos, "target line missing");
PASS();
}
void test_generate_emits_find_package_for_dependencies() {
TEST(generate_emits_find_package_for_dependencies);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {"nlohmann_json"});
CHECK(out.cmakeLists.find("find_package(nlohmann_json CONFIG REQUIRED)") != std::string::npos,
"dependency line missing");
PASS();
}
void test_generate_emits_main_cpp_with_description() {
TEST(generate_emits_main_cpp_with_description);
auto out = ProjectSkeletonGenerator::generate("drone", "HiveMind bootstrap", {});
CHECK(out.mainCpp.find("HiveMind bootstrap") != std::string::npos, "description missing in main");
PASS();
}
void test_generate_includes_module_headers() {
TEST(generate_includes_module_headers);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
CHECK(out.moduleHeaders.size() == 2, "module header count mismatch");
PASS();
}
void test_as_tool_response_includes_success_flag() {
TEST(as_tool_response_includes_success_flag);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
auto response = ProjectSkeletonGenerator::asToolResponse(out);
CHECK(response.value("success", false), "success flag missing");
PASS();
}
void test_as_tool_response_includes_cmake_text() {
TEST(as_tool_response_includes_cmake_text);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
auto response = ProjectSkeletonGenerator::asToolResponse(out);
CHECK(response.value("cmakeLists", "").find("cmake_minimum_required") != std::string::npos,
"cmake text missing");
PASS();
}
void test_as_tool_response_includes_dependencies() {
TEST(as_tool_response_includes_dependencies);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {"sqlite3"});
auto response = ProjectSkeletonGenerator::asToolResponse(out);
CHECK(response["dependencies"].size() == 1, "dependency count mismatch");
PASS();
}
void test_generate_handles_empty_dependencies_edge_case() {
TEST(generate_handles_empty_dependencies_edge_case);
auto out = ProjectSkeletonGenerator::generate("drone", "desc", {});
CHECK(out.dependencies.empty(), "dependencies should be empty");
PASS();
}
int main() {
std::cout << "Step 639: whetstone_generate_project MCP tool\n";
test_tool_name_matches_spec();
test_generate_rejects_empty_name();
test_generate_sets_project_name();
test_generate_emits_cmake_project_line();
test_generate_emits_executable_target();
test_generate_emits_find_package_for_dependencies();
test_generate_emits_main_cpp_with_description();
test_generate_includes_module_headers();
test_as_tool_response_includes_success_flag();
test_as_tool_response_includes_cmake_text();
test_as_tool_response_includes_dependencies();
test_generate_handles_empty_dependencies_edge_case();
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -12982,3 +12982,34 @@ and a shared-header main entry path.
- `editor/src/Phase38aIntegration.h` (`61` <= `600`)
- `editor/tests/step638_test.cpp` within test-file size guidance (`83` lines)
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`
### Step 639: `whetstone_generate_project` MCP tool
**Status:** PASS (12/12 tests)
Adds a project skeleton generator for one-call C++ project bootstrap from
description metadata, including `CMakeLists.txt`, `main.cpp`, module-header
stubs, dependency wiring, and JSON tool-response shaping.
**Files added:**
- `editor/src/ProjectSkeletonGenerator.h` - project-generation module:
- generator entrypoint for project name/description/dependencies
- CMake and main-entry text emission
- MCP-style JSON response shaping helper
- `editor/tests/step639_test.cpp` - 12 tests covering:
- tool identity and invalid-input handling
- project/cmake/main generation behavior
- dependency propagation and response payload shape
**Files modified:**
- `editor/CMakeLists.txt` - `step639_test` target
**Verification run:**
- `cmake -S editor -B editor/build-native` - PASS
- `cmake --build editor/build-native --target step639_test step638_test` - PASS
- `./editor/build-native/step639_test` - PASS (12/12)
- `./editor/build-native/step638_test` - PASS (8/8) regression coverage
**Architecture gate check:**
- `editor/src/ProjectSkeletonGenerator.h` (`67` <= `600`)
- `editor/tests/step639_test.cpp` within test-file size guidance (`121` lines)
- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md`