aw-spec-cli 0.1.26 → 0.1.28

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.
Files changed (137) hide show
  1. package/assets/.agents/skills/appweaver/SKILL.md +7 -47
  2. package/assets/.appweaver/ORCH-DIALECT.md +13 -9
  3. package/assets/.appweaver/RULE-PARTITION.md +11 -12
  4. package/assets/.appweaver/STACK-PROFILES.md +260 -108
  5. package/assets/.appweaver/domain.json +1 -1
  6. package/assets/.appweaver/interpreter/run-skill.py +28 -7
  7. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
  8. package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
  9. package/assets/.appweaver/orchestrator/README.md +120 -53
  10. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
  11. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +17 -7
  12. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
  13. package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
  14. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +392 -0
  15. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +548 -0
  16. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
  17. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
  18. package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
  19. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +5 -4
  20. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +3 -1
  21. package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
  22. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
  23. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +21 -13
  24. package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
  25. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +28 -31
  26. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
  27. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
  28. package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
  29. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +4 -1
  30. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +6 -4
  31. package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
  32. package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
  33. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +17 -16
  34. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +7 -1
  35. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +7 -1
  36. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
  37. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
  38. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
  39. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
  40. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
  41. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  42. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
  43. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +253 -44
  44. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +72 -71
  45. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
  46. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +38 -14
  47. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
  48. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
  49. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
  50. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
  51. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +3 -3
  52. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
  53. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
  54. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +371 -131
  55. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +293 -76
  56. package/assets/.appweaver/scripts/python/aw-foundation.py +885 -20
  57. package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
  58. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
  59. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
  60. package/assets/.appweaver/scripts/python/aw-stack.py +676 -99
  61. package/assets/.appweaver/stack-profiles/angular.json +2 -1
  62. package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
  63. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +18 -3
  64. package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
  65. package/assets/.appweaver/stack-profiles/java-spring.json +14 -5
  66. package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
  67. package/assets/.appweaver/stack-profiles/node-express.json +8 -2
  68. package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
  69. package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
  70. package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
  71. package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
  72. package/assets/.appweaver/stacks.json +40 -1
  73. package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
  74. package/assets/.appweaver/templates/delta-design-template.md +7 -5
  75. package/assets/.appweaver/templates/design-template.md +3 -0
  76. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  77. package/assets/.appweaver/templates/ui-design-template.md +6 -4
  78. package/assets/.claude/skills/appweaver/SKILL.md +7 -46
  79. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
  80. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.lane.json +6 -0
  81. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
  82. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.lane.json +6 -0
  83. package/assets/foundations/foundation.spec.template.txt +98 -0
  84. package/assets/foundations/java/Hexagonal/Hexagonal.lane.json +6 -0
  85. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +8 -1
  86. package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
  87. package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
  88. package/assets/guardrails/README.md +31 -17
  89. package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +25 -13
  90. package/assets/guardrails/project-specific/tech-rule-bindings.md +296 -0
  91. package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
  92. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
  93. package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
  94. package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
  95. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
  96. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
  97. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
  98. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
  99. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
  100. package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
  101. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  102. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
  103. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
  104. package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
  105. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  106. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
  107. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
  108. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
  109. package/assets/guardrails/technology/nextjs/api-client.md +1 -1
  110. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
  111. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
  112. package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
  113. package/assets/guardrails/technology/nextjs/client-security.md +1 -1
  114. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  115. package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
  116. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  117. package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
  118. package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
  119. package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
  120. package/assets/guardrails/technology/nextjs/i18n.md +1 -1
  121. package/assets/guardrails/technology/nextjs/observability.md +1 -1
  122. package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
  123. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  124. package/assets/guardrails/technology/nextjs/state-management.md +1 -1
  125. package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
  126. package/package.json +1 -1
  127. package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
  128. package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
  129. package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
  130. package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
  131. package/assets/.kilocode/agent.json +0 -28
  132. package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
  133. package/assets/.kilocode/workflows/appweaver.md +0 -55
  134. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +0 -271
  135. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
  136. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
  137. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/service/technical-requirements.md +0 -0
@@ -3,7 +3,7 @@
3
3
  # aw-spec-actions.ps1 — common action dispatcher for the aw-spec orchestrator
4
4
  # (Windows / PowerShell mirror of aw-spec-actions.sh).
5
5
  #
6
- # ONE shared script for every integration (.claude / .agents / .kilocode). The
6
+ # ONE shared script for every integration (.claude / .agents / .kilo). The
7
7
  # orchestrator workflows reach these subcommands through `execute_script` steps.
8
8
  # Each subcommand performs deterministic, governance-safe work and prints a single
9
9
  # JSON object on stdout. NONE of these actions author spec/code content — content
@@ -107,7 +107,7 @@ function Invoke-ResolveDomain {
107
107
  try { $domain = (Get-Content $domainJson -Raw | ConvertFrom-Json).domain } catch { $domain = '' }
108
108
  if (-not $domain) { $domain = '' }
109
109
  }
110
- $rulemap = Join-Path $repo "guardrails/projects/$domain/domain-rule-bindings.md"
110
+ $rulemap = Join-Path $repo "guardrails/$domain/domain-rule-bindings.md"
111
111
  $rulemapExists = ($domain -ne '') -and (Test-Path $rulemap)
112
112
 
113
113
  $candidates = @()
