#pragma once // Step 479: Dependency + Build System Awareness // Adds build/dependency annotations from scaffold module dependencies. #include "ArchitectSkeletonGenerator.h" #include #include #include #include #include #include struct BuildDependencyAnnotation { std::string moduleName; std::string language; std::vector moduleDependencies; std::vector importHints; std::vector packageDependencies; std::string manifestSnippet; int migrationOrder = 0; // SQL-only: 1-based order std::vector notes; }; struct BuildAwarenessReport { std::vector modules; std::vector globalNotes; bool hasModule(const std::string& moduleName) const { for (const auto& m : modules) if (m.moduleName == moduleName) return true; return false; } BuildDependencyAnnotation getModule(const std::string& moduleName) const { for (const auto& m : modules) if (m.moduleName == moduleName) return m; return {}; } }; class ArchitectBuildAwareness { public: static BuildAwarenessReport annotate(const SkeletonProjectSpec& skeleton) { BuildAwarenessReport out; const auto sqlOrder = computeSqlMigrationOrder(skeleton); for (const auto& m : skeleton.modules) { BuildDependencyAnnotation ann; ann.moduleName = m.moduleName; ann.language = lower(m.language); ann.moduleDependencies = m.dependencies; if (ann.language == "python") { annotatePython(m, ann); } else if (ann.language == "rust") { annotateRust(m, ann); } else if (ann.language == "typescript" || ann.language == "javascript") { annotateNode(m, ann); } else if (ann.language == "cpp" || ann.language == "c") { annotateCpp(m, ann); } else if (ann.language == "sql") { annotateSql(m, ann, sqlOrder); } else { annotateGeneric(m, ann); } out.modules.push_back(std::move(ann)); } out.globalNotes.push_back("Build awareness report generated from module dependencies"); out.globalNotes.push_back("Snippets are annotation-level hints, not executable build configs"); return out; } private: static std::string lower(const std::string& s) { std::string out = s; std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return out; } static void annotatePython(const SkeletonModuleSpec& m, BuildDependencyAnnotation& ann) { for (const auto& dep : m.dependencies) { ann.importHints.push_back("from " + dep + " import *"); } ann.packageDependencies.push_back("typing-extensions"); if (m.moduleName.find("api") != std::string::npos) ann.packageDependencies.push_back("fastapi"); if (m.moduleName.find("data") != std::string::npos) ann.packageDependencies.push_back("sqlalchemy"); ann.manifestSnippet = "dependencies = ["; for (size_t i = 0; i < ann.packageDependencies.size(); ++i) { if (i) ann.manifestSnippet += ", "; ann.manifestSnippet += "\"" + ann.packageDependencies[i] + "\""; } ann.manifestSnippet += "]"; ann.notes.push_back("Python imports mapped from module graph"); } static void annotateRust(const SkeletonModuleSpec& m, BuildDependencyAnnotation& ann) { ann.packageDependencies.push_back("serde = \"1\""); for (const auto& dep : m.dependencies) { ann.packageDependencies.push_back(dep + " = { path = \"../" + dep + "\" }"); ann.importHints.push_back("use crate::" + dep + "::*;"); } ann.manifestSnippet = "[dependencies]\n"; for (const auto& p : ann.packageDependencies) ann.manifestSnippet += p + "\n"; if (m.dependencies.empty()) ann.manifestSnippet += "# no local module dependencies\n"; ann.notes.push_back("Cargo dependency hints generated from module dependencies"); } static void annotateNode(const SkeletonModuleSpec& m, BuildDependencyAnnotation& ann) { ann.packageDependencies.push_back("typescript"); if (m.moduleName.find("api") != std::string::npos) ann.packageDependencies.push_back("express"); for (const auto& dep : m.dependencies) { ann.importHints.push_back("import * as " + dep + " from \"../" + dep + "/" + dep + "\";"); } ann.manifestSnippet = "\"dependencies\": {"; for (size_t i = 0; i < ann.packageDependencies.size(); ++i) { if (i) ann.manifestSnippet += ", "; ann.manifestSnippet += "\"" + ann.packageDependencies[i] + "\": \"*\""; } ann.manifestSnippet += "}"; ann.notes.push_back("Node package and import hints generated"); } static void annotateCpp(const SkeletonModuleSpec& m, BuildDependencyAnnotation& ann) { for (const auto& dep : m.dependencies) { ann.importHints.push_back("#include \"" + dep + ".h\""); } ann.packageDependencies.push_back("cmake-target:" + m.moduleName); std::string snippet = "add_library(" + m.moduleName + " INTERFACE)\n"; if (!m.dependencies.empty()) { snippet += "target_link_libraries(" + m.moduleName + " INTERFACE"; for (const auto& dep : m.dependencies) snippet += " " + dep; snippet += ")\n"; } ann.manifestSnippet = snippet; ann.notes.push_back("CMake target/link hints generated from dependencies"); } static void annotateSql(const SkeletonModuleSpec& m, BuildDependencyAnnotation& ann, const std::map& sqlOrder) { auto it = sqlOrder.find(m.moduleName); ann.migrationOrder = (it == sqlOrder.end()) ? 0 : it->second; ann.manifestSnippet = "-- migration_order: " + std::to_string(ann.migrationOrder); for (const auto& dep : m.dependencies) { ann.importHints.push_back("-- depends_on: " + dep); } ann.notes.push_back("SQL migration ordering derived from dependency graph"); } static void annotateGeneric(const SkeletonModuleSpec& m, BuildDependencyAnnotation& ann) { ann.manifestSnippet = "# build-hints unavailable for language: " + lower(m.language); if (m.dependencies.empty()) ann.notes.push_back("No dependencies recorded"); else ann.notes.push_back("Dependency links preserved for manual review"); } static std::map computeSqlMigrationOrder(const SkeletonProjectSpec& sk) { std::set sql; for (const auto& m : sk.modules) { if (lower(m.language) == "sql") sql.insert(m.moduleName); } std::vector ordered; std::set temp, perm; bool hasCycle = false; std::function visit = [&](const std::string& node) { if (perm.count(node) || hasCycle) return; if (temp.count(node)) { hasCycle = true; return; } temp.insert(node); for (const auto& m : sk.modules) { if (m.moduleName != node) continue; for (const auto& dep : m.dependencies) { if (sql.count(dep)) visit(dep); } break; } temp.erase(node); perm.insert(node); ordered.push_back(node); }; for (const auto& n : sql) { if (!perm.count(n)) visit(n); } // Cycle fallback: deterministic lexical order. if (hasCycle) { ordered.assign(sql.begin(), sql.end()); std::sort(ordered.begin(), ordered.end()); } std::map out; for (size_t i = 0; i < ordered.size(); ++i) out[ordered[i]] = (int)i + 1; return out; } };