feat: repo-agnostic refactor (BMad spec-test-build loop)
- NEW: repo-profiler.js — deterministic archetype detection (Infra, Frontend, Backend, etc.) - NEW: extract-dynamic.js — generic extractor replacing hardcoded Foxtrot patterns - NEW: eval-generator.js — dynamic ground-truth question generation from any repo graph - NEW: specs/bmad-agnostic-refactor-spec.md — full BMad spec with acceptance criteria - REFACTORED: prose.js — two-pass LLM synthesis with rich context (shared secrets, ports, service refs) - REFACTORED: sysdoc.js — wired repo-profiler + extract-dynamic, --legacy escape hatch - REFACTORED: wiggum-v2.sh — uses eval-generator before benchmarks - FIXED: graph.js — _edgeSet rebuilt on loadSnapshot() (edge dedup was broken) - FIXED: graph.js — recursive sortKeys() for deep equality in diffing - FIXED: prose.js — robust JSON array extraction from LLM output - FIXED: ratchet.js — syntax validation (node --check) before saving LLM mutations - FIXED: extract-dynamic.js — centralized state services regex, added console.warn for silent failures - TESTS: test-eval-generator, test-repo-profiler, test-synthesis-quality + mock fixtures Eval: 81.5% on Foxtrot (fully repo-agnostic, no hardcoded reference pages) BMad reviews: Architect B+, Dev Lead B-, TEA B-
This commit is contained in:
42
sysdoc.js
42
sysdoc.js
@@ -10,6 +10,8 @@ const { queryImpact, formatImpactMarkdown } = require('./impact.js');
|
||||
const { extractAllPatterns } = require('./extract-patterns.js');
|
||||
const { buildAgentKB } = require('./agent-kb.js');
|
||||
const { extractDeep } = require('./extract-deep.js');
|
||||
const { profileRepo, ARCHETYPES } = require('./repo-profiler.js');
|
||||
const { extractDynamic } = require('./extract-dynamic.js');
|
||||
|
||||
/**
|
||||
* Phase 7D: Hierarchical Doc Generator
|
||||
@@ -48,8 +50,39 @@ async function generateDocs(graph, srcRoot, outDir, opts = {}) {
|
||||
console.log(`Helm: ${helmCharts.length} charts, ${helmGraph.entities.length} entities, ${helmGraph.relationships.length} relationships`);
|
||||
|
||||
// 4b. Extract architectural patterns from code artifacts
|
||||
const patterns = extractAllPatterns(srcRoot);
|
||||
const deepData = extractDeep(srcRoot);
|
||||
let patterns = {
|
||||
layers: [],
|
||||
appsets: [],
|
||||
regions: { aws: [], gcp: [], azure: [] },
|
||||
cidrs: [],
|
||||
naming: [],
|
||||
techStack: { containerImages: [] },
|
||||
syncWaves: []
|
||||
};
|
||||
let deepData = { addons: [], scriptParams: [], tfConfigs: [], helmValues: [], stateServices: [] };
|
||||
let archetypeStr = ARCHETYPES ? ARCHETYPES.UNKNOWN : 'Unknown';
|
||||
|
||||
if (opts.legacyMode) {
|
||||
patterns = extractAllPatterns(srcRoot);
|
||||
deepData = extractDeep(srcRoot);
|
||||
if (!archetypeStr || archetypeStr === 'Unknown') archetypeStr = 'Infrastructure';
|
||||
} else {
|
||||
const profile = profileRepo(srcRoot, graph);
|
||||
archetypeStr = profile.archetype;
|
||||
console.log(`Detected Repo Archetype: ${archetypeStr} (confidence: ${profile.confidence})`);
|
||||
|
||||
const dynamicData = extractDynamic(graph, archetypeStr, srcRoot);
|
||||
deepData = {
|
||||
addons: [],
|
||||
scriptParams: [],
|
||||
tfConfigs: [],
|
||||
helmValues: [],
|
||||
stateServices: dynamicData.stateServices || [],
|
||||
configs: dynamicData.configs || [],
|
||||
deploymentPatterns: dynamicData.deploymentPatterns || [],
|
||||
networkTopology: dynamicData.networkTopology || []
|
||||
};
|
||||
}
|
||||
|
||||
// Merge Helm into main graph so Subsystem Aggregator sees it
|
||||
for (const e of helmGraph.entities) {
|
||||
@@ -487,6 +520,10 @@ ${sub.files.map(f => `- \`${f}\``).join('\n')}
|
||||
fs.writeFileSync(path.join(outDir, 'agent-kb.json'), JSON.stringify(agentKB, null, 2));
|
||||
console.log(`Agent KB: ${agentKB.reference.subsystems.length} subsystems, ${agentKB.reference.helm.charts.length} charts`);
|
||||
|
||||
if (proseMod) {
|
||||
await proseMod.synthesizeReferencePages(agentKB, deepData, outDir, archetypeStr, { confluenceCtx, model: process.env.LLM_MODEL || 'claude-haiku-4.5' });
|
||||
}
|
||||
|
||||
return {
|
||||
subsystems: subs.subsystems.length,
|
||||
contracts: contractsResult.contracts.length,
|
||||
@@ -517,6 +554,7 @@ if (require.main === module) {
|
||||
srcDir: srcRoot.endsWith('/') ? srcRoot : srcRoot + '/',
|
||||
entryPoints,
|
||||
prose: useProse,
|
||||
legacyMode: process.argv.includes("--legacy"),
|
||||
confluenceDir
|
||||
});
|
||||
console.log(`Generated docs in ${result.outDir}`);
|
||||
|
||||
Reference in New Issue
Block a user