@@ -10,7 +10,7 @@ import { writeJson, readJson, readAllCodeFiles } from '../io/file-protocol.mts';
1010import { access , readFile , writeFile , mkdir } from 'node:fs/promises' ;
1111import type { CodeFile } from '../agents/codegen-agent.mts' ;
1212import { z } from 'zod' ;
13- import { dirname } from 'node:path' ;
13+ import { dirname , join } from 'node:path' ;
1414import { validateGraph } from '../graph/task-graph.mts' ;
1515import { executeGraph } from '../graph/parallel-executor.mts' ;
1616import { runFixLoop } from './fix-loop.mts' ;
@@ -443,61 +443,63 @@ export async function runPipeline(
443443 }
444444 } // end skipDocs guard
445445
446- // Phase 4: Generate architecture diagrams via diagram-agent
446+ // Phase 4: Generate architecture diagrams via diagram-generator- agent
447447 if ( config . skipDiagrams ) {
448448 logger . info ( `Phase 4: Diagrams — skipped (--no-diagrams)` ) ;
449449 } else {
450- logger . info ( `Phase 4: Generating architecture diagrams` ) ;
451- try {
452- // Build a system description from the PRD + task results for the diagram agent
453- const diagramInput = [
454- `# System Architecture Description` ,
455- `` ,
456- `## PRD Summary` ,
457- prdText . substring ( 0 , 3000 ) ,
458- `` ,
459- `## Generated Components` ,
460- ...taskGraph . tasks . map ( ( t ) => `- **${ t . name } ** (${ t . type } ): ${ t . description . substring ( 0 , 100 ) } ` ) ,
461- `` ,
462- `## Task Dependencies` ,
463- ...taskGraph . tasks . filter ( ( t ) => t . dependsOn . length > 0 ) . map ( ( t ) => `- ${ t . id } depends on: ${ t . dependsOn . join ( `, ` ) } ` ) ,
464- `` ,
465- `## Technology Stack` ,
466- `- Runtime: BunJS` ,
467- `- Framework: Elysia` ,
468- `- Database: MongoDB (Docker)` ,
469- `- Auth: JWT via jose + Elysia .resolve() pattern` ,
470- `- Validation: TypeBox` ,
471- `- Testing: bun:test against real MongoDB` ,
472- ] . join ( `\n` ) ;
473-
474- const diagramDescPath = `${ workspace . root } /diagram-input.md` ;
475- const diagramOutputDir = `${ workspace . outputDir ( ) } /graphs` ;
476- await writeFile ( diagramDescPath , diagramInput , `utf-8` ) ;
477-
478- const DIAGRAM_AGENT_PATH = `C:/projects/davis/agents/diagram-agent/src/index.mts` ;
479- const diagramProc = Bun . spawn ( [ `bun` , `run` , DIAGRAM_AGENT_PATH , diagramDescPath , diagramOutputDir ] , {
480- stdout : `pipe` ,
481- stderr : `pipe` ,
482- env : { ...Bun . env } ,
483- cwd : `C:/projects/davis/agents/diagram-agent` ,
484- } ) ;
485-
486- const [ diagramStdout , diagramStderr ] = await Promise . all ( [
487- new Response ( diagramProc . stdout ) . text ( ) ,
488- new Response ( diagramProc . stderr ) . text ( ) ,
489- ] ) ;
490- const diagramExit = await diagramProc . exited ;
491-
492- if ( diagramExit === 0 ) {
493- logger . info ( `[pipeline] Architecture diagrams generated at ${ diagramOutputDir } ` ) ;
494- } else {
495- logger . warn ( `[pipeline] Diagram generation failed (exit ${ diagramExit } ): ${ diagramStderr . substring ( 0 , 500 ) } ` ) ;
450+ logger . info ( `Phase 4: Generating architecture diagrams` ) ;
451+ try {
452+ // Build a system description from the PRD + task results for the diagram agent
453+ const diagramInput = [
454+ `# System Architecture Description` ,
455+ `` ,
456+ `## PRD Summary` ,
457+ prdText . substring ( 0 , 3000 ) ,
458+ `` ,
459+ `## Generated Components` ,
460+ ...taskGraph . tasks . map ( ( t ) => `- **${ t . name } ** (${ t . type } ): ${ t . description . substring ( 0 , 100 ) } ` ) ,
461+ `` ,
462+ `## Task Dependencies` ,
463+ ...taskGraph . tasks . filter ( ( t ) => t . dependsOn . length > 0 ) . map ( ( t ) => `- ${ t . id } depends on: ${ t . dependsOn . join ( `, ` ) } ` ) ,
464+ `` ,
465+ `## Technology Stack` ,
466+ `- Runtime: BunJS` ,
467+ `- Framework: Elysia` ,
468+ `- Database: MongoDB (Docker)` ,
469+ `- Auth: JWT via jose + Elysia .resolve() pattern` ,
470+ `- Validation: TypeBox` ,
471+ `- Testing: bun:test against real MongoDB` ,
472+ ] . join ( `\n` ) ;
473+
474+ const diagramDescPath = `${ workspace . root } /diagram-input.md` ;
475+ await writeFile ( diagramDescPath , diagramInput , `utf-8` ) ;
476+
477+ // Ensure diagram-generator-agent is available locally
478+ const agentDir = await ensureDiagramAgent ( config . workspaceDir , logger ) ;
479+
480+ // Run the diagram agent with --prd pointing at our generated description
481+ const diagramProc = Bun . spawn ( [ `bun` , `run` , `src/index.mts` , `--prd` , diagramDescPath ] , {
482+ stdout : `pipe` ,
483+ stderr : `pipe` ,
484+ env : { ...Bun . env , WORKSPACE_DIR : `${ workspace . outputDir ( ) } /graphs` } ,
485+ cwd : agentDir ,
486+ } ) ;
487+
488+ const [ , diagramStderr ] = await Promise . all ( [
489+ new Response ( diagramProc . stdout ) . text ( ) ,
490+ new Response ( diagramProc . stderr ) . text ( ) ,
491+ ] ) ;
492+ const diagramExit = await diagramProc . exited ;
493+
494+ if ( diagramExit === 0 ) {
495+ logger . info ( `[pipeline] Architecture diagrams generated at ${ workspace . outputDir ( ) } /graphs` ) ;
496+ } else {
497+ logger . warn ( `[pipeline] Diagram generation failed (exit ${ diagramExit } ): ${ diagramStderr . substring ( 0 , 500 ) } ` ) ;
498+ }
499+ } catch ( e ) {
500+ const msg = e instanceof Error ? e . message : String ( e ) ;
501+ logger . warn ( `[pipeline] Diagram generation skipped: ${ msg } ` ) ;
496502 }
497- } catch ( e ) {
498- const msg = e instanceof Error ? e . message : String ( e ) ;
499- logger . warn ( `[pipeline] Diagram generation skipped: ${ msg } ` ) ;
500- }
501503 } // end skipDiagrams guard
502504
503505 // Phase 4.5: Output validation — install deps, start server, verify swagger renders
@@ -812,3 +814,49 @@ async function gatherAllCode(workspace: Workspace, graph: TaskGraph): Promise<st
812814
813815 return parts . length > 0 ? parts . join ( '\n\n' ) : undefined ;
814816}
817+
818+ const DIAGRAM_AGENT_REPO = `https://github.com/DavisSylvester/diagram-generator-agent.git` ;
819+
820+ async function ensureDiagramAgent ( baseDir : string , logger : Logger ) : Promise < string > {
821+ const agentDir = join ( baseDir , `.agents` , `diagram-generator-agent` ) ;
822+
823+ try {
824+ await access ( join ( agentDir , `package.json` ) ) ;
825+ logger . info ( `[diagrams] Diagram agent found at ${ agentDir } ` ) ;
826+ return agentDir ;
827+ } catch {
828+ // Not present — clone it
829+ }
830+
831+ logger . info ( `[diagrams] Diagram agent not found — cloning from ${ DIAGRAM_AGENT_REPO } ` ) ;
832+ await mkdir ( dirname ( agentDir ) , { recursive : true } ) ;
833+
834+ const cloneProc = Bun . spawn ( [ `git` , `clone` , `--depth` , `1` , DIAGRAM_AGENT_REPO , agentDir ] , {
835+ stdout : `pipe` ,
836+ stderr : `pipe` ,
837+ } ) ;
838+ const cloneStderr = await new Response ( cloneProc . stderr ) . text ( ) ;
839+ const cloneExit = await cloneProc . exited ;
840+
841+ if ( cloneExit !== 0 ) {
842+ throw new Error ( `Failed to clone diagram agent: ${ cloneStderr . substring ( 0 , 500 ) } ` ) ;
843+ }
844+ logger . info ( `[diagrams] Cloned diagram-generator-agent` ) ;
845+
846+ // Install dependencies
847+ logger . info ( `[diagrams] Installing dependencies...` ) ;
848+ const installProc = Bun . spawn ( [ `bun` , `install` ] , {
849+ cwd : agentDir ,
850+ stdout : `pipe` ,
851+ stderr : `pipe` ,
852+ } ) ;
853+ const installStderr = await new Response ( installProc . stderr ) . text ( ) ;
854+ const installExit = await installProc . exited ;
855+
856+ if ( installExit !== 0 ) {
857+ throw new Error ( `Failed to install diagram agent deps: ${ installStderr . substring ( 0 , 500 ) } ` ) ;
858+ }
859+ logger . info ( `[diagrams] Dependencies installed` ) ;
860+
861+ return agentDir ;
862+ }
0 commit comments