Step 639: project skeleton generator
This commit is contained in:
@@ -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)
|
||||
|
||||
67
editor/src/ProjectSkeletonGenerator.h
Normal file
67
editor/src/ProjectSkeletonGenerator.h
Normal 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}
|
||||
};
|
||||
}
|
||||
};
|
||||
121
editor/tests/step639_test.cpp
Normal file
121
editor/tests/step639_test.cpp
Normal 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;
|
||||
}
|
||||
31
progress.md
31
progress.md
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user