guardian-framework 0.1.104 → 0.1.109
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/README.md +11 -2
- package/dist/cli.js +232 -16
- package/dist/exports.js +232 -16
- package/package.json +1 -1
- package/templates/languages/rust-patterns.md +5 -2
- package/templates/pi/context/checklists.md +15 -1
- package/templates/pi/domain/exploration.md +9 -0
- package/templates/pi/domain/ubiquitous-language.md +12 -0
- package/templates/pi/extensions/architect-lib/generators.ts +163 -12
- package/templates/pi/extensions/architect-lib/helpers.ts +49 -0
- package/templates/pi/extensions/architect-lib/tdd-generator.ts +1 -1
- package/templates/pi/extensions/architect-lib/types.ts +44 -2
- package/templates/pi/extensions/architect.ts +105 -41
- package/templates/pi/extensions/ask-user-question.ts +2 -2
- package/templates/pi/extensions/bash-guard.ts +2 -2
- package/templates/pi/extensions/config-reload.ts +12 -5
- package/templates/pi/extensions/coordinator.ts +2 -2
- package/templates/pi/extensions/curator.ts +1 -1
- package/templates/pi/extensions/domain-explorer.ts +50 -3
- package/templates/pi/extensions/filechanges.ts +2 -2
- package/templates/pi/extensions/goal-loop.ts +3 -3
- package/templates/pi/extensions/hooks.ts +1 -1
- package/templates/pi/extensions/pi-env.d.ts +96 -0
- package/templates/pi/extensions/pipeline.ts +1 -1
- package/templates/pi/extensions/project-scaffolder.ts +1 -1
- package/templates/pi/extensions/read-only-mode.ts +5 -1
- package/templates/pi/extensions/tsconfig.json +9 -2
- package/templates/pi/preflight_report.json +1 -1
- package/templates/pi/prompts/ci-blueprint.md +2 -2
- package/templates/pi/scripts/check_model_judgment.sh +28 -0
- package/templates/pi/scripts/ci/check_judgment_contracts.sh +93 -0
- package/templates/pi/scripts/ci/run_preflight.sh +3 -3
- package/templates/pi/scripts/ci/run_stage.sh +1 -1
- package/templates/pi/scripts/ci/stage_lint.sh +1 -1
- package/templates/pi/scripts/coverage.sh +58 -0
- package/templates/pi/scripts/install_coverage_tools.sh +43 -0
- package/templates/pi/scripts/languages/go/check_model_judgment.sh +70 -0
- package/templates/pi/scripts/languages/go/check_runtime_reachability.sh +34 -0
- package/templates/pi/scripts/languages/go/coverage.sh +78 -0
- package/templates/pi/scripts/languages/go/install_coverage_tools.sh +17 -0
- package/templates/pi/scripts/languages/java/check_model_judgment.sh +142 -0
- package/templates/pi/scripts/languages/java/check_runtime_reachability.sh +31 -0
- package/templates/pi/scripts/languages/java/coverage.sh +103 -0
- package/templates/pi/scripts/languages/java/install_coverage_tools.sh +40 -0
- package/templates/pi/scripts/languages/java/validate-architecture.sh +20 -0
- package/templates/pi/scripts/languages/python/check_model_judgment.sh +67 -0
- package/templates/pi/scripts/languages/python/check_runtime_reachability.sh +34 -0
- package/templates/pi/scripts/languages/python/coverage.sh +88 -0
- package/templates/pi/scripts/languages/python/install_coverage_tools.sh +22 -0
- package/templates/pi/scripts/languages/rust/check_model_judgment.sh +61 -0
- package/templates/pi/scripts/languages/rust/check_runtime_reachability.sh +40 -0
- package/templates/pi/scripts/languages/rust/coverage.sh +79 -0
- package/templates/pi/scripts/languages/rust/install_coverage_tools.sh +20 -0
- package/templates/pi/scripts/languages/rust/validate-tests.sh +9 -6
- package/templates/pi/scripts/languages/typescript/check_model_judgment.sh +81 -0
- package/templates/pi/scripts/languages/typescript/check_runtime_reachability.sh +41 -0
- package/templates/pi/scripts/languages/typescript/coverage.sh +154 -0
- package/templates/pi/scripts/languages/typescript/install_coverage_tools.sh +41 -0
- package/templates/pi/scripts/languages/typescript/validate-canonical.sh +6 -2
- package/templates/pi/scripts/languages/typescript/validate-ci.sh +2 -2
- package/templates/pi/scripts/validate-architecture-readiness.sh +29 -0
- package/templates/pi/scripts/validate-exploration-depth.sh +112 -0
- package/templates/pi/scripts/validate-runtime-wiring.sh +35 -0
- package/templates/pi/skills/agents/architecture-validator.md +28 -0
- package/templates/pi/skills/agents/test-validator.md +1 -1
- package/templates/pi/skills/go-enterprise-codegen.md +46 -0
- package/templates/pi/skills/java-spring-enterprise-codegen.md +50 -0
- package/templates/pi/skills/python-enterprise-codegen.md +46 -0
- package/templates/pi/skills/rust-enterprise-codegen.md +46 -0
- package/templates/pi/skills/tdd-practice.md +17 -9
- package/templates/pi/skills/typescript-enterprise-codegen.md +46 -0
|
@@ -122,10 +122,10 @@ function buildInScope(comp: ModuleComponent, primaryAcRows: AcRow[], implSteps:
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/** Supported project languages. */
|
|
125
|
-
type ProjectLanguage = "typescript" | "java" | "python" | "go" | "rust";
|
|
125
|
+
export type ProjectLanguage = "typescript" | "java" | "python" | "go" | "rust";
|
|
126
126
|
|
|
127
127
|
/** Detect project language at `cwd` by checking for build files. */
|
|
128
|
-
function detectLanguage(cwd?: string): ProjectLanguage {
|
|
128
|
+
export function detectLanguage(cwd?: string): ProjectLanguage {
|
|
129
129
|
if (!cwd) return "typescript";
|
|
130
130
|
try {
|
|
131
131
|
if (existsSync(join(cwd, "pom.xml")) || existsSync(join(cwd, "build.gradle")) || existsSync(join(cwd, "build.gradle.kts")))
|
|
@@ -143,7 +143,7 @@ function detectLanguage(cwd?: string): ProjectLanguage {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/** Language-specific file extension for implementation files. */
|
|
146
|
-
function implExtension(lang: ProjectLanguage): string {
|
|
146
|
+
export function implExtension(lang: ProjectLanguage): string {
|
|
147
147
|
switch (lang) {
|
|
148
148
|
case "java": return "java";
|
|
149
149
|
case "python": return "py";
|
|
@@ -154,7 +154,7 @@ function implExtension(lang: ProjectLanguage): string {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/** Language-specific test directory base. */
|
|
157
|
-
function testBaseDirFromLang(lang: ProjectLanguage): string {
|
|
157
|
+
export function testBaseDirFromLang(lang: ProjectLanguage): string {
|
|
158
158
|
switch (lang) {
|
|
159
159
|
case "java": return "src/test/java";
|
|
160
160
|
case "python": return "tests";
|
|
@@ -165,7 +165,7 @@ function testBaseDirFromLang(lang: ProjectLanguage): string {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/** Language-specific test runner command hint. */
|
|
168
|
-
function testRunnerHintFromLang(lang: ProjectLanguage): string {
|
|
168
|
+
export function testRunnerHintFromLang(lang: ProjectLanguage): string {
|
|
169
169
|
switch (lang) {
|
|
170
170
|
case "java": return "mvn test";
|
|
171
171
|
case "python": return "pytest";
|
|
@@ -197,6 +197,26 @@ export function generateIssueMarkdown(
|
|
|
197
197
|
const title = buildIssueTitle(comp, moduleId);
|
|
198
198
|
const inScope = buildInScope(comp, compAcs, implSteps, moduleId);
|
|
199
199
|
|
|
200
|
+
// ADR-008: append compact modeling directives for aggregate/root components.
|
|
201
|
+
const isTactical = comp.modelingDepth === "tactical" || comp.aggregateRoot;
|
|
202
|
+
if (isTactical && (comp.invariants?.length || comp.events)) {
|
|
203
|
+
if (comp.invariants?.length) {
|
|
204
|
+
inScope.push("Honor the frozen aggregate invariants: " + comp.invariants.join("; "));
|
|
205
|
+
}
|
|
206
|
+
if (comp.events) {
|
|
207
|
+
const ev = [
|
|
208
|
+
...(comp.events.publishes?.length ? ["publishes " + comp.events.publishes.join(", ")] : []),
|
|
209
|
+
...(comp.events.subscribes?.length ? ["subscribes " + comp.events.subscribes.join(", ")] : []),
|
|
210
|
+
].join(", ");
|
|
211
|
+
if (ev) inScope.push("Domain events: " + ev);
|
|
212
|
+
}
|
|
213
|
+
if (comp.aggregateRoot) {
|
|
214
|
+
inScope.push(
|
|
215
|
+
"Implement " + comp.name + " as the aggregate root — no setters; state changes via behavior methods; repository interface owned by the domain layer",
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
200
220
|
// Language-aware test paths
|
|
201
221
|
const lang = detectLanguage(cwd);
|
|
202
222
|
const ext = implExtension(lang);
|
|
@@ -373,6 +393,30 @@ export function generateContractFreezeMarkdown(
|
|
|
373
393
|
const implSteps = parseImplSequence(doc);
|
|
374
394
|
const allAcs = parseAcTable(doc);
|
|
375
395
|
|
|
396
|
+
// ADR-008 modeling contract for components carrying depth metadata.
|
|
397
|
+
const modelingParts = slice.nextLogicalSlice
|
|
398
|
+
.filter((c: ModuleComponent) => c.modelingDepth === "tactical" || c.aggregateRoot || c.invariants?.length || c.events)
|
|
399
|
+
.map((c: ModuleComponent) => {
|
|
400
|
+
const lines: string[] = [`### ${c.name}`];
|
|
401
|
+
if (c.aggregateRoot) {
|
|
402
|
+
lines.push("- Aggregate root — all state changes flow through behavior methods (no setters)");
|
|
403
|
+
lines.push("- Repository interface is owned by the domain layer (interface-ownership, ADR-008)");
|
|
404
|
+
lines.push("- One aggregate per transaction; reference other aggregates by identity");
|
|
405
|
+
}
|
|
406
|
+
if (c.invariants?.length) {
|
|
407
|
+
lines.push("- Frozen invariants (become pre-generated failing tests):");
|
|
408
|
+
for (const inv of c.invariants) lines.push(` - ${inv}`);
|
|
409
|
+
}
|
|
410
|
+
if (c.events) {
|
|
411
|
+
if (c.events.publishes?.length) lines.push("- Publishes: " + c.events.publishes.join(", "));
|
|
412
|
+
if (c.events.subscribes?.length) lines.push("- Subscribes: " + c.events.subscribes.join(", "));
|
|
413
|
+
}
|
|
414
|
+
return lines.join("\n");
|
|
415
|
+
});
|
|
416
|
+
const modelingContract = modelingParts.length > 0
|
|
417
|
+
? "## Modeling Contract (ADR-008)\n\n" + modelingParts.join("\n\n")
|
|
418
|
+
: "";
|
|
419
|
+
|
|
376
420
|
return `---
|
|
377
421
|
guardian_issue:
|
|
378
422
|
id: "ISSUE-CONTRACT-FREEZE"
|
|
@@ -481,6 +525,8 @@ ${implSteps.length > 0
|
|
|
481
525
|
? `## Full Implementation Sequence (for reference)\n\n${implSteps.map((s) => '- ' + s).join("\n")}`
|
|
482
526
|
: ""}
|
|
483
527
|
|
|
528
|
+
${modelingContract}
|
|
529
|
+
|
|
484
530
|
## Implementation
|
|
485
531
|
|
|
486
532
|
> **Agent:** Create interface-only files. No implementation. Use Clean Architecture layers:
|
|
@@ -552,7 +598,6 @@ guardian_issue:
|
|
|
552
598
|
|
|
553
599
|
file_changes:
|
|
554
600
|
- "create: .pi/scripts/ci/check_${moduleId}_contracts.sh"
|
|
555
|
-
- "create: .pi/scripts/ci/check_${moduleId}_coverage.sh"
|
|
556
601
|
- "modify: .pi/scripts/ci/run_hardening_stages.sh"
|
|
557
602
|
---
|
|
558
603
|
|
|
@@ -572,10 +617,15 @@ automatic — no human review needed for routine checks.
|
|
|
572
617
|
- Verifies all interface methods are implemented
|
|
573
618
|
- Reports violations with file:line references
|
|
574
619
|
|
|
575
|
-
### Coverage Threshold Check
|
|
576
|
-
-
|
|
577
|
-
|
|
578
|
-
|
|
620
|
+
### Coverage Threshold Check (real project coverage)
|
|
621
|
+
- Coverage is enforced with the PROJECT'S REAL coverage tooling and gate
|
|
622
|
+
(e.g. \`cargo llvm-cov\` via a \`.pi/scripts/coverage.sh --gate\`, \`pytest
|
|
623
|
+
--cov\`, or \`c8\`/\`nyc\` for TS — whatever the project's CI coverage job
|
|
624
|
+
uses); assert the aggregate threshold the project actually enforces
|
|
625
|
+
- Do NOT create a per-module \`*_coverage.sh\` script — grep-based module
|
|
626
|
+
coverage scripts are coverage-theater (count test functions, never a
|
|
627
|
+
percentage); the real coverage tool's artifact (lcov/cobertura) provides
|
|
628
|
+
the per-file breakdown instead
|
|
579
629
|
|
|
580
630
|
### CI Integration
|
|
581
631
|
Each check becomes a CI stage in the hardening pipeline — it runs automatically
|
|
@@ -586,7 +636,6 @@ on every PR. No LLM cost. No human review. Just pass or fail.
|
|
|
586
636
|
| Script | Purpose | Location |
|
|
587
637
|
|--------|---------|----------|
|
|
588
638
|
| check_${moduleId}_contracts.sh | Validate contract implementation | .pi/scripts/ci/ |
|
|
589
|
-
| check_${moduleId}_coverage.sh | Enforce coverage thresholds | .pi/scripts/ci/ |
|
|
590
639
|
| stage_${moduleId}_proofing.sh | CI stage wrapper | .pi/scripts/ci/ |
|
|
591
640
|
|
|
592
641
|
## CI Pipeline Update
|
|
@@ -604,7 +653,7 @@ run_stage "11" "${moduleId}_proofing" \\
|
|
|
604
653
|
| # | Criterion | Script |
|
|
605
654
|
|---|-----------|--------|
|
|
606
655
|
| 1 | All interfaces have implementations | check_contracts.sh |
|
|
607
|
-
| 2 | Coverage
|
|
656
|
+
| 2 | Coverage meets the project's real coverage gate (project coverage tool + threshold in CI) | project coverage job (e.g. .pi/scripts/coverage.sh --gate) |
|
|
608
657
|
| 3 | CI runs checks on every PR | run_hardening_stages.sh |
|
|
609
658
|
| 4 | All scripts exit 0 on pass, 1 on fail | self-validating |
|
|
610
659
|
|
|
@@ -634,6 +683,108 @@ run_stage "11" "${moduleId}_proofing" \\
|
|
|
634
683
|
|
|
635
684
|
// ── Architecture Readiness Generator (expanded) ──
|
|
636
685
|
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* ADR-009: Runtime Integration & Legacy Migration issue generator.
|
|
689
|
+
* Modules whose doc documents runtime integration get a mandatory epic item
|
|
690
|
+
* (after implementation, before proofing) so "implemented but never wired"
|
|
691
|
+
* can no longer be deferred via an honest note.
|
|
692
|
+
*/
|
|
693
|
+
export function moduleHasRuntimeIntegration(cwd: string, moduleId: string): boolean {
|
|
694
|
+
const doc = readModuleDoc(cwd, moduleId);
|
|
695
|
+
if (!doc) return false;
|
|
696
|
+
return /^#{2,3}\s+(Integration|Runtime|Dispatch|Wiring|.*Dispatch.*)/im.test(doc);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
export function generateRuntimeIntegrationMarkdown(
|
|
700
|
+
slice: ArchitectureSlice,
|
|
701
|
+
epicName: string,
|
|
702
|
+
cwd?: string,
|
|
703
|
+
): string {
|
|
704
|
+
const moduleId = slice.module.replace(/^module-/, "");
|
|
705
|
+
const doc = cwd ? readModuleDoc(cwd, slice.module) : "";
|
|
706
|
+
// Pull the documented integration seam(s) as guidance for the implementer.
|
|
707
|
+
const seam = (() => {
|
|
708
|
+
for (const heading of ["Integration with Existing Modules", "Runtime Integration", "Integration"]) {
|
|
709
|
+
const body = extractSection(doc, heading);
|
|
710
|
+
if (body && body.trim().length > 0) return `## ${heading}\n\n${body.trim().slice(0, 1800)}`;
|
|
711
|
+
}
|
|
712
|
+
return "";
|
|
713
|
+
})();
|
|
714
|
+
|
|
715
|
+
return `---
|
|
716
|
+
guardian_issue:
|
|
717
|
+
id: "ISSUE-RUNTIME-INTEGRATION"
|
|
718
|
+
epic: "${epicName}"
|
|
719
|
+
component: "Runtime Integration & Legacy Migration"
|
|
720
|
+
module: "${slice.module}"
|
|
721
|
+
status: planned
|
|
722
|
+
priority: high
|
|
723
|
+
dependencies: []
|
|
724
|
+
|
|
725
|
+
in_scope:
|
|
726
|
+
- Wire the new service(s) into the REAL runtime path — every choke point the module doc
|
|
727
|
+
documents (primary dispatch loop PLUS parallel / resume / hook variants; not just one seam)
|
|
728
|
+
- Remove or delegate the legacy path the module replaces (legacy symbol deleted or calling
|
|
729
|
+
the new service); honor any declared migration rule (e.g. GAP-N)
|
|
730
|
+
- Flip the feature ADR from Proposed to Accepted once wired
|
|
731
|
+
- Add an end-to-end test through the PUBLIC API that exercises the new path
|
|
732
|
+
|
|
733
|
+
out_of_scope:
|
|
734
|
+
- New feature behavior beyond wiring
|
|
735
|
+
- Schema/data migrations (unless the module doc's migration rule requires them)
|
|
736
|
+
|
|
737
|
+
canonical_references:
|
|
738
|
+
- module: ".pi/architecture/modules/${slice.module}.md"
|
|
739
|
+
- adr: ".pi/architecture/decisions/ADR-009-runtime-wiring-multilang-judgment.md"
|
|
740
|
+
|
|
741
|
+
acceptance_criteria:
|
|
742
|
+
- "New service reachable from the runtime entry path (production, non-test caller)"
|
|
743
|
+
- "Legacy path removed or delegating; migration rule honored"
|
|
744
|
+
- "Feature ADR Accepted"
|
|
745
|
+
- "E2E through the public API exercises the new path"
|
|
746
|
+
- "validate-runtime-wiring.sh passes for the module (no dead service)"
|
|
747
|
+
|
|
748
|
+
validators:
|
|
749
|
+
- ci
|
|
750
|
+
- tests
|
|
751
|
+
- architecture
|
|
752
|
+
- operations
|
|
753
|
+
- canonical
|
|
754
|
+
|
|
755
|
+
implementation_notes: |
|
|
756
|
+
Run .pi/scripts/validate-runtime-wiring.sh before and after. If the new service
|
|
757
|
+
is only referenced by its own tests, it is NOT integrated. Converting the
|
|
758
|
+
documented dispatch choke point(s) is the acceptance slice — do not close this
|
|
759
|
+
issue with an honest deferral note.
|
|
760
|
+
|
|
761
|
+
file_changes:
|
|
762
|
+
- "modify: runtime dispatch / composition root (per module doc integration section)"
|
|
763
|
+
---
|
|
764
|
+
|
|
765
|
+
# Runtime Integration & Legacy Migration: ${slice.module}
|
|
766
|
+
|
|
767
|
+
## Intent
|
|
768
|
+
|
|
769
|
+
The implementation issues above delivered tested components. This issue makes them
|
|
770
|
+
**actually run**: wire them into the runtime dispatch path, retire the legacy path,
|
|
771
|
+
and prove it with an end-to-end test — per ADR-009 (implemented-but-unwired is the
|
|
772
|
+
gap this closes).
|
|
773
|
+
|
|
774
|
+
${seam || "> No explicit integration section found in the module doc — trace the runtime entry path (dispatch/composition root) yourself."}
|
|
775
|
+
|
|
776
|
+
## Acceptance Criteria
|
|
777
|
+
|
|
778
|
+
| # | Criterion | How to Verify |
|
|
779
|
+
|---|-----------|---------------|
|
|
780
|
+
| 1 | Service reachable from runtime entry path | grep production (non-test) caller outside the module |
|
|
781
|
+
| 2 | Legacy path removed or delegating | legacy symbol deleted / delegates to new service |
|
|
782
|
+
| 3 | Feature ADR Accepted | ADR Status not Proposed |
|
|
783
|
+
| 4 | E2E exercises the new path through the public API | integration/e2e test |
|
|
784
|
+
| 5 | validate-runtime-wiring.sh passes | script exit 0 |
|
|
785
|
+
`;
|
|
786
|
+
}
|
|
787
|
+
|
|
637
788
|
export function generateArchitectureReadinessMarkdown(
|
|
638
789
|
slice: ArchitectureSlice,
|
|
639
790
|
epicName: string,
|
|
@@ -353,6 +353,11 @@ export function parseModuleFile(filePath: string): ModuleComponent[] {
|
|
|
353
353
|
let currentStatus = "";
|
|
354
354
|
let currentDesc = "";
|
|
355
355
|
let currentDeps: string[] = [];
|
|
356
|
+
let currentDepth = undefined as ModuleComponent["modelingDepth"];
|
|
357
|
+
let currentAggregateRoot = false;
|
|
358
|
+
let currentInvariants: string[] = [];
|
|
359
|
+
let currentPublishes: string[] = [];
|
|
360
|
+
let currentSubscribes: string[] = [];
|
|
356
361
|
|
|
357
362
|
function saveCurrent() {
|
|
358
363
|
if (currentName) {
|
|
@@ -364,6 +369,17 @@ export function parseModuleFile(filePath: string): ModuleComponent[] {
|
|
|
364
369
|
status: status as ModuleComponent["status"],
|
|
365
370
|
description: desc.trim(),
|
|
366
371
|
dependencies: currentDeps.length > 0 ? currentDeps : ["none"],
|
|
372
|
+
...(currentDepth ? { modelingDepth: currentDepth } : {}),
|
|
373
|
+
...(currentAggregateRoot ? { aggregateRoot: true } : {}),
|
|
374
|
+
...(currentInvariants.length > 0 ? { invariants: currentInvariants } : {}),
|
|
375
|
+
...(currentPublishes.length > 0 || currentSubscribes.length > 0
|
|
376
|
+
? {
|
|
377
|
+
events: {
|
|
378
|
+
publishes: currentPublishes,
|
|
379
|
+
subscribes: currentSubscribes,
|
|
380
|
+
},
|
|
381
|
+
}
|
|
382
|
+
: {}),
|
|
367
383
|
});
|
|
368
384
|
}
|
|
369
385
|
}
|
|
@@ -384,6 +400,11 @@ export function parseModuleFile(filePath: string): ModuleComponent[] {
|
|
|
384
400
|
currentStatus = "";
|
|
385
401
|
currentDesc = "";
|
|
386
402
|
currentDeps = [];
|
|
403
|
+
currentDepth = undefined;
|
|
404
|
+
currentAggregateRoot = false;
|
|
405
|
+
currentInvariants = [];
|
|
406
|
+
currentPublishes = [];
|
|
407
|
+
currentSubscribes = [];
|
|
387
408
|
inComponentSection = false;
|
|
388
409
|
inDetailsSection = false;
|
|
389
410
|
continue;
|
|
@@ -401,6 +422,11 @@ export function parseModuleFile(filePath: string): ModuleComponent[] {
|
|
|
401
422
|
currentStatus = "";
|
|
402
423
|
currentDesc = "";
|
|
403
424
|
currentDeps = [];
|
|
425
|
+
currentDepth = undefined;
|
|
426
|
+
currentAggregateRoot = false;
|
|
427
|
+
currentInvariants = [];
|
|
428
|
+
currentPublishes = [];
|
|
429
|
+
currentSubscribes = [];
|
|
404
430
|
continue;
|
|
405
431
|
}
|
|
406
432
|
|
|
@@ -413,6 +439,29 @@ export function parseModuleFile(filePath: string): ModuleComponent[] {
|
|
|
413
439
|
if (depsStr && depsStr !== "none" && depsStr !== "[TODO") {
|
|
414
440
|
currentDeps = depsStr.split(",").map((d) => d.trim()).filter(Boolean);
|
|
415
441
|
}
|
|
442
|
+
} else if (trimmed.startsWith("modelingDepth:")) {
|
|
443
|
+
const v = trimmed.replace("modelingDepth:", "").trim();
|
|
444
|
+
if (v === "tactical" || v === "service" || v === "adapter") currentDepth = v;
|
|
445
|
+
} else if (trimmed.startsWith("aggregateRoot:")) {
|
|
446
|
+
currentAggregateRoot = trimmed.replace("aggregateRoot:", "").trim() === "true";
|
|
447
|
+
} else if (trimmed.startsWith("invariants:")) {
|
|
448
|
+
currentInvariants = trimmed
|
|
449
|
+
.replace("invariants:", "")
|
|
450
|
+
.split(";")
|
|
451
|
+
.map((x) => x.trim())
|
|
452
|
+
.filter(Boolean);
|
|
453
|
+
} else if (trimmed.startsWith("publishes:")) {
|
|
454
|
+
currentPublishes = trimmed
|
|
455
|
+
.replace("publishes:", "")
|
|
456
|
+
.split(",")
|
|
457
|
+
.map((x) => x.trim())
|
|
458
|
+
.filter(Boolean);
|
|
459
|
+
} else if (trimmed.startsWith("subscribes:")) {
|
|
460
|
+
currentSubscribes = trimmed
|
|
461
|
+
.replace("subscribes:", "")
|
|
462
|
+
.split(",")
|
|
463
|
+
.map((x) => x.trim())
|
|
464
|
+
.filter(Boolean);
|
|
416
465
|
} else if (trimmed.startsWith("**Purpose:**")) {
|
|
417
466
|
currentDesc = trimmed.replace(/\*\*Purpose:\*\*\s*/, "").trim();
|
|
418
467
|
} else if (!currentDesc && trimmed.length > 10 && !trimmed.startsWith("#") && !trimmed.startsWith("-") && !trimmed.startsWith("|") && !trimmed.startsWith(">") && !trimmed.startsWith("```")) {
|
|
@@ -81,7 +81,7 @@ export interface TddGenerateOptions {
|
|
|
81
81
|
cwd: string;
|
|
82
82
|
/** Language from manifest (default: "typescript") */
|
|
83
83
|
language: string;
|
|
84
|
-
/** Base test directory (
|
|
84
|
+
/** Base test directory (auto-detected from project language if not set) */
|
|
85
85
|
testBaseDir?: string;
|
|
86
86
|
/** Module name for path construction */
|
|
87
87
|
moduleName?: string;
|
|
@@ -55,12 +55,16 @@ export type ExtensionContext = {
|
|
|
55
55
|
notify(message: string, level?: string): void;
|
|
56
56
|
setStatus(key: string, message: string | null): void;
|
|
57
57
|
confirm(title: string, message: string): Promise<boolean>;
|
|
58
|
+
theme?: unknown;
|
|
58
59
|
};
|
|
59
60
|
tools: { execute(name: string, params: Record<string, unknown>): Promise<unknown> };
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
export type ExtensionAPI = {
|
|
63
|
-
on(
|
|
64
|
+
on(
|
|
65
|
+
event: string,
|
|
66
|
+
handler: (event: unknown, ctx: ExtensionContext) => unknown | Promise<unknown>,
|
|
67
|
+
): void;
|
|
64
68
|
registerTool(options: {
|
|
65
69
|
name: string;
|
|
66
70
|
label: string;
|
|
@@ -70,7 +74,7 @@ export type ExtensionAPI = {
|
|
|
70
74
|
toolCallId: string,
|
|
71
75
|
params: Record<string, unknown>,
|
|
72
76
|
signal: AbortSignal,
|
|
73
|
-
onUpdate: (update: { type
|
|
77
|
+
onUpdate: (update: { type?: string; message?: string; content?: unknown }) => void,
|
|
74
78
|
ctx: ExtensionContext,
|
|
75
79
|
): unknown | Promise<unknown>;
|
|
76
80
|
}): void;
|
|
@@ -96,6 +100,14 @@ export type ModuleComponent = {
|
|
|
96
100
|
status: "planned" | "in-progress" | "implemented" | "deprecated";
|
|
97
101
|
description: string;
|
|
98
102
|
dependencies: string[];
|
|
103
|
+
/** ADR-008 modeling depth for this component's module (from exploration) */
|
|
104
|
+
modelingDepth?: "tactical" | "service" | "adapter";
|
|
105
|
+
/** True when this component is an aggregate root — slice selection keeps it atomic */
|
|
106
|
+
aggregateRoot?: boolean;
|
|
107
|
+
/** Aggregate invariants (ADR-008) — become frozen contract + TDD tests */
|
|
108
|
+
invariants?: string[];
|
|
109
|
+
/** Domain events this aggregate publishes/subscribes to (ADR-008) */
|
|
110
|
+
events?: { publishes: string[]; subscribes: string[] };
|
|
99
111
|
};
|
|
100
112
|
|
|
101
113
|
export type ArchitectureSlice = {
|
|
@@ -104,6 +116,36 @@ export type ArchitectureSlice = {
|
|
|
104
116
|
nextLogicalSlice: ModuleComponent[];
|
|
105
117
|
};
|
|
106
118
|
|
|
119
|
+
|
|
120
|
+
/** A module row inside a roadmap phase (implementation-roadmap.md). */
|
|
121
|
+
export interface RoadmapPhaseModule {
|
|
122
|
+
name: string;
|
|
123
|
+
deliverables: string;
|
|
124
|
+
doc: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** A single delivery phase parsed from implementation-roadmap.md. */
|
|
128
|
+
export interface RoadmapPhase {
|
|
129
|
+
index: number;
|
|
130
|
+
title: string;
|
|
131
|
+
goal: string;
|
|
132
|
+
days: string;
|
|
133
|
+
modules: RoadmapPhaseModule[];
|
|
134
|
+
completedModules: string[];
|
|
135
|
+
dependencies: string[];
|
|
136
|
+
migrations: string[];
|
|
137
|
+
criteria: string[];
|
|
138
|
+
status: string; // "pending" | "in_progress" | "done"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Persisted roadmap execution state (.pi/.guardian-roadmap-state.json). */
|
|
142
|
+
export interface RoadmapState {
|
|
143
|
+
phases: RoadmapPhase[];
|
|
144
|
+
currentPhaseIndex: number;
|
|
145
|
+
startedAt: string;
|
|
146
|
+
updatedAt: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
107
149
|
export type EpicState = {
|
|
108
150
|
name: string;
|
|
109
151
|
trackingIssueId: string | null;
|