@@ -132,7 +132,7 @@ function Invoke-ResolveDomain {
132
132
 
133
133
  # ─────────────────────────── resolve-tech ───────────────────────────────────
134
134
  # Technical rule-file mapping — parallel to resolve-domain, but reads
135
- # guardrails/projects/<project>/tech-rule-bindings.md. The TECHNICAL rule files live in the
135
+ # guardrails/<project>/tech-rule-bindings.md. The TECHNICAL rule files live in the
136
136
  # shared per-stack corpora at guardrails/technology/<stack>/ (rules) and
137
137
  # guardrails/technology/<stack>/examples/ (the worked sample for a rule file), and are
138
138
  # configured per-command in this map, so they can be tuned per project WITHOUT editing the
@@ -162,7 +162,7 @@ function Invoke-ResolveTech {
162
162
  try { $domain = (Get-Content $domainJson -Raw | ConvertFrom-Json).domain } catch { $domain = '' }
163
163
  if (-not $domain) { $domain = '' }
164
164
  }
165
- $techmap = Join-Path $repo "guardrails/projects/$domain/tech-rule-bindings.md"
165
+ $techmap = Join-Path $repo "guardrails/$domain/tech-rule-bindings.md"
166
166
  $techmapExists = ($domain -ne '') -and (Test-Path $techmap)
167
167
 
168
168
  # The declared stacks, so one map can be written for any of them.
@@ -512,15 +512,16 @@ function Invoke-CreateChecklist {
512
512
  }
513
513
 
514
514
  # ─────────────────────────── list-domains ──────────────────────────────────
515
- # The selectable projects: immediate subdirs of guardrails/projects/ that carry a rule
516
- # map. The map is what makes a directory a project, exactly as a *.pack.txt is what makes
517
- # a foundations/ directory a foundation — without that test any stray sibling would be
518
- # offered as a governance target. EITHER map qualifies, because onboard writes the domain
519
- # map several steps before the technical one and a half-built project must stay visible.
515
+ # The projects: immediate subdirs of guardrails/ that carry a rule map. The map is what
516
+ # makes a directory a project, exactly as a *.pack.txt is what makes a foundations/
517
+ # directory a foundation — the shared corpora technology/ and domain/ sit beside the
518
+ # projects and carry no map, so they are never listed. EITHER map qualifies, because
519
+ # onboard writes the domain map several steps before the technical one and a half-built
520
+ # project must stay visible.
520
521
  function Invoke-ListDomains {
521
522
  param([string[]]$Rest)
522
523
  $repo = Get-RepoRoot
523
- $base = Join-Path $repo 'guardrails/projects'
524
+ $base = Join-Path $repo 'guardrails'
524
525
  $domains = @()
525
526
  if (Test-Path $base) {
526
527
  $domains = @(Get-ChildItem -Directory $base -ErrorAction SilentlyContinue | Where-Object {
@@ -541,7 +542,7 @@ function Invoke-SetDomain {
541
542
  if (-not $domain) { Write-Error 'set-domain: --domain is required'; exit 1 }
542
543
 
543
544
  $repo = Get-RepoRoot
544
- $mapRel = "guardrails/projects/$domain/domain-rule-bindings.md"
545
+ $mapRel = "guardrails/$domain/domain-rule-bindings.md"
545
546
  $mapExists = Test-Path (Join-Path $repo $mapRel)
546
547
 
547
548
  New-Item -ItemType Directory -Force -Path (Join-Path $repo '.appweaver') | Out-Null
@@ -562,12 +563,11 @@ function Invoke-SetDomain {
562
563
  # SAME python core, so the JSON contract has one implementation and the pair cannot
563
564
  # drift.
564
565
  #
565
- # lane-declare is the SOLE WRITER of .appweaver/stacks.json, with two callers:
566
- # aw-spec-select-stack, where a person picks, and aw-spec-onboard, which declares
567
- # what it reverse-engineered (those lanes carry origin: reverse-engineered, and
568
- # onboard never overwrites a lane that is already declared). stack-detect proposes
569
- # candidates and writes nothing. lane-resolve can never write — which is why these
570
- # are separate subcommands rather than one with a mode flag.
566
+ # lane-declare writes WHOLE lanes into .appweaver/stacks.json and has exactly one caller:
567
+ # aw-spec-select-stack, where a person picks. lane-set changes only the API-contract keys
568
+ # on a lane already there (foundation and implement call it).
569
+ # stack-detect proposes candidates and writes nothing. lane-resolve can never write —
570
+ # which is why these are separate subcommands rather than one with a mode flag.
571
571
  function Invoke-AwStackCore {
572
572
  param([string]$Op, [string[]]$Rest)
573
573
  $py = Get-Py
@@ -640,9 +640,55 @@ function Invoke-LaneResolve {
640
640
  Invoke-AwStackCore -Op 'resolve' -Rest $fwd
641
641
  }
642
642
 
643
+ # Change the API-contract keys (contract_run, contract, client) on a lane already
644
+ # declared. Twin of bash cmd_lane_set.
645
+ function Invoke-LaneSet {
646
+ param([string[]]$Rest)
647
+ $fwd = @()
648
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
649
+ switch ($Rest[$i]) {
650
+ { $_ -in '--id','--kind','--set','--unset' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
651
+ default { Write-Error "lane-set: unknown arg '$($Rest[$i])'"; exit 1 }
652
+ }
653
+ }
654
+ Invoke-AwStackCore -Op 'set' -Rest $fwd
655
+ }
656
+
657
+ # ─────────────── contract-export / contract-client / contract-check ───────────────
658
+ # Twins of the bash cmd_contract_export / cmd_contract_client / cmd_contract_check.
659
+ function Invoke-ContractExport {
660
+ param([string[]]$Rest)
661
+ $fwd = @()
662
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
663
+ switch ($Rest[$i]) {
664
+ '--timeout' { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
665
+ default { Write-Error "contract-export: unknown arg '$($Rest[$i])'"; exit 1 }
666
+ }
667
+ }
668
+ Invoke-AwStackCore -Op 'contract-export' -Rest $fwd
669
+ }
670
+
671
+ function Invoke-ContractClient {
672
+ param([string[]]$Rest)
673
+ if ($Rest.Count -gt 0) { Write-Error "contract-client: unknown arg '$($Rest[0])'"; exit 1 }
674
+ Invoke-AwStackCore -Op 'run-phase' -Rest @('--phase', 'client', '--kind', 'frontend')
675
+ }
676
+
677
+ function Invoke-ContractCheck {
678
+ param([string[]]$Rest)
679
+ $fwd = @()
680
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
681
+ switch ($Rest[$i]) {
682
+ { $_ -in '--plan','--doc' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
683
+ default { Write-Error "contract-check: unknown arg '$($Rest[$i])'"; exit 1 }
684
+ }
685
+ }
686
+ Invoke-AwStackCore -Op 'contract-check' -Rest $fwd
687
+ }
688
+
643
689
  # The gate: is the declaration USABLE for the phase about to run. Twin of bash
644
690
  # cmd_lane_verify. --require names a lane kind the phase cannot run without;
645
- # --allow-missing-root is the greenfield state, where a source path is declared
691
+ # --allow-missing-root is the greenfield state, where a lane root folder is declared
646
692
  # before implement creates it.
647
693
  function Invoke-LaneVerify {
648
694
  param([string[]]$Rest)
@@ -811,6 +857,9 @@ function Invoke-ListContexts {
811
857
  # Twin of bash cmd_set_context. Creates the context directory but NOT
812
858
  # domain-model.md — specify is the only writer of the model, and an empty
813
859
  # placeholder would read as "the model exists" to every later gate.
860
+ # Clears .appweaver/feature.json when the selected context does not contain the
861
+ # active feature (a flat specs/<Feature> included), so no feature-scoped command
862
+ # writes into the context the developer just left.
814
863
  function Invoke-SetContext {
815
864
  param([string[]]$Rest)
816
865
  $raw = ''
@@ -840,6 +889,18 @@ function Invoke-SetContext {
840
889
  [ordered]@{ context = $context; context_directory = $contextDirRel } | ConvertTo-Json -Compress |
841
890
  Set-Content -Path (Join-Path $repo '.appweaver/context.json') -Encoding UTF8
842
891
 
892
+ $activeFd = "$(Read-FeatureDir -RepoRoot $repo)" -replace '\\', '/'
893
+ $repoPrefix = ($repo -replace '\\', '/').TrimEnd('/') + '/'
894
+ if ($activeFd.StartsWith($repoPrefix, [System.StringComparison]::Ordinal)) { $activeFd = $activeFd.Substring($repoPrefix.Length) }
895
+ if ($activeFd.StartsWith('./', [System.StringComparison]::Ordinal)) { $activeFd = $activeFd.Substring(2) }
896
+ $activeFd = $activeFd.TrimEnd('/')
897
+ $featureCleared = $false; $clearedFeature = ''
898
+ if ($activeFd -and -not $activeFd.StartsWith("$contextDirRel/", [System.StringComparison]::Ordinal)) {
899
+ @{ feature_directory = '' } | ConvertTo-Json -Compress |
900
+ Set-Content -Path (Join-Path $repo '.appweaver/feature.json') -Encoding UTF8
901
+ $featureCleared = $true; $clearedFeature = $activeFd
902
+ }
903
+
843
904
  Write-Json ([ordered]@{
844
905
  context = $context
845
906
  context_dir = $contextDirRel
@@ -847,6 +908,8 @@ function Invoke-SetContext {
847
908
  existed = [bool]$existed
848
909
  created = (-not $existed)
849
910
  domain_model_exists = (Test-Path (Join-Path $contextDir 'domain-model.md'))
911
+ feature_cleared = $featureCleared
912
+ cleared_feature = $clearedFeature
850
913
  written = $true
851
914
  })
852
915
  }
@@ -1033,6 +1096,43 @@ function Invoke-SetFeature {
1033
1096
  })
1034
1097
  }
1035
1098
 
1099
+ # ─────────────────────────── default-scope ─────────────────────────────────
1100
+ # Twin of bash cmd_default_scope. Acts only on a project with no specs yet — no
1101
+ # directory under specs/ and no active feature — and creates through set-context and
1102
+ # set-feature, so both pointer files are written exactly as the select commands write
1103
+ # them. context_dir / feature_dir report the active pair after the call, created or not.
1104
+ function Invoke-DefaultScope {
1105
+ param([string[]]$Rest)
1106
+ $ctx = ''; $feat = ''
1107
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1108
+ if ($Rest[$i] -in '--context','-Context') { $ctx = $Rest[++$i] }
1109
+ elseif ($Rest[$i] -in '--feature','-Feature') { $feat = $Rest[++$i] }
1110
+ }
1111
+ if (-not $ctx -or -not $feat) { Write-Error 'default-scope: --context and --feature are required'; exit 1 }
1112
+
1113
+ $repo = Get-RepoRoot
1114
+ $specs = Join-Path $repo 'specs'
1115
+ $reason = ''
1116
+ if ((Test-Path $specs) -and @(Get-ChildItem -Directory -Force $specs -ErrorAction SilentlyContinue).Count -gt 0) {
1117
+ $reason = 'specs/ already holds a bounded context or a feature'
1118
+ } elseif ("$(Read-FeatureDir -RepoRoot $repo)") {
1119
+ $reason = 'a feature is already active in .appweaver/feature.json'
1120
+ }
1121
+
1122
+ $created = $false
1123
+ if (-not $reason) {
1124
+ $null = Invoke-SetContext -Rest @('--context', $ctx)
1125
+ $null = Invoke-SetFeature -Rest @('--feature', $feat)
1126
+ $created = $true
1127
+ }
1128
+ Write-Json ([ordered]@{
1129
+ created = $created
1130
+ skipped_reason = $reason
1131
+ context_dir = "$(Get-ContextDirectory -Repo $repo)"
1132
+ feature_dir = "$(Read-FeatureDir -RepoRoot $repo)"
1133
+ })
1134
+ }
1135
+
1036
1136
  # ═══════════════════════════ active_version.json ════════════════════════════
1037
1137
  # Per-feature version state. Shells out to the SAME python as the bash twin so the
1038
1138
  # bump/timestamp logic is byte-identical across shells. (See bash _active_version.)
@@ -1483,7 +1583,7 @@ function Invoke-DetectProject {
1483
1583
  $repo = Get-RepoRoot
1484
1584
  $scope = 'repo'
1485
1585
  $start = $repo
1486
- # A lane's source path arrives as the value declare stored, so it may carry a
1586
+ # A lane root folder arrives as the value declare stored, so it may carry a
1487
1587
  # trailing slash; an option label ("path — why") never reaches a script argument.
1488
1588
  $rel = ($scopeRoot -replace '\\','/').TrimStart('.','/').TrimEnd('/')
1489
1589
  if ($rel -and (Test-Path -PathType Container (Join-Path $repo $rel))) {
@@ -1533,52 +1633,118 @@ function Get-FoundationDirs {
1533
1633
  }
1534
1634
 
1535
1635
  # ──────────────────────────── foundation-list ──────────────────────────────
1536
- # List available foundations (foundations/<stack>/<Name>/ with a real <Name>.pack.txt)
1537
- # for the user to PICK — deterministic, no LLM. Optional --args fast path mirrors bash,
1538
- # including a third token coming back as `rejected_out` rather than as a destination:
1539
- # see the bash twin for why a scaffold has no caller-chosen output directory.
1636
+ # What ONE lane can be scaffolded from, as a pick list: its packs and specs, then
1637
+ # "[manual spec]" and "[skip]". Twin of bash cmd_foundation_list — see it for the three
1638
+ # filters. Both delegate to aw-foundation.py, so the scan has one implementation.
1639
+ function Invoke-AwFoundationCore {
1640
+ param([string]$Op, [string[]]$Rest)
1641
+ $py = Get-Py
1642
+ if (-not $py) { Write-Error 'aw-foundation: python3 is required to list foundations'; exit 1 }
1643
+ $core = Join-Path $PSScriptRoot '..' 'python' 'aw-foundation.py'
1644
+ if (-not (Test-Path $core)) { Write-Error "aw-foundation: core not found at $core"; exit 1 }
1645
+ $repo = Get-RepoRoot
1646
+ & $py $core '--repo' $repo $Op @Rest
1647
+ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
1648
+ }
1649
+
1540
1650
  function Invoke-FoundationList {
1541
1651
  param([string[]]$Rest)
1542
- $raw = ''; $ecoFilter = ''
1543
- for ($i = 0; $i -lt $Rest.Count; $i++) { switch ($Rest[$i]) { '--args' { $raw = $Rest[++$i] } '--ecosystem' { $ecoFilter = $Rest[++$i] } } }
1544
- $repo = Get-RepoRoot
1652
+ $fwd = @(); $ecoGiven = $false
1653
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1654
+ switch ($Rest[$i]) {
1655
+ { $_ -in '--args','--kind','--profile','--lane-id' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1656
+ '--ecosystem' { $fwd += '--ecosystem'; $fwd += $Rest[++$i]; $ecoGiven = $true }
1657
+ default { Write-Error "foundation-list: unknown arg '$($Rest[$i])'"; exit 1 }
1658
+ }
1659
+ }
1660
+ # Without --ecosystem: every declared lane's ecosystem, and no filter on a bare repo.
1661
+ if (-not $ecoGiven) { foreach ($e in @(Get-Ecosystems)) { $fwd += '--ecosystem'; $fwd += $e } }
1662
+ Invoke-AwFoundationCore -Op 'list' -Rest $fwd
1663
+ }
1545
1664
 
1546
- # WHICH foundations this repo may be offered. A foundation bundle is a whole
1547
- # compiling project in one ecosystem's languages and build system, so unpacking a
1548
- # .NET one into a Spring repo does not produce a scaffold — it produces a second,
1549
- # foreign project beside the real one. --ecosystem narrows to the ONE lane being
1550
- # scaffolded; without it the filter is every declared lane's ecosystem, and nothing
1551
- # at all on a bare repo.
1552
- $laneEcos = if ($ecoFilter) { @($ecoFilter) } else { @(Get-Ecosystems) }
1553
- $foundations = @(); $all = @(); $ecoOf = @()
1554
- foreach ($f in @(Get-FoundationDirs $repo)) {
1555
- if (-not (Test-Path (Join-Path $f.Dir "$($f.Name).pack.txt"))) { continue }
1556
- $all += $f.Name; $ecoOf += $f.Stack
1557
- if ($laneEcos.Count -eq 0 -or $laneEcos -contains $f.Stack) { $foundations += $f.Name }
1558
- }
1559
- $preName = ''; $preApp = ''; $rejectedOut = ''
1560
- if ($raw) { $t = $raw -split '\s+' | Where-Object { $_ }; if ($t.Count -ge 1) { $preName = $t[0] }; if ($t.Count -ge 2) { $preApp = $t[1] }; if ($t.Count -ge 3) { $rejectedOut = $t[2] } }
1561
- $match = if ($foundations -contains $preName) { $preName } else { '' }
1562
- Write-Json ([ordered]@{
1563
- foundations = @($foundations); count = $foundations.Count
1564
- all_foundations = @($all); all_count = $all.Count
1565
- ecosystems = @($ecoOf); lane_ecosystems = @($laneEcos)
1566
- filtered = ($laneEcos.Count -gt 0)
1567
- preselect_name = $match; preselect_app = $preApp; rejected_out = $rejectedOut
1568
- })
1665
+ # ─────────────────────────── foundation-choice ─────────────────────────────
1666
+ # Resolve the picked option back to its entry (route, name, file). Twin of bash.
1667
+ function Invoke-FoundationChoice {
1668
+ param([string[]]$Rest)
1669
+ $fwd = @()
1670
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1671
+ switch ($Rest[$i]) {
1672
+ { $_ -in '--selection','--kind','--profile','--ecosystem' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1673
+ default { Write-Error "foundation-choice: unknown arg '$($Rest[$i])'"; exit 1 }
1674
+ }
1675
+ }
1676
+ Invoke-AwFoundationCore -Op 'choice' -Rest $fwd
1677
+ }
1678
+
1679
+ # ────────────────────────── foundation-spec-capture ────────────────────────
1680
+ # Copy the spec a lane is about to be built from to .appweaver/foundation/<lane>.spec.md.
1681
+ # Twin of bash cmd_foundation_spec_capture.
1682
+ function Invoke-FoundationSpecCapture {
1683
+ param([string[]]$Rest)
1684
+ $fwd = @()
1685
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1686
+ switch ($Rest[$i]) {
1687
+ { $_ -in '--lane','--kind','--file','--input','--app' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1688
+ default { Write-Error "foundation-spec-capture: unknown arg '$($Rest[$i])'"; exit 1 }
1689
+ }
1690
+ }
1691
+ Invoke-AwFoundationCore -Op 'spec-capture' -Rest $fwd
1692
+ }
1693
+
1694
+ # ─────────────────────────── foundation-lane-files ─────────────────────────
1695
+ # What a lane already holds, asked before anything is scaffolded into it. Twin of
1696
+ # bash cmd_foundation_lane_files.
1697
+ function Invoke-FoundationLaneFiles {
1698
+ param([string[]]$Rest)
1699
+ $fwd = @()
1700
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1701
+ switch ($Rest[$i]) {
1702
+ { $_ -in '--source','--test','--workdir','--profile' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1703
+ default { Write-Error "foundation-lane-files: unknown arg '$($Rest[$i])'"; exit 1 }
1704
+ }
1705
+ }
1706
+ Invoke-AwFoundationCore -Op 'lane-files' -Rest $fwd
1707
+ }
1708
+
1709
+ # ─────────────────────── foundation-snapshot / -outside ────────────────────
1710
+ # What a spec build did outside its lane root folder: `snapshot` records the repo before
1711
+ # the build, `outside` lists what changed elsewhere afterwards and, with --undo, removes
1712
+ # what was created. Twins of bash cmd_foundation_snapshot / cmd_foundation_outside.
1713
+ function Invoke-FoundationSnapshot {
1714
+ param([string[]]$Rest)
1715
+ $fwd = @()
1716
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1717
+ switch ($Rest[$i]) {
1718
+ '--out' { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1719
+ default { Write-Error "foundation-snapshot: unknown arg '$($Rest[$i])'"; exit 1 }
1720
+ }
1721
+ }
1722
+ Invoke-AwFoundationCore -Op 'snapshot' -Rest $fwd
1723
+ }
1724
+
1725
+ function Invoke-FoundationOutside {
1726
+ param([string[]]$Rest)
1727
+ $fwd = @()
1728
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1729
+ switch ($Rest[$i]) {
1730
+ { $_ -in '--snapshot','--lane' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1731
+ '--undo' { $fwd += $Rest[$i] }
1732
+ default { Write-Error "foundation-outside: unknown arg '$($Rest[$i])'"; exit 1 }
1733
+ }
1734
+ }
1735
+ Invoke-AwFoundationCore -Op 'outside' -Rest $fwd
1569
1736
  }
1570
1737
 
1571
1738
  function Invoke-FoundationLocate {
1572
1739
  param([string[]]$Rest)
1573
- $name = ''; $app = ''; $out = '.'; $raw = ''
1574
- for ($i = 0; $i -lt $Rest.Count; $i++) { switch ($Rest[$i]) { '--name' { $name = $Rest[++$i] } '--app' { $app = $Rest[++$i] } '--out' { $out = $Rest[++$i] } '--args' { $raw = $Rest[++$i] } } }
1575
- if ($raw) { $t = $raw -split '\s+' | Where-Object { $_ }; if ($t.Count -ge 1) { $name = $t[0] }; if ($t.Count -ge 2) { $app = $t[1] }; if ($t.Count -ge 3) { $out = $t[2] } }
1740
+ $name = ''; $app = ''; $out = '.'
1741
+ for ($i = 0; $i -lt $Rest.Count; $i++) { switch ($Rest[$i]) { '--name' { $name = $Rest[++$i] } '--app' { $app = $Rest[++$i] } '--out' { $out = $Rest[++$i] } } }
1576
1742
  $repo = Get-RepoRoot
1577
1743
  $dirs = @(Get-FoundationDirs $repo)
1578
1744
  # available = every foundation dir (Get-FoundationDirs already requires a *.pack.txt)
1579
1745
  $available = @($dirs | ForEach-Object { $_.Name })
1580
1746
  function _fail($r) { Write-Json ([ordered]@{ ok = $false; reason = $r; available = @($available) }) }
1581
- if (-not $name -or -not $app) { _fail 'Usage: /aw-spec-foundation <FoundationName> <AppName> [OutputDirectory]'; return }
1747
+ if (-not $name -or -not $app) { _fail 'foundation-locate needs --name <FoundationName> and --app <AppName>'; return }
1582
1748
  $found = $dirs | Where-Object { $_.Name -eq $name } | Select-Object -First 1
1583
1749
  if (-not $found) { _fail "Foundation '$name' not found (expected foundations/<stack>/$name/)"; return }
1584
1750
  $stack = $found.Stack; $rel = $found.Rel; $fdir = $found.Dir
@@ -1593,15 +1759,17 @@ function Invoke-FoundationLocate {
1593
1759
  $sm = [regex]::Match($header, '(?i)sentinel[^A-Za-z0-9_.]*([A-Za-z0-9_.]+)')
1594
1760
  if ($sm.Success) { $sentinel = $sm.Groups[1].Value }
1595
1761
  $fc = 0; $fm = [regex]::Match($header, '(?i)file[^0-9]*([0-9]+)'); if ($fm.Success) { $fc = [int]$fm.Groups[1].Value }
1762
+ # A reference sample is offered only when its pack is there to unpack.
1763
+ $hasReference = Test-Path (Join-Path $fdir "$name.Reference.pack.txt")
1596
1764
  Write-Json ([ordered]@{
1597
1765
  ok = $true; reason = ''; name = $name; stack = $stack; app = $app; out_dir = $out
1598
1766
  pack_file = "$rel/$name.pack.txt"; unpacker = $unpacker; runner = $runner
1599
- sentinel = $sentinel; file_count = $fc; available = @($available)
1767
+ sentinel = $sentinel; file_count = $fc; has_reference = $hasReference; available = @($available)
1600
1768
  })
1601
1769
  }
1602
1770
 
1603
1771
  # ─────────────────────────── foundation-unpack ─────────────────────────────
1604
- # --out is the LANE'S SOURCE PATH and --test-path its other subtree; the pack's own test
1772
+ # --out is the LANE ROOT FOLDER and --test-path its other subtree; the pack's own test
1605
1773
  # tree is lifted onto the latter by aw-foundation.py. Twin of the bash cmd_foundation_unpack
1606
1774
  # — see it for why a scaffold goes into a lane rather than into the repo root.
1607
1775
  function Invoke-FoundationUnpack {
@@ -1613,11 +1781,11 @@ function Invoke-FoundationUnpack {
1613
1781
  if (-not $name -or -not $app) { Write-Error 'foundation-unpack: --name and --app required'; exit 1 }
1614
1782
  $repo = Get-RepoRoot
1615
1783
  $found = @(Get-FoundationDirs $repo) | Where-Object { $_.Name -eq $name } | Select-Object -First 1
1616
- $fdir = if ($found) { $found.Dir } else { Join-Path $repo "foundations/$name" }
1617
1784
  $packbase = if ($reference) { "$name.Reference" } else { $name }
1618
1785
  $stem = if ($reference) { 'unpack-reference-foundation' } else { 'unpack-foundation' }
1619
- $pack = Join-Path $fdir "$packbase.pack.txt"
1620
- if (-not (Test-Path $pack)) { Write-Json ([ordered]@{ ok = $false; mode = $(if ($dry) { 'dry' } else { 'real' }); written = 0; has_collisions = $false; stdout = "pack not found: $packbase.pack.txt" }); return }
1786
+ $pack = if ($found) { Join-Path $found.Dir "$packbase.pack.txt" } else { '' }
1787
+ $fdir = if ($found) { $found.Dir } else { '' }
1788
+ if (-not $pack -or -not (Test-Path $pack)) { Write-Json ([ordered]@{ ok = $false; mode = $(if ($dry) { 'dry' } else { 'real' }); written = 0; has_collisions = $false; stdout = "pack not found: $packbase.pack.txt" }); return }
1621
1789
  $cmd = $null; $cargs = @()
1622
1790
  if ((Get-Command pwsh -ErrorAction SilentlyContinue) -and (Test-Path (Join-Path $fdir "$stem.ps1"))) {
1623
1791
  $cmd = 'pwsh'; $cargs = @('-NoProfile','-File',(Join-Path $fdir "$stem.ps1"),'-PackFile',$pack,'-TargetAppName',$app,'-OutDir',$out)
@@ -1657,20 +1825,45 @@ function Invoke-FoundationUnpack {
1657
1825
  Write-Json ([ordered]@{ ok = ($rc -eq 0); mode = $(if ($dry) { 'dry' } else { 'real' }); written = $written; has_collisions = $hasColl; tests_moved = $testsMoved; tests_message = $testsMsg; stdout = ($outp.Substring([Math]::Max(0,$outp.Length-800))) })
1658
1826
  }
1659
1827
 
1660
- # ─────────────────────── foundation-stash-dbcontext ────────────────────────
1661
- function Invoke-FoundationStashDbContext {
1828
+ # ───────────────────── foundation-rules / -rules-done ──────────────────────
1829
+ # What a pack's rule file (<pack name>.rules.json) asks of an unpack, and the clean-up
1830
+ # after its merges. Twins of bash cmd_foundation_rules / cmd_foundation_rules_done.
1831
+ function Invoke-FoundationRules {
1662
1832
  param([string[]]$Rest)
1663
- $out = '.'
1664
- for ($i = 0; $i -lt $Rest.Count; $i++) { if ($Rest[$i] -eq '--out') { $out = $Rest[++$i] } }
1665
- $repo = Get-RepoRoot
1666
- if (-not [System.IO.Path]::IsPathRooted($out)) { $out = Join-Path $repo $out }
1667
- # Searched from the unpack root itself, which IS the lane's source path — a `src/`
1668
- # segment underneath it is the old repo-root layout and is not there any more.
1669
- $ctx = Get-ChildItem -LiteralPath $out -Recurse -Filter 'ApplicationDbContext.cs' -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName
1670
- if (-not $ctx) { Write-Json ([ordered]@{ found = $false; dbcontext = ''; backup = '' }); return }
1671
- $bak = "$ctx.foundation.bak"
1672
- Copy-Item $ctx $bak
1673
- Write-Json ([ordered]@{ found = $true; dbcontext = $ctx; backup = $bak })
1833
+ $fwd = @()
1834
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1835
+ switch ($Rest[$i]) {
1836
+ { $_ -in '--name','--app','--out','--state' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1837
+ '--reference' { $fwd += $Rest[$i] }
1838
+ default { Write-Error "foundation-rules: unknown arg '$($Rest[$i])'"; exit 1 }
1839
+ }
1840
+ }
1841
+ Invoke-AwFoundationCore -Op 'rules' -Rest $fwd
1842
+ }
1843
+
1844
+ function Invoke-FoundationRulesDone {
1845
+ param([string[]]$Rest)
1846
+ $fwd = @()
1847
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1848
+ switch ($Rest[$i]) {
1849
+ '--state' { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1850
+ default { Write-Error "foundation-rules-done: unknown arg '$($Rest[$i])'"; exit 1 }
1851
+ }
1852
+ }
1853
+ Invoke-AwFoundationCore -Op 'rules-done' -Rest $fwd
1854
+ }
1855
+
1856
+ # A pack's lane settings (<pack name>.lane.json). Twin of bash cmd_foundation_pack_lane.
1857
+ function Invoke-FoundationPackLane {
1858
+ param([string[]]$Rest)
1859
+ $fwd = @()
1860
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1861
+ switch ($Rest[$i]) {
1862
+ { $_ -in '--name','--app' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
1863
+ default { Write-Error "foundation-pack-lane: unknown arg '$($Rest[$i])'"; exit 1 }
1864
+ }
1865
+ }
1866
+ Invoke-AwFoundationCore -Op 'pack-lane' -Rest $fwd
1674
1867
  }
1675
1868
 
1676
1869
  # ─────────────────────────── foundation-verify ─────────────────────────────
@@ -2144,7 +2337,7 @@ function Invoke-ListComponents {
2144
2337
  function Invoke-FindHostProject {
2145
2338
  param([string[]]$Rest)
2146
2339
  $repo = Get-RepoRoot
2147
- # WHERE the host lives. The service lane's declared source path when there is one,
2340
+ # WHERE the host lives. The declared lane root folder of the service lane when there is one,
2148
2341
  # 'src' when there is not — the same question run-migrate asks, and the same answer.
2149
2342
  $svcRoot = Get-LaneField -Field 'backend_root'
2150
2343
  if (-not $svcRoot) { $svcRoot = 'src' }
@@ -2461,13 +2654,25 @@ function Get-Ecosystems {
2461
2654
  function Invoke-BuildCompile {
2462
2655
  param([string[]]$Rest)
2463
2656
  $repo = Get-RepoRoot
2657
+ # --kind builds ONE declared lane — what `foundation` uses to check the lane it just
2658
+ # created without compiling a lane it did not touch. Ignored on the undeclared ladder.
2659
+ $kind = ''
2660
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
2661
+ switch ($Rest[$i]) {
2662
+ '--feature-dir' { $i++ }
2663
+ '--kind' { $kind = $Rest[++$i] }
2664
+ default { Write-Error "build-compile: unknown arg '$($Rest[$i])'"; exit 1 }
2665
+ }
2666
+ }
2464
2667
 
2465
2668
  # A DECLARED lane model is the answer, and it is a better answer than the ladder
2466
2669
  # below in exactly the case that matters: a repo with two lanes. The sniffer takes
2467
2670
  # the first toolchain it finds and silently never builds the second, which reports
2468
2671
  # green for a frontend that was never compiled.
2469
2672
  if ((Get-LaneField -Field 'lane_count') -and (Get-LaneField -Field 'lane_count') -ne '0') {
2470
- Invoke-AwStackCore -Op 'run-phase' -Rest @('--phase', 'build')
2673
+ $phaseArgs = @('--phase', 'build')
2674
+ if ($kind) { $phaseArgs += @('--kind', $kind) }
2675
+ Invoke-AwStackCore -Op 'run-phase' -Rest $phaseArgs
2471
2676
  return
2472
2677
  }
2473
2678
 
@@ -2673,7 +2878,7 @@ function Invoke-RunMigrate {
2673
2878
  return
2674
2879
  }
2675
2880
 
2676
- # WHERE to look for the migration project. The service lane's declared source path
2881
+ # WHERE to look for the migration project. The declared lane root folder of the service lane
2677
2882
  # when there is one, 'src' when there is not. Migrations belong to the backend lane
2678
2883
  # by definition, so a repo whose service code sits in 'Legacy/App/' or 'backend/'
2679
2884
  # gets searched where its code actually is instead of being told it has no .NET
@@ -2691,7 +2896,7 @@ function Invoke-RunMigrate {
2691
2896
  }
2692
2897
  if ($efOk) {
2693
2898
  # Prefer *Service.csproj (API host with ApplicationDbContext); fall back to first
2694
- # non-AppHost/Web/ServiceDefaults/test project under the service lane's root.
2899
+ # non-AppHost/Web/ServiceDefaults/test project under the service lane root folder.
2695
2900
  $project = Get-ChildItem -LiteralPath $svcDir -Filter '*.Service.csproj' -Recurse -ErrorAction SilentlyContinue |
2696
2901
  Select-Object -First 1 -ExpandProperty FullName
2697
2902
  if (-not $project) {
@@ -4451,10 +4656,15 @@ switch ($sub) {
4451
4656
  'lane-resolve' { Invoke-LaneResolve -Rest $rest }
4452
4657
  'lane-verify' { Invoke-LaneVerify -Rest $rest }
4453
4658
  'lane-probe' { Invoke-LaneProbe -Rest $rest }
4659
+ 'lane-set' { Invoke-LaneSet -Rest $rest }
4660
+ 'contract-export' { Invoke-ContractExport -Rest $rest }
4661
+ 'contract-client' { Invoke-ContractClient -Rest $rest }
4662
+ 'contract-check' { Invoke-ContractCheck -Rest $rest }
4454
4663
  'list-contexts' { Invoke-ListContexts -Rest $rest }
4455
4664
  'set-context' { Invoke-SetContext -Rest $rest }
4456
4665
  'list-features' { Invoke-ListFeatures -Rest $rest }
4457
4666
  'set-feature' { Invoke-SetFeature -Rest $rest }
4667
+ 'default-scope' { Invoke-DefaultScope -Rest $rest }
4458
4668
  'version-read' { Invoke-VersionState 'read' $rest }
4459
4669
  'version-init' { Invoke-VersionState 'init' $rest }
4460
4670
  'version-bootstrap-done' { Invoke-VersionState 'bootstrap-done' $rest }
@@ -4494,10 +4704,17 @@ switch ($sub) {
4494
4704
  'checklist-apply' { Invoke-ChecklistApply -Rest $rest }
4495
4705
  'detect-project' { Invoke-DetectProject -Rest $rest }
4496
4706
  'foundation-list' { Invoke-FoundationList -Rest $rest }
4707
+ 'foundation-choice' { Invoke-FoundationChoice -Rest $rest }
4708
+ 'foundation-spec-capture' { Invoke-FoundationSpecCapture -Rest $rest }
4709
+ 'foundation-lane-files' { Invoke-FoundationLaneFiles -Rest $rest }
4710
+ 'foundation-snapshot' { Invoke-FoundationSnapshot -Rest $rest }
4711
+ 'foundation-outside' { Invoke-FoundationOutside -Rest $rest }
4497
4712
  'foundation-locate' { Invoke-FoundationLocate -Rest $rest }
4498
4713
  'foundation-unpack' { Invoke-FoundationUnpack -Rest $rest }
4499
4714
  'foundation-verify' { Invoke-FoundationVerify -Rest $rest }
4500
- 'foundation-stash-dbcontext' { Invoke-FoundationStashDbContext -Rest $rest }
4715
+ 'foundation-rules' { Invoke-FoundationRules -Rest $rest }
4716
+ 'foundation-rules-done' { Invoke-FoundationRulesDone -Rest $rest }
4717
+ 'foundation-pack-lane' { Invoke-FoundationPackLane -Rest $rest }
4501
4718
  'list-components' { Invoke-ListComponents -Rest $rest }
4502
4719
  'component-catalog' { Invoke-ComponentCatalog -Rest $rest }
4503
4720
  'component-verify' { Invoke-ComponentVerify -Rest $rest }