@llm-dev-ops/agentics-cli 1.5.32 → 1.5.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pipeline/auto-chain.d.ts.map +1 -1
- package/dist/pipeline/auto-chain.js +165 -256
- package/dist/pipeline/auto-chain.js.map +1 -1
- package/dist/pipeline/phase2/phases/ddd-generator.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/ddd-generator.js +11 -6
- package/dist/pipeline/phase2/phases/ddd-generator.js.map +1 -1
- package/dist/pipeline/phase3/phases/scaffold-generator.d.ts.map +1 -1
- package/dist/pipeline/phase3/phases/scaffold-generator.js +18 -79
- package/dist/pipeline/phase3/phases/scaffold-generator.js.map +1 -1
- package/dist/pipeline/phase4/phases/http-server-generator.d.ts.map +1 -1
- package/dist/pipeline/phase4/phases/http-server-generator.js +6 -1
- package/dist/pipeline/phase4/phases/http-server-generator.js.map +1 -1
- package/dist/pipeline/phase6/phases/deployment-finalizer.d.ts.map +1 -1
- package/dist/pipeline/phase6/phases/deployment-finalizer.js +1 -11
- package/dist/pipeline/phase6/phases/deployment-finalizer.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-chain.d.ts","sourceRoot":"","sources":["../../src/pipeline/auto-chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AA+BhC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;CACxC;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6MD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"auto-chain.d.ts","sourceRoot":"","sources":["../../src/pipeline/auto-chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AA+BhC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;CACxC;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC1E;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6MD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CA+5B1B;AA6PD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA0DzE"}
|
|
@@ -663,8 +663,8 @@ The prompts must be production-grade — they will be given directly to a coding
|
|
|
663
663
|
? fs.readdirSync(promptsDir).filter(f => f.startsWith('impl-'))
|
|
664
664
|
: [];
|
|
665
665
|
if (generatedPrompts.length === 0) {
|
|
666
|
-
console.error(' [PROMPTS] Ruflo swarm did not produce prompts — writing
|
|
667
|
-
// ── Read
|
|
666
|
+
console.error(' [PROMPTS] Ruflo swarm did not produce prompts — writing SPARC+ADR-driven build phases');
|
|
667
|
+
// ── Read all source material ──
|
|
668
668
|
const adrMarkdownByFile = new Map();
|
|
669
669
|
for (const f of adrFiles) {
|
|
670
670
|
try {
|
|
@@ -672,7 +672,6 @@ The prompts must be production-grade — they will be given directly to a coding
|
|
|
672
672
|
}
|
|
673
673
|
catch { /* skip */ }
|
|
674
674
|
}
|
|
675
|
-
// Read ADR index for structured data
|
|
676
675
|
const adrIndexPath = path.join(adrDir, 'adr-index.json');
|
|
677
676
|
let adrs = [];
|
|
678
677
|
if (fs.existsSync(adrIndexPath)) {
|
|
@@ -685,17 +684,9 @@ The prompts must be production-grade — they will be given directly to a coding
|
|
|
685
684
|
for (const f of adrFiles) {
|
|
686
685
|
const content = adrMarkdownByFile.get(f) ?? '';
|
|
687
686
|
const titleMatch = content.match(/^#\s+(.+)/m);
|
|
688
|
-
adrs.push({
|
|
689
|
-
id: f.replace(/\.md$/, ''),
|
|
690
|
-
title: titleMatch?.[1] ?? f,
|
|
691
|
-
context: content.slice(0, 500),
|
|
692
|
-
decision: '',
|
|
693
|
-
consequences: [],
|
|
694
|
-
alternatives: [],
|
|
695
|
-
});
|
|
687
|
+
adrs.push({ id: f.replace(/\.md$/, ''), title: titleMatch?.[1] ?? f, context: content.slice(0, 500), decision: '', consequences: [], alternatives: [] });
|
|
696
688
|
}
|
|
697
689
|
}
|
|
698
|
-
// Find the full markdown for each ADR (match by ID in filename)
|
|
699
690
|
function getAdrMarkdown(adr) {
|
|
700
691
|
for (const [filename, content] of adrMarkdownByFile) {
|
|
701
692
|
if (filename.startsWith(adr.id))
|
|
@@ -703,285 +694,203 @@ The prompts must be production-grade — they will be given directly to a coding
|
|
|
703
694
|
}
|
|
704
695
|
return '';
|
|
705
696
|
}
|
|
706
|
-
|
|
707
|
-
let
|
|
708
|
-
let glossary = [];
|
|
697
|
+
// Read DDD as reference material (not as driver)
|
|
698
|
+
let dddContent = '';
|
|
709
699
|
const dddModelPath = dddDir ? path.join(dddDir, 'domain-model.json') : '';
|
|
710
700
|
if (dddModelPath && fs.existsSync(dddModelPath)) {
|
|
711
701
|
try {
|
|
712
|
-
|
|
713
|
-
dddContexts = (model.contexts ?? []).map((c) => ({
|
|
714
|
-
name: String(c['name'] ?? 'unknown'),
|
|
715
|
-
description: String(c['description'] ?? ''),
|
|
716
|
-
aggregates: Array.isArray(c['aggregates']) ? c['aggregates'] : [],
|
|
717
|
-
domainEvents: Array.isArray(c['domainEvents']) ? c['domainEvents'] : [],
|
|
718
|
-
commands: Array.isArray(c['commands']) ? c['commands'] : [],
|
|
719
|
-
queries: Array.isArray(c['queries']) ? c['queries'] : [],
|
|
720
|
-
}));
|
|
721
|
-
contextMap = Array.isArray(model.contextMap) ? model.contextMap : [];
|
|
722
|
-
glossary = Array.isArray(model.ubiquitousLanguageGlossary) ? model.ubiquitousLanguageGlossary : [];
|
|
702
|
+
dddContent = fs.readFileSync(dddModelPath, 'utf-8');
|
|
723
703
|
}
|
|
724
|
-
catch { /*
|
|
704
|
+
catch { /* skip */ }
|
|
725
705
|
}
|
|
726
|
-
//
|
|
706
|
+
// Also read DDD markdown if available
|
|
707
|
+
if (dddDir) {
|
|
708
|
+
for (const f of ['domain-model.md', 'ddd-model.md']) {
|
|
709
|
+
const p = path.join(dddDir, f);
|
|
710
|
+
if (fs.existsSync(p)) {
|
|
711
|
+
try {
|
|
712
|
+
dddContent += '\n\n' + fs.readFileSync(p, 'utf-8');
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
catch { /* skip */ }
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// Read SPARC documents
|
|
727
720
|
let sparcSpec = '';
|
|
728
721
|
let sparcArch = '';
|
|
722
|
+
let sparcPseudocode = '';
|
|
723
|
+
let sparcRefinement = '';
|
|
729
724
|
if (sparcDir) {
|
|
730
|
-
for (const [file,
|
|
725
|
+
for (const [file, setter] of [
|
|
726
|
+
['specification.md', 'spec'], ['architecture.md', 'arch'],
|
|
727
|
+
['pseudocode.md', 'pseudo'], ['refinement.md', 'refine'],
|
|
728
|
+
]) {
|
|
731
729
|
const p = path.join(sparcDir, file);
|
|
732
730
|
if (fs.existsSync(p)) {
|
|
733
731
|
try {
|
|
734
732
|
const content = fs.readFileSync(p, 'utf-8');
|
|
735
|
-
if (
|
|
733
|
+
if (setter === 'spec')
|
|
736
734
|
sparcSpec = content;
|
|
737
|
-
else
|
|
735
|
+
else if (setter === 'arch')
|
|
738
736
|
sparcArch = content;
|
|
737
|
+
else if (setter === 'pseudo')
|
|
738
|
+
sparcPseudocode = content;
|
|
739
|
+
else if (setter === 'refine')
|
|
740
|
+
sparcRefinement = content;
|
|
739
741
|
}
|
|
740
742
|
catch { /* skip */ }
|
|
741
743
|
}
|
|
742
744
|
}
|
|
743
745
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
746
|
+
const buildPhases = [
|
|
747
|
+
// Foundation
|
|
748
|
+
{ title: 'Project Foundation & Configuration', slug: 'foundation', description: 'Set up project structure, build tooling, dependency management, and configuration. Establish the base folder layout (src/, backend/, frontend/, erp/, integrations/) and configure TypeScript/Rust build pipelines.', folder: 'src', adrKeywords: ['language', 'framework', 'typescript', 'rust', 'build', 'configuration', 'deployment'], includeSparc: 'spec', includeDdd: false },
|
|
749
|
+
{ title: 'Core Domain Types & Shared Models', slug: 'core-types', description: 'Define the core domain types, enums, interfaces, and shared models that all other modules will import. These are the foundational data structures of the platform.', folder: 'src', adrKeywords: ['data', 'model', 'schema', 'type', 'domain'], includeSparc: 'arch', includeDdd: true },
|
|
750
|
+
{ title: 'Database Schema & Persistence Layer', slug: 'database', description: 'Design and implement the database schema, migrations, connection pooling, and repository interfaces. Create the persistence layer that the backend services will use.', folder: 'backend', adrKeywords: ['database', 'postgres', 'sql', 'bigquery', 'persistence', 'storage', 'migration'], includeSparc: 'none', includeDdd: true },
|
|
751
|
+
// Backend services
|
|
752
|
+
{ title: 'Backend API & Service Layer', slug: 'backend-api', description: 'Implement the HTTP API routes, request validation, service layer, and business logic orchestration. Wire up the API to the domain types and persistence layer.', folder: 'backend', adrKeywords: ['api', 'service', 'endpoint', 'route', 'rest', 'http'], includeSparc: 'pseudo', includeDdd: true },
|
|
753
|
+
{ title: 'Business Logic & Domain Services', slug: 'business-logic', description: 'Implement the core business logic that is unique to this platform. This is where the domain-specific algorithms, calculations, rules, and decision logic live.', folder: 'backend', adrKeywords: ['logic', 'algorithm', 'calculation', 'rule', 'decision', 'simulation', 'optimization', 'model'], includeSparc: 'pseudo', includeDdd: true },
|
|
754
|
+
{ title: 'Authentication & Authorization', slug: 'auth', description: 'Implement authentication (login, tokens, sessions) and authorization (roles, permissions, access control) as specified in the security ADRs.', folder: 'backend', adrKeywords: ['auth', 'security', 'token', 'jwt', 'oauth', 'identity', 'permission', 'role', 'access'], includeSparc: 'none', includeDdd: false },
|
|
755
|
+
// ERP & Integrations
|
|
756
|
+
{ title: 'ERP Integration Layer', slug: 'erp-integration', description: 'Build the ERP integration adapters, data mapping, and sync logic for the ERP system specified in requirements.', folder: 'erp', adrKeywords: ['erp', 'netsuite', 'sap', 'dynamics', 'oracle', 'workday', 'integration'], includeSparc: 'none', includeDdd: false },
|
|
757
|
+
{ title: 'External System Integrations', slug: 'external-integrations', description: 'Implement connectors for external systems, APIs, data sources, and third-party services mentioned in the requirements.', folder: 'integrations', adrKeywords: ['integration', 'connector', 'external', 'api', 'webhook', 'sync', 'import', 'export'], includeSparc: 'none', includeDdd: false },
|
|
758
|
+
// Frontend
|
|
759
|
+
{ title: 'Frontend Application Shell', slug: 'frontend-shell', description: 'Set up the frontend application framework, routing, layout, and component library. Create the application shell that feature pages will plug into.', folder: 'frontend', adrKeywords: ['frontend', 'ui', 'dashboard', 'react', 'vue', 'angular', 'component'], includeSparc: 'none', includeDdd: false },
|
|
760
|
+
{ title: 'Frontend Feature Pages & Components', slug: 'frontend-features', description: 'Build the feature-specific pages, forms, data tables, charts, and interactive components that let users interact with the platform.', folder: 'frontend', adrKeywords: ['dashboard', 'page', 'form', 'table', 'chart', 'visualization', 'report'], includeSparc: 'none', includeDdd: true },
|
|
761
|
+
// Quality & Operations
|
|
762
|
+
{ title: 'Error Handling, Logging & Monitoring', slug: 'observability', description: 'Implement structured logging, error handling, health checks, metrics, and monitoring endpoints.', folder: 'backend', adrKeywords: ['logging', 'error', 'monitoring', 'health', 'metric', 'observability', 'alert'], includeSparc: 'refine', includeDdd: false },
|
|
763
|
+
{ title: 'Testing & Quality Assurance', slug: 'testing', description: 'Write comprehensive unit tests, integration tests, and end-to-end tests. Test the business logic, API endpoints, ERP integration, and frontend components.', folder: 'tests', adrKeywords: ['test', 'quality', 'tdd', 'coverage', 'validation'], includeSparc: 'refine', includeDdd: false },
|
|
764
|
+
{ title: 'Deployment & Infrastructure', slug: 'deployment', description: 'Create Dockerfiles, CI/CD pipelines, cloud deployment configs, environment templates, and infrastructure-as-code for the target cloud platform.', folder: 'src', adrKeywords: ['deploy', 'docker', 'cloud', 'gcp', 'aws', 'azure', 'kubernetes', 'terraform', 'ci', 'cd', 'infrastructure'], includeSparc: 'none', includeDdd: false },
|
|
765
|
+
{ title: 'Security Hardening & Compliance', slug: 'security', description: 'Implement security controls, input validation, audit logging, data encryption, and compliance requirements specified in the ADRs.', folder: 'backend', adrKeywords: ['security', 'audit', 'compliance', 'encryption', 'governance', 'gdpr', 'sox', 'pci'], includeSparc: 'refine', includeDdd: false },
|
|
766
|
+
{ title: 'Documentation & API Reference', slug: 'documentation', description: 'Write API documentation, architecture overview, deployment guide, and user documentation.', folder: 'docs', adrKeywords: ['documentation', 'api', 'reference', 'guide'], includeSparc: 'spec', includeDdd: false },
|
|
767
|
+
];
|
|
768
|
+
// Filter to only phases that have matching ADRs or are always-included foundational phases
|
|
769
|
+
const alwaysInclude = new Set(['foundation', 'core-types', 'database', 'backend-api', 'business-logic', 'testing', 'deployment']);
|
|
770
|
+
const activeBuildPhases = buildPhases.filter(phase => {
|
|
771
|
+
if (alwaysInclude.has(phase.slug))
|
|
772
|
+
return true;
|
|
773
|
+
// Check if any ADR matches this phase's keywords
|
|
774
|
+
return adrs.some(adr => {
|
|
775
|
+
const adrText = `${adr.title} ${adr.context} ${adr.decision}`.toLowerCase();
|
|
776
|
+
return phase.adrKeywords.some(kw => adrText.includes(kw));
|
|
753
777
|
});
|
|
778
|
+
});
|
|
779
|
+
// Also check the scenario query for additional phases
|
|
780
|
+
const queryLower = scenarioQuery.toLowerCase();
|
|
781
|
+
for (const phase of buildPhases) {
|
|
782
|
+
if (!activeBuildPhases.includes(phase)) {
|
|
783
|
+
if (phase.adrKeywords.some(kw => queryLower.includes(kw))) {
|
|
784
|
+
activeBuildPhases.push(phase);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
754
787
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
return contextMap
|
|
758
|
-
.filter(r => r.downstream === contextName)
|
|
759
|
-
.map(r => `${r.upstream} (${r.type})`);
|
|
760
|
-
}
|
|
761
|
-
// Build list of previously completed contexts for dependency tracking
|
|
762
|
-
const completedContexts = [];
|
|
788
|
+
const totalSteps = activeBuildPhases.length;
|
|
789
|
+
const completedPhases = [];
|
|
763
790
|
for (let i = 0; i < totalSteps; i++) {
|
|
791
|
+
const phase = activeBuildPhases[i];
|
|
764
792
|
const order = i + 1;
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
lines.push(
|
|
787
|
-
}
|
|
793
|
+
const filename = `impl-${String(order).padStart(3, '0')}-${phase.slug}.md`;
|
|
794
|
+
const lines = [
|
|
795
|
+
`# Implementation Prompt ${order} of ${totalSteps}: ${phase.title}`,
|
|
796
|
+
'',
|
|
797
|
+
'**The implementation must be production ready, enterprise grade, commercially viable, bug and error free, without compilation errors.**',
|
|
798
|
+
'',
|
|
799
|
+
`**Target folder:** \`${phase.folder}/\``,
|
|
800
|
+
'',
|
|
801
|
+
];
|
|
802
|
+
// Dependencies
|
|
803
|
+
if (order > 1) {
|
|
804
|
+
lines.push(`> This step builds on steps 1-${order - 1}. Import from previously built modules.`);
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
lines.push('> This is the foundation step. Establish the project structure and base configuration.');
|
|
808
|
+
}
|
|
809
|
+
lines.push('');
|
|
810
|
+
// Previously built phases
|
|
811
|
+
if (completedPhases.length > 0) {
|
|
812
|
+
lines.push('## Previously Completed (available for import)', '');
|
|
813
|
+
for (const prev of completedPhases)
|
|
814
|
+
lines.push(`- ${prev}`);
|
|
788
815
|
lines.push('');
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
for (const prev of completedContexts) {
|
|
794
|
-
lines.push(`- **${prev}** — completed`);
|
|
795
|
-
}
|
|
796
|
-
lines.push('');
|
|
797
|
-
}
|
|
798
|
-
// Project objective (first time only, abbreviated after)
|
|
799
|
-
if (order === 1) {
|
|
800
|
-
lines.push('## Project Objective', '', scenarioQuery, '');
|
|
801
|
-
}
|
|
802
|
-
else {
|
|
803
|
-
lines.push(`## Project Objective`, '', scenarioQuery.split('\n')[0]?.slice(0, 300) ?? scenarioQuery.slice(0, 300), '', '> See impl-001 for full project context.', '');
|
|
804
|
-
}
|
|
805
|
-
// Full DDD bounded context specification
|
|
806
|
-
lines.push(`## Bounded Context: ${ctx.name}`, '');
|
|
807
|
-
lines.push(ctx.description, '');
|
|
808
|
-
if (ctx.aggregates.length > 0) {
|
|
809
|
-
lines.push('### Aggregates', '');
|
|
810
|
-
for (const agg of ctx.aggregates) {
|
|
811
|
-
lines.push(`#### ${agg.name} (root: ${agg.root ?? agg.name})`);
|
|
812
|
-
if (agg.entities?.length)
|
|
813
|
-
lines.push(`- **Entities:** ${agg.entities.join(', ')}`);
|
|
814
|
-
if (agg.valueObjects?.length)
|
|
815
|
-
lines.push(`- **Value Objects:** ${agg.valueObjects.join(', ')}`);
|
|
816
|
-
lines.push('');
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
if (ctx.commands.length > 0) {
|
|
820
|
-
lines.push('### Commands', '');
|
|
821
|
-
for (const cmd of ctx.commands)
|
|
822
|
-
lines.push(`- ${cmd}`);
|
|
823
|
-
lines.push('');
|
|
824
|
-
}
|
|
825
|
-
if (ctx.queries.length > 0) {
|
|
826
|
-
lines.push('### Queries', '');
|
|
827
|
-
for (const q of ctx.queries)
|
|
828
|
-
lines.push(`- ${q}`);
|
|
829
|
-
lines.push('');
|
|
830
|
-
}
|
|
831
|
-
if (ctx.domainEvents.length > 0) {
|
|
832
|
-
lines.push('### Domain Events', '');
|
|
833
|
-
for (const evt of ctx.domainEvents)
|
|
834
|
-
lines.push(`- ${evt}`);
|
|
835
|
-
lines.push('');
|
|
836
|
-
}
|
|
837
|
-
// Related ADRs — include FULL markdown content, not just title/decision
|
|
838
|
-
if (relatedAdrs.length > 0) {
|
|
839
|
-
lines.push(`## Architecture Decisions Governing This Context (${relatedAdrs.length} ADRs)`, '');
|
|
840
|
-
for (const adr of relatedAdrs) {
|
|
841
|
-
const fullMarkdown = getAdrMarkdown(adr);
|
|
842
|
-
if (fullMarkdown) {
|
|
843
|
-
lines.push(fullMarkdown, '');
|
|
844
|
-
}
|
|
845
|
-
else {
|
|
846
|
-
lines.push(`### ${adr.id}: ${adr.title}`, '');
|
|
847
|
-
if (adr.context)
|
|
848
|
-
lines.push(`**Context:** ${adr.context}`, '');
|
|
849
|
-
if (adr.decision)
|
|
850
|
-
lines.push(`**Decision:** ${adr.decision}`, '');
|
|
851
|
-
if (adr.consequences?.length) {
|
|
852
|
-
lines.push('**Consequences:**');
|
|
853
|
-
for (const c of adr.consequences)
|
|
854
|
-
lines.push(`- ${c}`);
|
|
855
|
-
lines.push('');
|
|
856
|
-
}
|
|
857
|
-
if (adr.alternatives?.length) {
|
|
858
|
-
lines.push('**Alternatives Considered:**');
|
|
859
|
-
for (const a of adr.alternatives)
|
|
860
|
-
lines.push(`- ${a}`);
|
|
861
|
-
lines.push('');
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
else {
|
|
867
|
-
// No keyword match — include cross-cutting ADRs (infra, security, deployment)
|
|
868
|
-
const crossCuttingAdrs = adrs.filter(a => {
|
|
869
|
-
const text = `${a.title} ${a.decision}`.toLowerCase();
|
|
870
|
-
return /security|auth|deploy|infra|database|logging|error.handling|api.design/i.test(text);
|
|
871
|
-
});
|
|
872
|
-
if (crossCuttingAdrs.length > 0) {
|
|
873
|
-
lines.push(`## Cross-Cutting Architecture Decisions (${crossCuttingAdrs.length} ADRs)`, '');
|
|
874
|
-
for (const adr of crossCuttingAdrs) {
|
|
875
|
-
const fullMarkdown = getAdrMarkdown(adr);
|
|
876
|
-
if (fullMarkdown) {
|
|
877
|
-
lines.push(fullMarkdown, '');
|
|
878
|
-
}
|
|
879
|
-
else {
|
|
880
|
-
lines.push(`### ${adr.id}: ${adr.title}`, '');
|
|
881
|
-
if (adr.decision)
|
|
882
|
-
lines.push(`**Decision:** ${adr.decision}`, '');
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
// SPARC architecture excerpt for first prompt
|
|
888
|
-
if (order === 1 && sparcArch) {
|
|
889
|
-
lines.push('## SPARC Architecture Reference', '', sparcArch.slice(0, 3000), '');
|
|
890
|
-
}
|
|
891
|
-
// Relevant glossary terms
|
|
892
|
-
const ctxKeywords = ctx.name.toLowerCase().split(/[-_\s]+/);
|
|
893
|
-
const relevantTerms = glossary.filter(g => ctxKeywords.some(k => k.length > 2 && (g.term?.toLowerCase().includes(k) || g.definition?.toLowerCase().includes(k))));
|
|
894
|
-
if (relevantTerms.length > 0) {
|
|
895
|
-
lines.push('## Ubiquitous Language', '');
|
|
896
|
-
for (const g of relevantTerms) {
|
|
897
|
-
lines.push(`- **${g.term}**: ${g.definition}`);
|
|
898
|
-
}
|
|
899
|
-
lines.push('');
|
|
900
|
-
}
|
|
901
|
-
// Implementation instructions specific to this context
|
|
902
|
-
lines.push('## Implementation Requirements', '', `- Implement ALL commands, queries, and domain events listed above for the ${ctx.name} context`, '- Create aggregate root classes with proper invariant enforcement', '- Define port interfaces (e.g., `${ctx.name}Port`) for external dependencies', '- Write adapter implementations for each port', '- Include London School TDD tests — mock at aggregate boundaries', '- Export public interfaces so downstream contexts can import them', '- Follow the technology stack and patterns specified in the ADRs above', '');
|
|
903
|
-
fs.writeFileSync(path.join(promptsDir, filename), lines.join('\n'), { mode: 0o600, encoding: 'utf-8' });
|
|
904
|
-
completedContexts.push(ctx.name);
|
|
816
|
+
}
|
|
817
|
+
// Project requirements — full on first prompt, abbreviated after
|
|
818
|
+
if (order === 1) {
|
|
819
|
+
lines.push('## Project Requirements', '', scenarioQuery, '');
|
|
905
820
|
}
|
|
906
821
|
else {
|
|
907
|
-
//
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
if (sparcSpec)
|
|
931
|
-
lines.push('## SPARC Specification', '', sparcSpec.slice(0, 4000), '');
|
|
932
|
-
if (sparcArch)
|
|
933
|
-
lines.push('## SPARC Architecture', '', sparcArch.slice(0, 3000), '');
|
|
934
|
-
}
|
|
935
|
-
else {
|
|
936
|
-
lines.push(`## Project Objective`, '', scenarioQuery.split('\n')[0]?.slice(0, 300) ?? '', '', '> See impl-001 for full project context and SPARC specification.', '');
|
|
937
|
-
}
|
|
938
|
-
// Full ADR content
|
|
939
|
-
lines.push('## Architecture Decision', '');
|
|
940
|
-
if (fullMarkdown) {
|
|
941
|
-
lines.push(fullMarkdown, '');
|
|
822
|
+
// Include enough context but not the entire prompt every time
|
|
823
|
+
const firstParagraph = scenarioQuery.split(/\n\n/)[0] ?? scenarioQuery.slice(0, 400);
|
|
824
|
+
lines.push('## Project Requirements (Summary)', '', firstParagraph, '', '> See impl-001 for full project requirements.', '');
|
|
825
|
+
}
|
|
826
|
+
// Phase-specific description
|
|
827
|
+
lines.push(`## What to Build`, '', phase.description, '');
|
|
828
|
+
// SPARC reference for this phase
|
|
829
|
+
const sparcMap = { spec: sparcSpec, arch: sparcArch, pseudo: sparcPseudocode, refine: sparcRefinement, none: '' };
|
|
830
|
+
const sparcContent = sparcMap[phase.includeSparc] ?? '';
|
|
831
|
+
if (sparcContent) {
|
|
832
|
+
const sparcLabel = { spec: 'SPARC Specification', arch: 'SPARC Architecture', pseudo: 'SPARC Pseudocode', refine: 'SPARC Refinement', none: '' }[phase.includeSparc] ?? 'SPARC';
|
|
833
|
+
lines.push(`## ${sparcLabel} Reference`, '', sparcContent, '');
|
|
834
|
+
}
|
|
835
|
+
// Relevant ADRs — match by keywords and include FULL markdown
|
|
836
|
+
const matchedAdrs = adrs.filter(adr => {
|
|
837
|
+
const adrText = `${adr.title} ${adr.context} ${adr.decision}`.toLowerCase();
|
|
838
|
+
return phase.adrKeywords.some(kw => adrText.includes(kw));
|
|
839
|
+
});
|
|
840
|
+
// Always include cross-cutting ADRs in foundation prompt
|
|
841
|
+
if (order === 1 && matchedAdrs.length < adrs.length) {
|
|
842
|
+
for (const adr of adrs) {
|
|
843
|
+
if (!matchedAdrs.includes(adr))
|
|
844
|
+
matchedAdrs.push(adr);
|
|
942
845
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
lines.push('**Consequences:**');
|
|
951
|
-
for (const c of adr.consequences)
|
|
952
|
-
lines.push(`- ${c}`);
|
|
953
|
-
lines.push('');
|
|
846
|
+
}
|
|
847
|
+
if (matchedAdrs.length > 0) {
|
|
848
|
+
lines.push(`## Relevant Architecture Decisions (${matchedAdrs.length} ADRs)`, '');
|
|
849
|
+
for (const adr of matchedAdrs) {
|
|
850
|
+
const fullMarkdown = getAdrMarkdown(adr);
|
|
851
|
+
if (fullMarkdown) {
|
|
852
|
+
lines.push(fullMarkdown, '', '---', '');
|
|
954
853
|
}
|
|
955
|
-
|
|
956
|
-
lines.push(
|
|
957
|
-
|
|
958
|
-
lines.push(
|
|
854
|
+
else {
|
|
855
|
+
lines.push(`### ${adr.id}: ${adr.title}`, '');
|
|
856
|
+
if (adr.context)
|
|
857
|
+
lines.push(`**Context:** ${adr.context}`, '');
|
|
858
|
+
if (adr.decision)
|
|
859
|
+
lines.push(`**Decision:** ${adr.decision}`, '');
|
|
860
|
+
if (adr.consequences?.length) {
|
|
861
|
+
lines.push('**Consequences:**');
|
|
862
|
+
for (const c of adr.consequences)
|
|
863
|
+
lines.push(`- ${c}`);
|
|
864
|
+
lines.push('');
|
|
865
|
+
}
|
|
959
866
|
lines.push('');
|
|
960
867
|
}
|
|
961
868
|
}
|
|
962
|
-
lines.push('## Implementation Requirements', '', '- Implement the decision described in the ADR above', '- Write clean, modular code following the technology stack specified', '- Include London School TDD tests — mock at boundaries', '- Export public interfaces for downstream consumers', '');
|
|
963
|
-
fs.writeFileSync(path.join(promptsDir, filename), lines.join('\n'), { mode: 0o600, encoding: 'utf-8' });
|
|
964
|
-
completedContexts.push(adr.title);
|
|
965
869
|
}
|
|
870
|
+
// DDD reference — included as context, not as driver
|
|
871
|
+
if (phase.includeDdd && dddContent) {
|
|
872
|
+
lines.push('## Domain Model Reference (DDD)', '', '> Use this as reference for domain concepts, entity relationships, and business rules.', '');
|
|
873
|
+
// Include a reasonable excerpt
|
|
874
|
+
lines.push(dddContent.slice(0, 6000), '');
|
|
875
|
+
}
|
|
876
|
+
// Implementation instructions
|
|
877
|
+
lines.push('## Implementation Instructions', '', '- All code must be CUSTOM to this project — no generic boilerplate or placeholder logic', '- Follow the technology stack decisions from the ADRs above', '- Write production-quality code with proper error handling', '- Include unit tests for business logic (London School TDD)', '- Export public interfaces so later build phases can import them', `- Place all files in the \`${phase.folder}/\` directory`, '');
|
|
878
|
+
fs.writeFileSync(path.join(promptsDir, filename), lines.join('\n'), { mode: 0o600, encoding: 'utf-8' });
|
|
879
|
+
completedPhases.push(`${order}. ${phase.title}`);
|
|
966
880
|
}
|
|
967
881
|
// Write execution plan
|
|
968
|
-
const planItems =
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
file: `impl-${String(i + 1).padStart(3, '0')}-${adr.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 50)}.md`,
|
|
979
|
-
title: adr.title,
|
|
980
|
-
upstreams: [],
|
|
981
|
-
adrs: [adr.id],
|
|
982
|
-
}));
|
|
882
|
+
const planItems = activeBuildPhases.map((phase, i) => ({
|
|
883
|
+
order: i + 1,
|
|
884
|
+
file: `impl-${String(i + 1).padStart(3, '0')}-${phase.slug}.md`,
|
|
885
|
+
title: phase.title,
|
|
886
|
+
folder: phase.folder,
|
|
887
|
+
adrs: adrs.filter(a => {
|
|
888
|
+
const t = `${a.title} ${a.context} ${a.decision}`.toLowerCase();
|
|
889
|
+
return phase.adrKeywords.some(kw => t.includes(kw));
|
|
890
|
+
}).map(a => a.id),
|
|
891
|
+
}));
|
|
983
892
|
fs.writeFileSync(path.join(promptsDir, 'execution-plan.json'), JSON.stringify({ totalSteps, prompts: planItems }, null, 2), { mode: 0o600, encoding: 'utf-8' });
|
|
984
|
-
console.error(` [PROMPTS] Wrote ${totalSteps} implementation prompts
|
|
893
|
+
console.error(` [PROMPTS] Wrote ${totalSteps} SPARC+ADR-driven implementation prompts (${adrs.length} ADRs, SPARC: ${sparcSpec ? 'yes' : 'no'}, DDD ref: ${dddContent ? 'yes' : 'no'})`);
|
|
985
894
|
}
|
|
986
895
|
copyPlanningArtifacts(runDir);
|
|
987
896
|
}
|