guardian-framework 0.1.42 → 0.1.44

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/cli.js CHANGED
@@ -1335,7 +1335,7 @@ __export(exports_package, {
1335
1335
  bin: () => bin,
1336
1336
  author: () => author
1337
1337
  });
1338
- var name = "guardian-framework", version = "0.1.42", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1338
+ var name = "guardian-framework", version = "0.1.44", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1339
1339
  var init_package = __esm(() => {
1340
1340
  exports = {
1341
1341
  ".": {
package/dist/exports.js CHANGED
@@ -995,7 +995,7 @@ __export(exports_package, {
995
995
  bin: () => bin,
996
996
  author: () => author
997
997
  });
998
- var name = "guardian-framework", version = "0.1.42", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
998
+ var name = "guardian-framework", version = "0.1.44", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
999
999
  var init_package = __esm(() => {
1000
1000
  exports = {
1001
1001
  ".": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardian-framework",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "Token-optimized agentic framework scaffolder with pi-first architecture",
5
5
  "type": "module",
6
6
  "main": "dist/exports.js",
@@ -6,6 +6,7 @@
6
6
  * Pi extension providing:
7
7
  * /domain --explore — Returns DDD analysis instructions + agent writes files directly
8
8
  * /domain --architect-scaffold — Generate architecture directories from exploration
9
+ * /domain --enrich — Enrich module stubs with full DDD content
9
10
  * /domain --validate — Validate exploration session structure
10
11
  * domain_explore tool — (deprecated, use /domain --explore instead)
11
12
  * domain_validate tool — Validate exploration sessions against glossary + source code
@@ -75,7 +76,7 @@ type ExtensionAPI = {
75
76
  toolCallId: string,
76
77
  params: Record<string, unknown>,
77
78
  signal: AbortSignal,
78
- onUpdate: (update: { content: Array<{ type: string; text: string }> }) => void,
79
+ onUpdate: (update: { type: string; message: string }) => void,
79
80
  ctx: ExtensionContext,
80
81
  ): unknown | Promise<unknown>;
81
82
  }): void;
@@ -190,132 +191,6 @@ function buildExplorationPrompt(context: string): string {
190
191
  ].join("\n");
191
192
  }
192
193
 
193
- function readLanguage(cwd: string): string {
194
- try {
195
- const manifestPath = path.join(cwd, "guardian-manifest.json");
196
- if (fs.existsSync(manifestPath)) {
197
- const raw = fs.readFileSync(manifestPath, "utf-8");
198
- const manifest = JSON.parse(raw) as { language?: string };
199
- if (manifest.language) return manifest.language;
200
- }
201
- } catch {}
202
- return "typescript";
203
- }
204
-
205
- function buildFrontendExplorationPrompt(context: string): string {
206
- return [
207
- "You are a frontend architecture expert. Analyze the following web application",
208
- "description and extract a structured model focused on user experience,",
209
- "UI concepts, and design principles. Respond with valid JSON only.",
210
- "",
211
- "## Business Context",
212
- "",
213
- context,
214
- "",
215
- "## Output Format (JSON)",
216
- "",
217
- "\`\`\`json",
218
- "{",
219
- ' "businessContext": "Brief one-line summary",',
220
- ' "actors": [',
221
- " {",
222
- ' "name": "UserRole",',
223
- ' "description": "Who this user is",',
224
- ' "interactions": "What they do in the application"',
225
- " }",
226
- " ],",
227
- ' "functionalRequirements": [',
228
- " {",
229
- ' "id": "FR-001",',
230
- ' "requirement": "The user shall be able to...",',
231
- ' "priority": "critical|high|medium|low",',
232
- ' "boundedContext": "FeatureName"',
233
- " }",
234
- " ],",
235
- ' "nonFunctionalRequirements": [',
236
- " {",
237
- ' "id": "NFR-001",',
238
- ' "requirement": "The application shall...",',
239
- ' "category": "performance|accessibility|usability|security|maintainability",',
240
- ' "target": "Specific measurable target"',
241
- " }",
242
- " ],",
243
- ' "assumptions": [',
244
- " {",
245
- ' "assumption": "We assume that...",',
246
- ' "impactIfWrong": "What breaks if this is false",',
247
- ' "mitigation": "How we handle it being wrong"',
248
- " }",
249
- " ],",
250
- ' "boundedContexts": [',
251
- " {",
252
- ' "name": "FeatureName",',
253
- ' "description": "Brief description of this app feature/section",',
254
- ' "entities": ["UIConcept1", "UIConcept2"]',
255
- " }",
256
- " ],",
257
- ' "entities": [',
258
- " {",
259
- ' "name": "UIConceptName",',
260
- ' "context": "FeatureName",',
261
- ' "type": "ui-concept | user-intent | design-token | app-shell | value-object",',
262
- ' "description": "What this UI concept represents"',
263
- " }",
264
- " ],",
265
- ' "userIntents": [',
266
- " {",
267
- ' "name": "UserIntentName",',
268
- ' "context": "FeatureName",',
269
- ' "description": "What the user is trying to do",',
270
- ' "triggeredBy": "What UI action triggers this intent"',
271
- " }",
272
- " ],",
273
- ' "designPrinciples": [',
274
- " {",
275
- ' "principle": "The application is...",',
276
- ' "description": "What this principle means in practice",',
277
- ' "rationale": "Why this principle exists"',
278
- " }",
279
- " ],",
280
- ' "navigationPhilosophy": {',
281
- ' "contextPreservation": "How the user never loses context",',
282
- ' "deepLinking": "How every page is deep-linkable",',
283
- ' "multiTab": "How multiple tabs are supported"',
284
- " },",
285
- ' "appShell": {',
286
- ' "navigation": "Navigation structure",',
287
- ' "header": "Header content",',
288
- ' "sidebar": "Sidebar content",',
289
- ' "commandPalette": "Command palette actions",',
290
- ' "globalSearch": "Global search behavior"',
291
- " },",
292
- ' "degradationStrategy": [',
293
- " {",
294
- ' "feature": "FeatureName",',
295
- ' "whenUnavailable": "What happens when this feature API is down",',
296
- ' "degradesTo": "What still works"',
297
- " }",
298
- " ],",
299
- ' "ubiquitousLanguage": [',
300
- " {",
301
- ' "term": "CanonicalTerm",',
302
- ' "definition": "Clear definition",',
303
- ' "boundedContext": "FeatureName",',
304
- ' "aliases": ["AlternativeName1"],',
305
- ' "examples": "Usage example"',
306
- " }",
307
- " ],",
308
- ' "openQuestions": "Any open questions about the application",',
309
- ' "designSystem": {',
310
- ' "componentLibrary": "Which component library or approach",',
311
- ' "theming": "How theming works",',
312
- ' "accessibility": "Accessibility requirements"',
313
- " }",
314
- "}",
315
- "\`\`\`",
316
- ].join("\n");
317
- }
318
-
319
194
  // ── Domain Explore Tool (deprecated) ──
320
195
 
321
196
  export default function (pi: ExtensionAPI) {
@@ -599,9 +474,7 @@ export default function (pi: ExtensionAPI) {
599
474
  return "(domain command handled)";
600
475
  }
601
476
  const sanitized = sanitizeContext(context);
602
- const lang = readLanguage(ctx.cwd);
603
- const isFrontend = lang === "nextjs" || lang === "angular";
604
- const prompt = isFrontend ? buildFrontendExplorationPrompt(sanitized) : buildExplorationPrompt(sanitized);
477
+ const prompt = buildExplorationPrompt(sanitized);
605
478
  const sessionId = crypto.randomUUID();
606
479
  const explorationDir = path.join(ctx.cwd, ".pi", "domain", "exploration");
607
480
  fs.mkdirSync(explorationDir, { recursive: true });
@@ -630,237 +503,99 @@ export default function (pi: ExtensionAPI) {
630
503
 
631
504
  // Write stub exploration.md with business context filled in
632
505
  const explorationMdPath = path.join(ctx.cwd, ".pi", "domain", "exploration.md");
633
- const stubContent = isFrontend
634
- ? [
635
- "---",
636
- "session_id: " + sessionId,
637
- "created: " + new Date().toISOString().split("T")[0],
638
- 'business_context: "' + sanitized.replace(/"/g, '\\"') + '"',
639
- "status: draft",
640
- "---",
641
- "",
642
- "# Domain Exploration: " + sessionId,
643
- "",
644
- "> **Status:** draft — agent needs to fill in the analysis below.",
645
- "",
646
- "---",
647
- "",
648
- "## Business Context",
649
- "",
650
- sanitized,
651
- "",
652
- "---",
653
- "",
654
- "## Actors & Roles",
655
- "",
656
- "| Actor | Description | Interactions |",
657
- "|-------|-------------|-------------|",
658
- "| | | |",
659
- "",
660
- "---",
661
- "",
662
- "## Functional Requirements",
663
- "",
664
- "| ID | Requirement | Priority | Feature |",
665
- "|----|-------------|----------|--------|",
666
- "| | | | |",
667
- "",
668
- "---",
669
- "",
670
- "## Non-Functional Requirements",
671
- "",
672
- "| ID | Requirement | Category | Target |",
673
- "|----|-------------|----------|--------|",
674
- "| | | | |",
675
- "",
676
- "---",
677
- "",
678
- "## Assumptions",
679
- "",
680
- "| Assumption | Impact if Wrong | Mitigation |",
681
- "|------------|----------------|-----------|",
682
- "| | | |",
683
- "",
684
- "---",
685
- "",
686
- "## Features (Bounded Contexts)",
687
- "",
688
- "| Feature | Description | UI Concepts |",
689
- "|---------|-------------|------------|",
690
- "| | | |",
691
- "",
692
- "---",
693
- "",
694
- "## UI Concepts",
695
- "",
696
- "| Concept | Feature | Type | Description |",
697
- "|---------|---------|------|-------------|",
698
- "| | | | |",
699
- "",
700
- "---",
701
- "",
702
- "## User Intents",
703
- "",
704
- "| Intent | Feature | Description | Triggered By |",
705
- "|--------|---------|-------------|-------------|",
706
- "| | | | |",
707
- "",
708
- "---",
709
- "",
710
- "## Design Principles",
711
- "",
712
- "| Principle | Description | Rationale |",
713
- "|-----------|-------------|----------|",
714
- "| | | |",
715
- "",
716
- "---",
717
- "",
718
- "## Navigation Philosophy",
719
- "",
720
- "| Aspect | Description |",
721
- "|--------|-------------|",
722
- "| Context Preservation | |",
723
- "| Deep Linking | |",
724
- "| Multi-Tab Support | |",
725
- "",
726
- "---",
727
- "",
728
- "## App Shell",
729
- "",
730
- "| Component | Description |",
731
- "|-----------|-------------|",
732
- "| Navigation | |",
733
- "| Header | |",
734
- "| Sidebar | |",
735
- "| Command Palette | |",
736
- "| Global Search | |",
737
- "| Status Bar | |",
738
- "",
739
- "---",
740
- "",
741
- "## Degradation Strategy",
742
- "",
743
- "| Feature | When Unavailable | Degrades To |",
744
- "|---------|-----------------|-------------|",
745
- "| | | |",
746
- "",
747
- "---",
748
- "",
749
- "## Ubiquitous Language",
750
- "",
751
- "| Term | Definition | Feature | Aliases/Synonyms |",
752
- "|------|-----------|---------|-----------------|",
753
- "| | | | |",
754
- "",
755
- "---",
756
- "",
757
- "## Design System",
758
- "",
759
- "| Aspect | Decision |",
760
- "|--------|----------|",
761
- "| Component Library | |",
762
- "| Theming | |",
763
- "| Accessibility | |",
764
- "",
765
- "---",
766
- "",
767
- "## Open Questions",
768
- "",
769
- "",
770
- ].join("\n")
771
- : [
772
- "---",
773
- "session_id: " + sessionId,
774
- "created: " + new Date().toISOString().split("T")[0],
775
- 'business_context: "' + sanitized.replace(/"/g, '\\"') + '"',
776
- "status: draft",
777
- "---",
778
- "",
779
- "# Domain Exploration: " + sessionId,
780
- "",
781
- "> **Status:** draft — agent needs to fill in the analysis below.",
782
- "",
783
- "---",
784
- "",
785
- "## Business Context",
786
- "",
787
- sanitized,
788
- "",
789
- "---",
790
- "",
791
- "## Actors & Roles",
792
- "",
793
- "| Actor | Description | Interactions |",
794
- "|-------|-------------|-------------|",
795
- "| | | |",
796
- "",
797
- "---",
798
- "",
799
- "## Functional Requirements",
800
- "",
801
- "| ID | Requirement | Priority | Bounded Context |",
802
- "|----|-------------|----------|----------------|",
803
- "| | | | |",
804
- "",
805
- "---",
806
- "",
807
- "## Non-Functional Requirements",
808
- "",
809
- "| ID | Requirement | Category | Target |",
810
- "|----|-------------|----------|--------|",
811
- "| | | | |",
812
- "",
813
- "---",
814
- "",
815
- "## Assumptions",
816
- "",
817
- "| Assumption | Impact if Wrong | Mitigation |",
818
- "|------------|----------------|-----------|",
819
- "| | | |",
820
- "",
821
- "---",
822
- "",
823
- "## Bounded Contexts",
824
- "",
825
- "| Context | Description | Entities |",
826
- "|---------|-------------|----------|",
827
- "| | | |",
828
- "",
829
- "---",
830
- "",
831
- "## Entities",
832
- "",
833
- "| Entity | Context | Type | Description |",
834
- "|--------|---------|------|-------------|",
835
- "| | | | |",
836
- "",
837
- "---",
838
- "",
839
- "## Domain Events",
840
- "",
841
- "| Event | Context | Description | Triggered By |",
842
- "|-------|---------|-------------|-------------|",
843
- "| | | | |",
844
- "",
845
- "---",
846
- "",
847
- "## Ubiquitous Language",
848
- "",
849
- "| Term | Definition | Bounded Context | Aliases/Synonyms |",
850
- "|------|-----------|----------------|-----------------|",
851
- "| | | | |",
852
- "",
853
- "---",
854
- "",
855
- "## Open Questions",
856
- "",
857
- "",
858
- "---",
859
- "",
860
- "## Aggregate Roots",
861
- "",
862
- "",
863
- ].join("\n");
506
+ const stubContent = [
507
+ "---",
508
+ "session_id: " + sessionId,
509
+ "created: " + new Date().toISOString().split("T")[0],
510
+ 'business_context: "' + sanitized.replace(/"/g, '\\"') + '"',
511
+ "status: draft",
512
+ "---",
513
+ "",
514
+ "# Domain Exploration: " + sessionId,
515
+ "",
516
+ "> **Status:** draft — agent needs to fill in the analysis below.",
517
+ "",
518
+ "---",
519
+ "",
520
+ "## Business Context",
521
+ "",
522
+ sanitized,
523
+ "",
524
+ "---",
525
+ "",
526
+ "## Actors & Roles",
527
+ "",
528
+ "| Actor | Description | Interactions |",
529
+ "|-------|-------------|-------------|",
530
+ "| | | |",
531
+ "",
532
+ "---",
533
+ "",
534
+ "## Functional Requirements",
535
+ "",
536
+ "| ID | Requirement | Priority | Bounded Context |",
537
+ "|----|-------------|----------|----------------|",
538
+ "| | | | |",
539
+ "",
540
+ "---",
541
+ "",
542
+ "## Non-Functional Requirements",
543
+ "",
544
+ "| ID | Requirement | Category | Target |",
545
+ "|----|-------------|----------|--------|",
546
+ "| | | | |",
547
+ "",
548
+ "---",
549
+ "",
550
+ "## Assumptions",
551
+ "",
552
+ "| Assumption | Impact if Wrong | Mitigation |",
553
+ "|------------|----------------|-----------|",
554
+ "| | | |",
555
+ "",
556
+ "---",
557
+ "",
558
+ "## Bounded Contexts",
559
+ "",
560
+ "| Context | Description | Entities |",
561
+ "|---------|-------------|----------|",
562
+ "| | | |",
563
+ "",
564
+ "---",
565
+ "",
566
+ "## Entities",
567
+ "",
568
+ "| Entity | Context | Type | Description |",
569
+ "|--------|---------|------|-------------|",
570
+ "| | | | |",
571
+ "",
572
+ "---",
573
+ "",
574
+ "## Domain Events",
575
+ "",
576
+ "| Event | Context | Description | Triggered By |",
577
+ "|-------|---------|-------------|-------------|",
578
+ "| | | | |",
579
+ "",
580
+ "---",
581
+ "",
582
+ "## Ubiquitous Language",
583
+ "",
584
+ "| Term | Definition | Bounded Context | Aliases/Synonyms |",
585
+ "|------|-----------|----------------|-----------------|",
586
+ "| | | | |",
587
+ "",
588
+ "---",
589
+ "",
590
+ "## Open Questions",
591
+ "",
592
+ "",
593
+ "---",
594
+ "",
595
+ "## Aggregate Roots",
596
+ "",
597
+ "",
598
+ ].join("\n");
864
599
  fs.writeFileSync(explorationMdPath + ".tmp", stubContent, "utf-8");
865
600
  fs.renameSync(explorationMdPath + ".tmp", explorationMdPath);
866
601
 
@@ -892,18 +627,12 @@ export default function (pi: ExtensionAPI) {
892
627
  // Using sendMessage with triggerTurn=true causes the agent to process
893
628
  // this as a new conversation turn, not as a command response.
894
629
  const analysisPrompt = [
895
- "I need you to analyze the following business domain.",
630
+ "I need you to analyze the following business domain using Domain-Driven Design.",
896
631
  "I have created stub files in .pi/domain/exploration.md and .pi/domain/ubiquitous-language.md.",
897
632
  "",
898
- "IMPORTANT: Read .pi/domain/exploration.md FIRST. It contains empty tables.",
899
- "FILL IN the existing tables exactly as structured. Do NOT change the section names or table columns.",
900
- "Do NOT add new sections that aren't in the stub. Do NOT use 'Domain Events' or 'Aggregate Roots' — those are backend concepts.",
901
- "",
902
633
  "Your task:",
903
634
  "1. READ .pi/domain/exploration.md — it has the business context and empty tables",
904
- (isFrontend
905
- ? "2. ANALYZE the domain: actors, FR/NFR, assumptions, features (bounded contexts), UI concepts, user intents, glossary"
906
- : "2. ANALYZE the domain: actors, FR/NFR, assumptions, bounded contexts, entities, events, glossary"),
635
+ "2. ANALYZE the domain: actors, FR/NFR, assumptions, bounded contexts, entities, events , glossary",
907
636
  "3. FILL IN all empty tables in .pi/domain/exploration.md with your analysis",
908
637
  "4. UPDATE .pi/domain/ubiquitous-language.md with the glossary terms",
909
638
  "",
@@ -911,40 +640,18 @@ export default function (pi: ExtensionAPI) {
911
640
  sanitized,
912
641
  "",
913
642
  "Use this JSON schema as a reference for structuring your analysis:",
914
- isFrontend
915
- ? [
916
- '\`\`\`json',
917
- "{",
918
- ' "actors": [{ "name": "", "description": "", "interactions": "" }],',
919
- ' "functionalRequirements": [{ "id": "FR-001", "requirement": "", "priority": "critical|high|medium|low", "boundedContext": "" }],',
920
- ' "nonFunctionalRequirements": [{ "id": "NFR-001", "requirement": "", "category": "performance|accessibility|usability|security|maintainability", "target": "" }],',
921
- ' "assumptions": [{ "assumption": "", "impactIfWrong": "", "mitigation": "" }],',
922
- ' "boundedContexts": [{ "name": "", "description": "", "entities": [""] }],',
923
- ' "entities": [{ "name": "", "context": "", "type": "ui-concept|user-intent|design-token|app-shell|value-object", "description": "" }],',
924
- ' "userIntents": [{ "name": "", "context": "", "description": "", "triggeredBy": "" }],',
925
- ' "designPrinciples": [{ "principle": "", "description": "", "rationale": "" }],',
926
- ' "navigationPhilosophy": { "contextPreservation": "", "deepLinking": "", "multiTab": "" },',
927
- ' "appShell": { "navigation": "", "header": "", "sidebar": "", "commandPalette": "", "globalSearch": "" },',
928
- ' "degradationStrategy": [{ "feature": "", "whenUnavailable": "", "degradesTo": "" }],',
929
- ' "ubiquitousLanguage": [{ "term": "", "definition": "", "boundedContext": "", "aliases": [""], "examples": "" }],',
930
- ' "designSystem": { "componentLibrary": "", "theming": "", "accessibility": "" }',
931
- "}",
932
- '\`\`\`',
933
- ].join("\n")
934
- : [
935
- '\`\`\`json',
936
- "{",
937
- ' "actors": [{ "name": "", "description": "", "interactions": "" }],',
938
- ' "functionalRequirements": [{ "id": "FR-001", "requirement": "", "priority": "critical|high|medium|low", "boundedContext": "" }],',
939
- ' "nonFunctionalRequirements": [{ "id": "NFR-001", "requirement": "", "category": "performance|security|scalability|availability|maintainability", "target": "" }],',
940
- ' "assumptions": [{ "assumption": "", "impactIfWrong": "", "mitigation": "" }],',
941
- ' "boundedContexts": [{ "name": "", "description": "", "entities": [""] }],',
942
- ' "entities": [{ "name": "", "context": "", "type": "entity|value-object|aggregate-root", "description": "" }],',
943
- ' "domainEvents": [{ "name": "", "context": "", "description": "", "triggeredBy": "" }],',
944
- ' "ubiquitousLanguage": [{ "term": "", "definition": "", "boundedContext": "", "aliases": [""], "examples": "" }]',
945
- "}",
946
- '\`\`\`',
947
- ].join("\n"),
643
+ '```json',
644
+ "{",
645
+ ' "actors": [{ "name": "", "description": "", "interactions": "" }],',
646
+ ' "functionalRequirements": [{ "id": "FR-001", "requirement": "", "priority": "critical|high|medium|low", "boundedContext": "" }],',
647
+ ' "nonFunctionalRequirements": [{ "id": "NFR-001", "requirement": "", "category": "performance|security|scalability|availability|maintainability", "target": "" }],',
648
+ ' "assumptions": [{ "assumption": "", "impactIfWrong": "", "mitigation": "" }],',
649
+ ' "boundedContexts": [{ "name": "", "description": "", "entities": [""] }],',
650
+ ' "entities": [{ "name": "", "context": "", "type": "entity|value-object|aggregate-root", "description": "" }],',
651
+ ' "domainEvents": [{ "name": "", "context": "", "description": "", "triggeredBy": "" }],',
652
+ ' "ubiquitousLanguage": [{ "term": "", "definition": "", "boundedContext": "", "aliases": [""], "examples": "" }]',
653
+ "}",
654
+ '```',
948
655
  ].join("\n");
949
656
 
950
657
  try {
@@ -1017,6 +724,15 @@ export default function (pi: ExtensionAPI) {
1017
724
  }
1018
725
 
1019
726
  // Parse bounded context names from (now synced) session content
727
+ // Strip markdown formatting (**bold**, *italic*, `code`) from a string
728
+ function stripMarkdown(text: string): string {
729
+ return text
730
+ .replace(/\*\*(.+?)\*\*/g, "$1")
731
+ .replace(/\*(.+?)\*/g, "$1")
732
+ .replace(/`(.+?)`/g, "$1")
733
+ .trim();
734
+ }
735
+
1020
736
  const bcNames: string[] = [];
1021
737
  const sourceForBC = analysisContent || sessionContent;
1022
738
  const bcSection = sourceForBC.match(/## Bounded Contexts[\s\S]*?(?=\n## |$)/);
@@ -1028,7 +744,7 @@ export default function (pi: ExtensionAPI) {
1028
744
  if (!inData || !line.startsWith("|")) continue;
1029
745
  const cells = line.split("|").map(c => c.trim()).filter(c => c);
1030
746
  if (cells.length >= 1 && cells[0] !== "Context" && cells[0] !== "Bounded Context") {
1031
- bcNames.push(cells[0]);
747
+ bcNames.push(stripMarkdown(cells[0]));
1032
748
  }
1033
749
  }
1034
750
  }
@@ -1202,27 +918,151 @@ export default function (pi: ExtensionAPI) {
1202
918
  }
1203
919
 
1204
920
  resultLines.push("", "### Next Steps");
1205
- resultLines.push("1. Review the module docs in .pi/architecture/modules/");
1206
- resultLines.push("2. Review ADR-001 in .pi/architecture/decisions/");
1207
- resultLines.push("3. Review the system diagram in .pi/architecture/diagrams/");
1208
- resultLines.push("4. Use /epic-plan --overview or /architect to plan implementation");
921
+ resultLines.push("1. Review ADR-001 in .pi/architecture/decisions/");
922
+ resultLines.push("2. Review the system diagram in .pi/architecture/diagrams/");
923
+ resultLines.push("3. Use /epic-plan --overview or /architect to plan implementation");
1209
924
  resultLines.push("");
1210
- resultLines.push("Or run through the full delivery pipeline:");
1211
- resultLines.push(" 1. /domain --validate " + sessionId + " (validate exploration)");
1212
- resultLines.push(" 2. (architecture scaffold just completed)");
1213
- resultLines.push(" 3. guardian project create --lang <lang> (Epic 0 - greenfield only)");
1214
- resultLines.push(" 4. /epic-plan --module <module> (plan each module)");
925
+ resultLines.push("To enrich stubs with full DDD content: /domain --enrich " + sessionId);
926
+
927
+ ctx.ui.notify("Architecture scaffold complete", "success");
928
+ return resultLines.join("\n");
929
+ }
930
+ if (trimmed.startsWith("--enrich")) {
931
+ const sessionId = trimmed.slice("--enrich".length).trim();
932
+ if (!sessionId) {
933
+ ctx.ui.notify("Usage: /domain --enrich <session-id>", "error");
934
+ return "(domain command handled)";
935
+ }
936
+
937
+ const explorationDir = path.join(ctx.cwd, ".pi", "domain", "exploration");
938
+ const sessionPath = path.join(explorationDir, sessionId + ".md");
939
+ const modulesDir = path.join(ctx.cwd, ".pi", "architecture", "modules");
940
+
941
+ if (!fs.existsSync(sessionPath)) {
942
+ ctx.ui.notify("Session not found: " + sessionId + ". Run /domain --explore first.", "error");
943
+ return "(domain command handled)";
944
+ }
945
+
946
+ const moduleFiles = fs.readdirSync(modulesDir).filter(f => f.endsWith(".md") && f !== "module-template.md");
947
+ if (moduleFiles.length === 0) {
948
+ ctx.ui.notify("No module docs found. Run /domain --architect-scaffold " + sessionId + " first.", "error");
949
+ return "(domain command handled)";
950
+ }
951
+
952
+ ctx.ui.notify("Enriching " + moduleFiles.length + " module docs from session " + sessionId, "info");
953
+ const lang = readLanguage(ctx.cwd);
954
+
955
+ const enrichPrompt = [
956
+ "## Task: Complete Architecture Package",
957
+ "",
958
+ "The scaffold generated basic stubs. Your task is to produce a **complete, interconnected architecture package**",
959
+ "that an implementation agent can build from.",
960
+ "",
961
+ "**YOU MUST FOLLOW THESE 3 STEPS IN ORDER. Do not skip steps or reorder them.**",
962
+ "",
963
+ "### Source Data",
964
+ "",
965
+ "- Domain exploration: `.pi/domain/exploration/" + sessionId + ".md`",
966
+ "- Ubiquitous Language: `.pi/domain/ubiquitous-language.md`",
967
+ "- Current ADR-001: `.pi/architecture/decisions/ADR-001-architecture-pattern.md`",
968
+ "- System diagram: `.pi/architecture/diagrams/system-context.md`",
969
+ "- Module stubs: `.pi/architecture/modules/` (" + moduleFiles.length + " files)",
970
+ "",
971
+ "### STEP 1: Generate All ADRs",
972
+ "",
973
+ "**Do this first, before touching any module docs.** Module enrichment needs ADR references.",
974
+ "",
975
+ "Create these ADR files in `.pi/architecture/decisions/`:",
976
+ "",
977
+ "- ADR-001: Architecture Pattern (DDD Modular Monolith) — review and update if needed",
978
+ "- ADR-002: Data Storage Strategy (Postgres + SQLx per context)",
979
+ "- ADR-003: Cross-Context Communication (Domain Events)",
980
+ "- ADR-004: API Design (REST + JSON, versioning strategy)",
981
+ "- ADR-005: Authentication & Authorization (API Keys + Scopes)",
982
+ "- ADR-006: Cost Tracking & Usage Metering",
983
+ "- ADR-007: Compliance Engine Architecture",
984
+ "",
985
+ "Each ADR file must follow the format: **Status, Date, Context, Decision, Consequences, Alternatives**",
986
+ "Stop after generating ALL ADR files before proceeding.",
987
+ "",
988
+ "### STEP 2: Generate Diagrams",
989
+ "",
990
+ "**After all ADRs are created, generate diagrams.**",
991
+ "",
992
+ "#### System-Level (in `.pi/architecture/diagrams/`)",
993
+ "",
994
+ "1. Update `system-context.md` with clean names",
995
+ "2. Create `event-flow.md` — Mermaid flowchart showing domain events between all bounded contexts",
996
+ "",
997
+ "#### Module-Level (embedded in each module doc)",
998
+ "",
999
+ "In EACH module doc under `## Diagrams`, add these 4 mermaid diagrams:",
1000
+ "",
1001
+ "1. **Data Flow** — flowchart: inputs → processing → outputs → storage",
1002
+ "2. **Entity Relationship** — classDiagram: aggregates, entities, VOs, fields, relationships",
1003
+ "3. **Aggregate State** — stateDiagram-v2: states and transitions for each aggregate root",
1004
+ "4. **Key Use Case Sequence** — sequenceDiagram: Actor → Interface → App → Domain → Infra",
1005
+ "",
1006
+ "Stop after creating diagrams before proceeding.",
1007
+ "",
1008
+ "### STEP 3: Enrich Each Module Doc",
1009
+ "",
1010
+ "**After ADRs and diagrams are done, enhance each module doc.**",
1011
+ "",
1012
+ "For each file in `.pi/architecture/modules/*.md`, add:",
1013
+ "",
1014
+ "1. **## Related ADRs** — Links to ADR files with descriptions of relevance",
1015
+ "2. **## Diagrams** — Embed the 4 mermaid diagrams from Step 2",
1016
+ "3. **## Components** — Expand each aggregate with " + lang + " stubs, methods, invariants keep `status:` and `depends:` markers",
1017
+ "4. **Domain Events** — Table: Event, Description, Trigger, Payload, Published By",
1018
+ "5. **API Endpoints** — Table: Method, Path, Handler, Input, Output, Auth",
1019
+ "6. **Ubiquitous Language** — Terms for this context from `.pi/domain/ubiquitous-language.md`",
1020
+ "7. **Dependencies** — Depends On + Used By",
1021
+ "8. **Implementation Sequence** — Ordered build list",
1022
+ "",
1023
+ "### STEP 4: Generate Implementation Roadmap",
1024
+ "",
1025
+ "**After all module docs are enriched, generate the implementation roadmap.**",
1026
+ "",
1027
+ "Read each module doc's dependency section and create `.pi/architecture/implementation-roadmap.md`",
1028
+ "with `## Phase N: Name (Days N-N)` sections, each having:",
1029
+ "- Goal, Modules table, Dependencies, Database Migrations, Acceptance Criteria",
1030
+ "",
1031
+ "Organize phases by dependency chain:",
1032
+ "- Phase 0: Foundation (no upstream deps)",
1033
+ "- Phase 1: Core services depending on Phase 0",
1034
+ "- Phase 2+: Following the dependency chain",
1035
+ "",
1036
+ "Also add: Dependency Graph, Effort Estimates table, Key Milestones",
1037
+ "",
1038
+ "### STEP 5: Fill Architecture CHANGELOG",
1039
+ "",
1040
+ "Read `.pi/architecture/CHANGELOG.md` and add an entry for each enriched module.",
1041
+ "Each entry should note: Module, what was defined (aggregates, events, endpoints),",
1042
+ "and update the Sync Status table at the bottom.",
1043
+ "",
1044
+ "### Scope Rules",
1045
+ "",
1046
+ "- CREATE new ADRs in `.pi/architecture/decisions/`",
1047
+ "- CREATE new diagram md files in `.pi/architecture/diagrams/`",
1048
+ "- CREATE `.pi/architecture/implementation-roadmap.md` with phased plan",
1049
+ "- EDIT `.pi/architecture/CHANGELOG.md` — add entries for each module",
1050
+ "- EDIT existing module docs in `.pi/architecture/modules/`",
1051
+ "- Do NOT create any source code files",
1052
+ "- Use " + lang + " syntax for code stubs",
1053
+ "- Use Mermaid for all diagrams",
1054
+ ].join("\n");
1215
1055
 
1216
- // Send the results as a follow-up message so the agent sees them
1217
1056
  try {
1218
1057
  pi.sendMessage(
1219
- { content: resultLines.join("\n"), display: true },
1058
+ { content: enrichPrompt, display: true },
1220
1059
  { deliverAs: "followUp", triggerTurn: true },
1221
1060
  );
1222
1061
  } catch (e) {
1223
- return resultLines.join("\n");
1062
+ return enrichPrompt;
1224
1063
  }
1225
- return "Architecture scaffold dispatched. Session: " + sessionId;
1064
+ ctx.ui.notify("Enrich task dispatched to agent for " + moduleFiles.length + " modules", "success");
1065
+ return "Enrich task dispatched. Session: " + sessionId;
1226
1066
  }
1227
1067
  if (trimmed.startsWith("--validate")) {
1228
1068
  const sessionId = trimmed.slice("--validate".length).trim();
@@ -1262,6 +1102,7 @@ export default function (pi: ExtensionAPI) {
1262
1102
  "Usage:",
1263
1103
  ' /domain --explore "Business context description"',
1264
1104
  " /domain --architect-scaffold <session-id>",
1105
+ " /domain --enrich <session-id>",
1265
1106
  " /domain --validate <session-id>",
1266
1107
  ].join("\n"),
1267
1108
  "info",
@@ -1276,8 +1117,11 @@ export default function (pi: ExtensionAPI) {
1276
1117
  " /domain --architect-scaffold <session-id>",
1277
1118
  " Generate architecture directories from exploration",
1278
1119
  "",
1120
+ " /domain --enrich <session-id>",
1121
+ " Enrich module stubs with full DDD architecture content",
1122
+ "",
1279
1123
  " /domain --validate <session-id>",
1280
- " Validate exploration session structure",
1124
+ " Validate exploration session structure",}]}
1281
1125
  ].join("\n");
1282
1126
  },
1283
1127
  });
@@ -404,6 +404,7 @@ class PipelineManager {
404
404
  this.state.status = "done";
405
405
  this.state.currentItemIndex = this.state.items.length;
406
406
  this.state.currentStepIndex = 0;
407
+ this.syncRoadmapState();
407
408
  changed = true;
408
409
  }
409
410
 
@@ -608,16 +609,8 @@ class PipelineManager {
608
609
  advanceStep(): void {
609
610
  if (!this.state) return;
610
611
 
611
- // Before advancing, verify the current step's work actually happened
612
+ // Auto-run acceptance gates for validate steps
612
613
  if (this.state.currentStepIndex < this.state.steps.length) {
613
- const { verified, reason } = this.verifyCurrentStep();
614
- if (!verified) {
615
- // Reality disagrees with state — reconcile from git and refuse to advance
616
- this.reconcile();
617
- return; // don't advance, state was wrong
618
- }
619
-
620
- // Auto-run acceptance gates for validate steps
621
614
  const step = this.state.steps[this.state.currentStepIndex];
622
615
  if (step.name === "validate" && step.acceptance.type !== "none") {
623
616
  const { allPassed, errors } = this.runAcceptanceGates(step);
@@ -661,12 +654,54 @@ class PipelineManager {
661
654
 
662
655
  if (this.state.currentItemIndex >= this.state.items.length) {
663
656
  this.state.status = "done";
657
+ this.syncRoadmapState();
664
658
  }
665
659
  }
666
660
 
667
661
  savePipelineState(this.cwd, this.state);
668
662
  }
669
663
 
664
+ /**
665
+ * When pipeline completes, sync the roadmap state file to reflect done phases.
666
+ */
667
+ private syncRoadmapState(): void {
668
+ try {
669
+ const roadmapPath = join(this.cwd, ".pi", ".guardian-roadmap-state.json");
670
+ if (!existsSync(roadmapPath)) return;
671
+ const raw = readFileSync(roadmapPath, "utf-8");
672
+ const roadmap = JSON.parse(raw) as { phases?: { index: number; status: string }[] };
673
+ if (!roadmap.phases) return;
674
+ for (const phase of roadmap.phases) {
675
+ const phaseModules = this.state!.items.filter((item) =>
676
+ item.toLowerCase().includes(`phase${phase.index}`) ||
677
+ this.isItemInPhase(item, phase.index)
678
+ );
679
+ const allDone = phaseModules.every((item) => {
680
+ const r = this.state!.results.find((res) => res.item === item);
681
+ return r && r.status === "done";
682
+ });
683
+ if (allDone && phaseModules.length > 0) {
684
+ phase.status = "done";
685
+ }
686
+ }
687
+ writeFileSync(roadmapPath, JSON.stringify(roadmap, null, 2));
688
+ } catch { /* roadmap file may not exist */ }
689
+ }
690
+
691
+ private isItemInPhase(item: string, phaseIndex: number): boolean {
692
+ try {
693
+ const roadmapPath = join(this.cwd, ".pi", "architecture", "implementation-roadmap.md");
694
+ if (!existsSync(roadmapPath)) return false;
695
+ const content = readFileSync(roadmapPath, "utf-8");
696
+ // Check if item appears under the phase section
697
+ const phaseSection = content.match(
698
+ new RegExp(`## Phase ${phaseIndex}:.*?\\n(?:.|\\n)*?(?=\\n## Phase|$)`),
699
+ );
700
+ if (!phaseSection) return false;
701
+ return phaseSection[0].includes(item);
702
+ } catch { return false; }
703
+ }
704
+
670
705
  /**
671
706
  * Run acceptance gates for a step and return pass/fail.
672
707
  */
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-07-04T06:14:58Z",
2
+ "timestamp": "2026-07-04T06:43:47Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {