aw-spec-cli 0.1.26 → 0.1.27
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/assets/.agents/skills/appweaver/SKILL.md +7 -47
- package/assets/.appweaver/ORCH-DIALECT.md +13 -9
- package/assets/.appweaver/RULE-PARTITION.md +3 -3
- package/assets/.appweaver/STACK-PROFILES.md +188 -101
- package/assets/.appweaver/domain.json +1 -1
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
- package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
- package/assets/.appweaver/orchestrator/README.md +120 -53
- package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
- package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
- package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +349 -0
- package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +381 -0
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
- package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +5 -5
- package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +14 -14
- package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
- package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
- package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +13 -13
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +29 -28
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +53 -53
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +284 -128
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +224 -70
- package/assets/.appweaver/scripts/python/aw-foundation.py +809 -20
- package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
- package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
- package/assets/.appweaver/scripts/python/aw-stack.py +195 -89
- package/assets/.appweaver/stack-profiles/angular.json +2 -1
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +16 -3
- package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
- package/assets/.appweaver/stack-profiles/java-spring.json +12 -5
- package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
- package/assets/.appweaver/stack-profiles/node-express.json +8 -2
- package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
- package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
- package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
- package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
- package/assets/.appweaver/stacks.json +37 -1
- package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
- package/assets/.claude/skills/appweaver/SKILL.md +7 -46
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
- package/assets/foundations/foundation.spec.template.txt +73 -0
- package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +1 -1
- package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
- package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
- package/assets/guardrails/README.md +31 -17
- package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +5 -5
- package/assets/guardrails/{projects/dotnet-default-project → project-specific}/tech-rule-bindings.md +151 -114
- package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
- package/assets/guardrails/technology/nextjs/api-client.md +1 -1
- package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
- package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
- package/assets/guardrails/technology/nextjs/design-system.md +1 -1
- package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
- package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
- package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
- package/package.json +1 -1
- package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
- package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
- package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
- package/assets/.kilocode/agent.json +0 -28
- package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
- package/assets/.kilocode/workflows/appweaver.md +0 -55
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
- /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
- /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 / .
|
|
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
|
|
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
|
|
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
|
|
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
|
|
516
|
-
#
|
|
517
|
-
#
|
|
518
|
-
#
|
|
519
|
-
# map several steps before the technical one and a half-built
|
|
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
|
|
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
|
|
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
|
|
@@ -642,7 +643,7 @@ function Invoke-LaneResolve {
|
|
|
642
643
|
|
|
643
644
|
# The gate: is the declaration USABLE for the phase about to run. Twin of bash
|
|
644
645
|
# cmd_lane_verify. --require names a lane kind the phase cannot run without;
|
|
645
|
-
# --allow-missing-root is the greenfield state, where a
|
|
646
|
+
# --allow-missing-root is the greenfield state, where a lane root folder is declared
|
|
646
647
|
# before implement creates it.
|
|
647
648
|
function Invoke-LaneVerify {
|
|
648
649
|
param([string[]]$Rest)
|
|
@@ -811,6 +812,9 @@ function Invoke-ListContexts {
|
|
|
811
812
|
# Twin of bash cmd_set_context. Creates the context directory but NOT
|
|
812
813
|
# domain-model.md — specify is the only writer of the model, and an empty
|
|
813
814
|
# placeholder would read as "the model exists" to every later gate.
|
|
815
|
+
# Clears .appweaver/feature.json when the selected context does not contain the
|
|
816
|
+
# active feature (a flat specs/<Feature> included), so no feature-scoped command
|
|
817
|
+
# writes into the context the developer just left.
|
|
814
818
|
function Invoke-SetContext {
|
|
815
819
|
param([string[]]$Rest)
|
|
816
820
|
$raw = ''
|
|
@@ -840,6 +844,18 @@ function Invoke-SetContext {
|
|
|
840
844
|
[ordered]@{ context = $context; context_directory = $contextDirRel } | ConvertTo-Json -Compress |
|
|
841
845
|
Set-Content -Path (Join-Path $repo '.appweaver/context.json') -Encoding UTF8
|
|
842
846
|
|
|
847
|
+
$activeFd = "$(Read-FeatureDir -RepoRoot $repo)" -replace '\\', '/'
|
|
848
|
+
$repoPrefix = ($repo -replace '\\', '/').TrimEnd('/') + '/'
|
|
849
|
+
if ($activeFd.StartsWith($repoPrefix, [System.StringComparison]::Ordinal)) { $activeFd = $activeFd.Substring($repoPrefix.Length) }
|
|
850
|
+
if ($activeFd.StartsWith('./', [System.StringComparison]::Ordinal)) { $activeFd = $activeFd.Substring(2) }
|
|
851
|
+
$activeFd = $activeFd.TrimEnd('/')
|
|
852
|
+
$featureCleared = $false; $clearedFeature = ''
|
|
853
|
+
if ($activeFd -and -not $activeFd.StartsWith("$contextDirRel/", [System.StringComparison]::Ordinal)) {
|
|
854
|
+
@{ feature_directory = '' } | ConvertTo-Json -Compress |
|
|
855
|
+
Set-Content -Path (Join-Path $repo '.appweaver/feature.json') -Encoding UTF8
|
|
856
|
+
$featureCleared = $true; $clearedFeature = $activeFd
|
|
857
|
+
}
|
|
858
|
+
|
|
843
859
|
Write-Json ([ordered]@{
|
|
844
860
|
context = $context
|
|
845
861
|
context_dir = $contextDirRel
|
|
@@ -847,6 +863,8 @@ function Invoke-SetContext {
|
|
|
847
863
|
existed = [bool]$existed
|
|
848
864
|
created = (-not $existed)
|
|
849
865
|
domain_model_exists = (Test-Path (Join-Path $contextDir 'domain-model.md'))
|
|
866
|
+
feature_cleared = $featureCleared
|
|
867
|
+
cleared_feature = $clearedFeature
|
|
850
868
|
written = $true
|
|
851
869
|
})
|
|
852
870
|
}
|
|
@@ -1033,6 +1051,43 @@ function Invoke-SetFeature {
|
|
|
1033
1051
|
})
|
|
1034
1052
|
}
|
|
1035
1053
|
|
|
1054
|
+
# ─────────────────────────── default-scope ─────────────────────────────────
|
|
1055
|
+
# Twin of bash cmd_default_scope. Acts only on a project with no specs yet — no
|
|
1056
|
+
# directory under specs/ and no active feature — and creates through set-context and
|
|
1057
|
+
# set-feature, so both pointer files are written exactly as the select commands write
|
|
1058
|
+
# them. context_dir / feature_dir report the active pair after the call, created or not.
|
|
1059
|
+
function Invoke-DefaultScope {
|
|
1060
|
+
param([string[]]$Rest)
|
|
1061
|
+
$ctx = ''; $feat = ''
|
|
1062
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1063
|
+
if ($Rest[$i] -in '--context','-Context') { $ctx = $Rest[++$i] }
|
|
1064
|
+
elseif ($Rest[$i] -in '--feature','-Feature') { $feat = $Rest[++$i] }
|
|
1065
|
+
}
|
|
1066
|
+
if (-not $ctx -or -not $feat) { Write-Error 'default-scope: --context and --feature are required'; exit 1 }
|
|
1067
|
+
|
|
1068
|
+
$repo = Get-RepoRoot
|
|
1069
|
+
$specs = Join-Path $repo 'specs'
|
|
1070
|
+
$reason = ''
|
|
1071
|
+
if ((Test-Path $specs) -and @(Get-ChildItem -Directory -Force $specs -ErrorAction SilentlyContinue).Count -gt 0) {
|
|
1072
|
+
$reason = 'specs/ already holds a bounded context or a feature'
|
|
1073
|
+
} elseif ("$(Read-FeatureDir -RepoRoot $repo)") {
|
|
1074
|
+
$reason = 'a feature is already active in .appweaver/feature.json'
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
$created = $false
|
|
1078
|
+
if (-not $reason) {
|
|
1079
|
+
$null = Invoke-SetContext -Rest @('--context', $ctx)
|
|
1080
|
+
$null = Invoke-SetFeature -Rest @('--feature', $feat)
|
|
1081
|
+
$created = $true
|
|
1082
|
+
}
|
|
1083
|
+
Write-Json ([ordered]@{
|
|
1084
|
+
created = $created
|
|
1085
|
+
skipped_reason = $reason
|
|
1086
|
+
context_dir = "$(Get-ContextDirectory -Repo $repo)"
|
|
1087
|
+
feature_dir = "$(Read-FeatureDir -RepoRoot $repo)"
|
|
1088
|
+
})
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1036
1091
|
# ═══════════════════════════ active_version.json ════════════════════════════
|
|
1037
1092
|
# Per-feature version state. Shells out to the SAME python as the bash twin so the
|
|
1038
1093
|
# bump/timestamp logic is byte-identical across shells. (See bash _active_version.)
|
|
@@ -1483,7 +1538,7 @@ function Invoke-DetectProject {
|
|
|
1483
1538
|
$repo = Get-RepoRoot
|
|
1484
1539
|
$scope = 'repo'
|
|
1485
1540
|
$start = $repo
|
|
1486
|
-
# A lane
|
|
1541
|
+
# A lane root folder arrives as the value declare stored, so it may carry a
|
|
1487
1542
|
# trailing slash; an option label ("path — why") never reaches a script argument.
|
|
1488
1543
|
$rel = ($scopeRoot -replace '\\','/').TrimStart('.','/').TrimEnd('/')
|
|
1489
1544
|
if ($rel -and (Test-Path -PathType Container (Join-Path $repo $rel))) {
|
|
@@ -1533,52 +1588,118 @@ function Get-FoundationDirs {
|
|
|
1533
1588
|
}
|
|
1534
1589
|
|
|
1535
1590
|
# ──────────────────────────── foundation-list ──────────────────────────────
|
|
1536
|
-
#
|
|
1537
|
-
#
|
|
1538
|
-
#
|
|
1539
|
-
|
|
1591
|
+
# What ONE lane can be scaffolded from, as a pick list: its packs and specs, then
|
|
1592
|
+
# "[manual spec]" and "[skip]". Twin of bash cmd_foundation_list — see it for the three
|
|
1593
|
+
# filters. Both delegate to aw-foundation.py, so the scan has one implementation.
|
|
1594
|
+
function Invoke-AwFoundationCore {
|
|
1595
|
+
param([string]$Op, [string[]]$Rest)
|
|
1596
|
+
$py = Get-Py
|
|
1597
|
+
if (-not $py) { Write-Error 'aw-foundation: python3 is required to list foundations'; exit 1 }
|
|
1598
|
+
$core = Join-Path $PSScriptRoot '..' 'python' 'aw-foundation.py'
|
|
1599
|
+
if (-not (Test-Path $core)) { Write-Error "aw-foundation: core not found at $core"; exit 1 }
|
|
1600
|
+
$repo = Get-RepoRoot
|
|
1601
|
+
& $py $core '--repo' $repo $Op @Rest
|
|
1602
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1540
1605
|
function Invoke-FoundationList {
|
|
1541
1606
|
param([string[]]$Rest)
|
|
1542
|
-
$
|
|
1543
|
-
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1544
|
-
|
|
1607
|
+
$fwd = @(); $ecoGiven = $false
|
|
1608
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1609
|
+
switch ($Rest[$i]) {
|
|
1610
|
+
{ $_ -in '--args','--kind','--profile','--lane-id' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1611
|
+
'--ecosystem' { $fwd += '--ecosystem'; $fwd += $Rest[++$i]; $ecoGiven = $true }
|
|
1612
|
+
default { Write-Error "foundation-list: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
# Without --ecosystem: every declared lane's ecosystem, and no filter on a bare repo.
|
|
1616
|
+
if (-not $ecoGiven) { foreach ($e in @(Get-Ecosystems)) { $fwd += '--ecosystem'; $fwd += $e } }
|
|
1617
|
+
Invoke-AwFoundationCore -Op 'list' -Rest $fwd
|
|
1618
|
+
}
|
|
1545
1619
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1620
|
+
# ─────────────────────────── foundation-choice ─────────────────────────────
|
|
1621
|
+
# Resolve the picked option back to its entry (route, name, file). Twin of bash.
|
|
1622
|
+
function Invoke-FoundationChoice {
|
|
1623
|
+
param([string[]]$Rest)
|
|
1624
|
+
$fwd = @()
|
|
1625
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1626
|
+
switch ($Rest[$i]) {
|
|
1627
|
+
{ $_ -in '--selection','--kind','--profile','--ecosystem' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1628
|
+
default { Write-Error "foundation-choice: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
Invoke-AwFoundationCore -Op 'choice' -Rest $fwd
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
# ────────────────────────── foundation-spec-capture ────────────────────────
|
|
1635
|
+
# Copy the spec a lane is about to be built from to .appweaver/foundation/<lane>.spec.md.
|
|
1636
|
+
# Twin of bash cmd_foundation_spec_capture.
|
|
1637
|
+
function Invoke-FoundationSpecCapture {
|
|
1638
|
+
param([string[]]$Rest)
|
|
1639
|
+
$fwd = @()
|
|
1640
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1641
|
+
switch ($Rest[$i]) {
|
|
1642
|
+
{ $_ -in '--lane','--kind','--file','--input' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1643
|
+
default { Write-Error "foundation-spec-capture: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
Invoke-AwFoundationCore -Op 'spec-capture' -Rest $fwd
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
# ─────────────────────────── foundation-lane-files ─────────────────────────
|
|
1650
|
+
# What a lane already holds, asked before anything is scaffolded into it. Twin of
|
|
1651
|
+
# bash cmd_foundation_lane_files.
|
|
1652
|
+
function Invoke-FoundationLaneFiles {
|
|
1653
|
+
param([string[]]$Rest)
|
|
1654
|
+
$fwd = @()
|
|
1655
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1656
|
+
switch ($Rest[$i]) {
|
|
1657
|
+
{ $_ -in '--source','--test','--workdir','--profile' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1658
|
+
default { Write-Error "foundation-lane-files: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
Invoke-AwFoundationCore -Op 'lane-files' -Rest $fwd
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
# ─────────────────────── foundation-snapshot / -outside ────────────────────
|
|
1665
|
+
# What a spec build did outside its lane root folder: `snapshot` records the repo before
|
|
1666
|
+
# the build, `outside` lists what changed elsewhere afterwards and, with --undo, removes
|
|
1667
|
+
# what was created. Twins of bash cmd_foundation_snapshot / cmd_foundation_outside.
|
|
1668
|
+
function Invoke-FoundationSnapshot {
|
|
1669
|
+
param([string[]]$Rest)
|
|
1670
|
+
$fwd = @()
|
|
1671
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1672
|
+
switch ($Rest[$i]) {
|
|
1673
|
+
'--out' { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1674
|
+
default { Write-Error "foundation-snapshot: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
Invoke-AwFoundationCore -Op 'snapshot' -Rest $fwd
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
function Invoke-FoundationOutside {
|
|
1681
|
+
param([string[]]$Rest)
|
|
1682
|
+
$fwd = @()
|
|
1683
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1684
|
+
switch ($Rest[$i]) {
|
|
1685
|
+
{ $_ -in '--snapshot','--lane' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1686
|
+
'--undo' { $fwd += $Rest[$i] }
|
|
1687
|
+
default { Write-Error "foundation-outside: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
Invoke-AwFoundationCore -Op 'outside' -Rest $fwd
|
|
1569
1691
|
}
|
|
1570
1692
|
|
|
1571
1693
|
function Invoke-FoundationLocate {
|
|
1572
1694
|
param([string[]]$Rest)
|
|
1573
|
-
$name = ''; $app = ''; $out = '.'
|
|
1574
|
-
for ($i = 0; $i -lt $Rest.Count; $i++) { switch ($Rest[$i]) { '--name' { $name = $Rest[++$i] } '--app' { $app = $Rest[++$i] } '--out' { $out = $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] } }
|
|
1695
|
+
$name = ''; $app = ''; $out = '.'
|
|
1696
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) { switch ($Rest[$i]) { '--name' { $name = $Rest[++$i] } '--app' { $app = $Rest[++$i] } '--out' { $out = $Rest[++$i] } } }
|
|
1576
1697
|
$repo = Get-RepoRoot
|
|
1577
1698
|
$dirs = @(Get-FoundationDirs $repo)
|
|
1578
1699
|
# available = every foundation dir (Get-FoundationDirs already requires a *.pack.txt)
|
|
1579
1700
|
$available = @($dirs | ForEach-Object { $_.Name })
|
|
1580
1701
|
function _fail($r) { Write-Json ([ordered]@{ ok = $false; reason = $r; available = @($available) }) }
|
|
1581
|
-
if (-not $name -or -not $app) { _fail '
|
|
1702
|
+
if (-not $name -or -not $app) { _fail 'foundation-locate needs --name <FoundationName> and --app <AppName>'; return }
|
|
1582
1703
|
$found = $dirs | Where-Object { $_.Name -eq $name } | Select-Object -First 1
|
|
1583
1704
|
if (-not $found) { _fail "Foundation '$name' not found (expected foundations/<stack>/$name/)"; return }
|
|
1584
1705
|
$stack = $found.Stack; $rel = $found.Rel; $fdir = $found.Dir
|
|
@@ -1593,15 +1714,17 @@ function Invoke-FoundationLocate {
|
|
|
1593
1714
|
$sm = [regex]::Match($header, '(?i)sentinel[^A-Za-z0-9_.]*([A-Za-z0-9_.]+)')
|
|
1594
1715
|
if ($sm.Success) { $sentinel = $sm.Groups[1].Value }
|
|
1595
1716
|
$fc = 0; $fm = [regex]::Match($header, '(?i)file[^0-9]*([0-9]+)'); if ($fm.Success) { $fc = [int]$fm.Groups[1].Value }
|
|
1717
|
+
# A reference sample is offered only when its pack is there to unpack.
|
|
1718
|
+
$hasReference = Test-Path (Join-Path $fdir "$name.Reference.pack.txt")
|
|
1596
1719
|
Write-Json ([ordered]@{
|
|
1597
1720
|
ok = $true; reason = ''; name = $name; stack = $stack; app = $app; out_dir = $out
|
|
1598
1721
|
pack_file = "$rel/$name.pack.txt"; unpacker = $unpacker; runner = $runner
|
|
1599
|
-
sentinel = $sentinel; file_count = $fc; available = @($available)
|
|
1722
|
+
sentinel = $sentinel; file_count = $fc; has_reference = $hasReference; available = @($available)
|
|
1600
1723
|
})
|
|
1601
1724
|
}
|
|
1602
1725
|
|
|
1603
1726
|
# ─────────────────────────── foundation-unpack ─────────────────────────────
|
|
1604
|
-
# --out is the LANE
|
|
1727
|
+
# --out is the LANE ROOT FOLDER and --test-path its other subtree; the pack's own test
|
|
1605
1728
|
# tree is lifted onto the latter by aw-foundation.py. Twin of the bash cmd_foundation_unpack
|
|
1606
1729
|
# — see it for why a scaffold goes into a lane rather than into the repo root.
|
|
1607
1730
|
function Invoke-FoundationUnpack {
|
|
@@ -1613,11 +1736,11 @@ function Invoke-FoundationUnpack {
|
|
|
1613
1736
|
if (-not $name -or -not $app) { Write-Error 'foundation-unpack: --name and --app required'; exit 1 }
|
|
1614
1737
|
$repo = Get-RepoRoot
|
|
1615
1738
|
$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
1739
|
$packbase = if ($reference) { "$name.Reference" } else { $name }
|
|
1618
1740
|
$stem = if ($reference) { 'unpack-reference-foundation' } else { 'unpack-foundation' }
|
|
1619
|
-
$pack = Join-Path $
|
|
1620
|
-
|
|
1741
|
+
$pack = if ($found) { Join-Path $found.Dir "$packbase.pack.txt" } else { '' }
|
|
1742
|
+
$fdir = if ($found) { $found.Dir } else { '' }
|
|
1743
|
+
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
1744
|
$cmd = $null; $cargs = @()
|
|
1622
1745
|
if ((Get-Command pwsh -ErrorAction SilentlyContinue) -and (Test-Path (Join-Path $fdir "$stem.ps1"))) {
|
|
1623
1746
|
$cmd = 'pwsh'; $cargs = @('-NoProfile','-File',(Join-Path $fdir "$stem.ps1"),'-PackFile',$pack,'-TargetAppName',$app,'-OutDir',$out)
|
|
@@ -1657,20 +1780,32 @@ function Invoke-FoundationUnpack {
|
|
|
1657
1780
|
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
1781
|
}
|
|
1659
1782
|
|
|
1660
|
-
#
|
|
1661
|
-
|
|
1783
|
+
# ───────────────────── foundation-rules / -rules-done ──────────────────────
|
|
1784
|
+
# What a pack's rule file (<pack name>.rules.json) asks of an unpack, and the clean-up
|
|
1785
|
+
# after its merges. Twins of bash cmd_foundation_rules / cmd_foundation_rules_done.
|
|
1786
|
+
function Invoke-FoundationRules {
|
|
1662
1787
|
param([string[]]$Rest)
|
|
1663
|
-
$
|
|
1664
|
-
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1788
|
+
$fwd = @()
|
|
1789
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1790
|
+
switch ($Rest[$i]) {
|
|
1791
|
+
{ $_ -in '--name','--app','--out','--state' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1792
|
+
'--reference' { $fwd += $Rest[$i] }
|
|
1793
|
+
default { Write-Error "foundation-rules: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
Invoke-AwFoundationCore -Op 'rules' -Rest $fwd
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
function Invoke-FoundationRulesDone {
|
|
1800
|
+
param([string[]]$Rest)
|
|
1801
|
+
$fwd = @()
|
|
1802
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
1803
|
+
switch ($Rest[$i]) {
|
|
1804
|
+
'--state' { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
|
|
1805
|
+
default { Write-Error "foundation-rules-done: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
Invoke-AwFoundationCore -Op 'rules-done' -Rest $fwd
|
|
1674
1809
|
}
|
|
1675
1810
|
|
|
1676
1811
|
# ─────────────────────────── foundation-verify ─────────────────────────────
|
|
@@ -2144,7 +2279,7 @@ function Invoke-ListComponents {
|
|
|
2144
2279
|
function Invoke-FindHostProject {
|
|
2145
2280
|
param([string[]]$Rest)
|
|
2146
2281
|
$repo = Get-RepoRoot
|
|
2147
|
-
# WHERE the host lives. The
|
|
2282
|
+
# WHERE the host lives. The declared lane root folder of the service lane when there is one,
|
|
2148
2283
|
# 'src' when there is not — the same question run-migrate asks, and the same answer.
|
|
2149
2284
|
$svcRoot = Get-LaneField -Field 'backend_root'
|
|
2150
2285
|
if (-not $svcRoot) { $svcRoot = 'src' }
|
|
@@ -2461,13 +2596,25 @@ function Get-Ecosystems {
|
|
|
2461
2596
|
function Invoke-BuildCompile {
|
|
2462
2597
|
param([string[]]$Rest)
|
|
2463
2598
|
$repo = Get-RepoRoot
|
|
2599
|
+
# --kind builds ONE declared lane — what `foundation` uses to check the lane it just
|
|
2600
|
+
# created without compiling a lane it did not touch. Ignored on the undeclared ladder.
|
|
2601
|
+
$kind = ''
|
|
2602
|
+
for ($i = 0; $i -lt $Rest.Count; $i++) {
|
|
2603
|
+
switch ($Rest[$i]) {
|
|
2604
|
+
'--feature-dir' { $i++ }
|
|
2605
|
+
'--kind' { $kind = $Rest[++$i] }
|
|
2606
|
+
default { Write-Error "build-compile: unknown arg '$($Rest[$i])'"; exit 1 }
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2464
2609
|
|
|
2465
2610
|
# A DECLARED lane model is the answer, and it is a better answer than the ladder
|
|
2466
2611
|
# below in exactly the case that matters: a repo with two lanes. The sniffer takes
|
|
2467
2612
|
# the first toolchain it finds and silently never builds the second, which reports
|
|
2468
2613
|
# green for a frontend that was never compiled.
|
|
2469
2614
|
if ((Get-LaneField -Field 'lane_count') -and (Get-LaneField -Field 'lane_count') -ne '0') {
|
|
2470
|
-
|
|
2615
|
+
$phaseArgs = @('--phase', 'build')
|
|
2616
|
+
if ($kind) { $phaseArgs += @('--kind', $kind) }
|
|
2617
|
+
Invoke-AwStackCore -Op 'run-phase' -Rest $phaseArgs
|
|
2471
2618
|
return
|
|
2472
2619
|
}
|
|
2473
2620
|
|
|
@@ -2673,7 +2820,7 @@ function Invoke-RunMigrate {
|
|
|
2673
2820
|
return
|
|
2674
2821
|
}
|
|
2675
2822
|
|
|
2676
|
-
# WHERE to look for the migration project. The
|
|
2823
|
+
# WHERE to look for the migration project. The declared lane root folder of the service lane
|
|
2677
2824
|
# when there is one, 'src' when there is not. Migrations belong to the backend lane
|
|
2678
2825
|
# by definition, so a repo whose service code sits in 'Legacy/App/' or 'backend/'
|
|
2679
2826
|
# gets searched where its code actually is instead of being told it has no .NET
|
|
@@ -2691,7 +2838,7 @@ function Invoke-RunMigrate {
|
|
|
2691
2838
|
}
|
|
2692
2839
|
if ($efOk) {
|
|
2693
2840
|
# Prefer *Service.csproj (API host with ApplicationDbContext); fall back to first
|
|
2694
|
-
# non-AppHost/Web/ServiceDefaults/test project under the service lane
|
|
2841
|
+
# non-AppHost/Web/ServiceDefaults/test project under the service lane root folder.
|
|
2695
2842
|
$project = Get-ChildItem -LiteralPath $svcDir -Filter '*.Service.csproj' -Recurse -ErrorAction SilentlyContinue |
|
|
2696
2843
|
Select-Object -First 1 -ExpandProperty FullName
|
|
2697
2844
|
if (-not $project) {
|
|
@@ -4455,6 +4602,7 @@ switch ($sub) {
|
|
|
4455
4602
|
'set-context' { Invoke-SetContext -Rest $rest }
|
|
4456
4603
|
'list-features' { Invoke-ListFeatures -Rest $rest }
|
|
4457
4604
|
'set-feature' { Invoke-SetFeature -Rest $rest }
|
|
4605
|
+
'default-scope' { Invoke-DefaultScope -Rest $rest }
|
|
4458
4606
|
'version-read' { Invoke-VersionState 'read' $rest }
|
|
4459
4607
|
'version-init' { Invoke-VersionState 'init' $rest }
|
|
4460
4608
|
'version-bootstrap-done' { Invoke-VersionState 'bootstrap-done' $rest }
|
|
@@ -4494,10 +4642,16 @@ switch ($sub) {
|
|
|
4494
4642
|
'checklist-apply' { Invoke-ChecklistApply -Rest $rest }
|
|
4495
4643
|
'detect-project' { Invoke-DetectProject -Rest $rest }
|
|
4496
4644
|
'foundation-list' { Invoke-FoundationList -Rest $rest }
|
|
4645
|
+
'foundation-choice' { Invoke-FoundationChoice -Rest $rest }
|
|
4646
|
+
'foundation-spec-capture' { Invoke-FoundationSpecCapture -Rest $rest }
|
|
4647
|
+
'foundation-lane-files' { Invoke-FoundationLaneFiles -Rest $rest }
|
|
4648
|
+
'foundation-snapshot' { Invoke-FoundationSnapshot -Rest $rest }
|
|
4649
|
+
'foundation-outside' { Invoke-FoundationOutside -Rest $rest }
|
|
4497
4650
|
'foundation-locate' { Invoke-FoundationLocate -Rest $rest }
|
|
4498
4651
|
'foundation-unpack' { Invoke-FoundationUnpack -Rest $rest }
|
|
4499
4652
|
'foundation-verify' { Invoke-FoundationVerify -Rest $rest }
|
|
4500
|
-
'foundation-
|
|
4653
|
+
'foundation-rules' { Invoke-FoundationRules -Rest $rest }
|
|
4654
|
+
'foundation-rules-done' { Invoke-FoundationRulesDone -Rest $rest }
|
|
4501
4655
|
'list-components' { Invoke-ListComponents -Rest $rest }
|
|
4502
4656
|
'component-catalog' { Invoke-ComponentCatalog -Rest $rest }
|
|
4503
4657
|
'component-verify' { Invoke-ComponentVerify -Rest $rest }
|