aw-spec-cli 0.1.22 → 0.1.24

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 (48) hide show
  1. package/assets/.appweaver/ORCH-DIALECT.md +3 -3
  2. package/assets/.appweaver/RULE-PARTITION.md +41 -28
  3. package/assets/.appweaver/orchestrator/orchestrator.py +139 -17
  4. package/assets/.appweaver/orchestrator/rev-templates/ai-rules.reference.md +3 -3
  5. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +19 -12
  6. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +25 -17
  7. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
  8. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +10 -10
  9. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +28 -17
  10. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +22 -24
  11. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
  12. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +29 -19
  13. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +27 -20
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +184 -37
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +18 -0
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +19 -0
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +18 -0
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +1 -1
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +4 -1
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +5 -1
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +58 -43
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +650 -205
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +19 -0
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +3 -1
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +5 -5
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +2 -2
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +4 -1
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +34 -6
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +40 -1
  30. package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +23 -4
  31. package/assets/.appweaver/scripts/bash/aw-rev-constitution.sh +1 -1
  32. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +82 -10
  33. package/assets/.appweaver/scripts/powershell/aw-rev-constitution.ps1 +1 -1
  34. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +67 -2
  35. package/assets/.appweaver/scripts/python/aw-inventory.py +1809 -156
  36. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +106 -145
  37. package/assets/.appweaver/scripts/python/aw-stack.py +45 -1
  38. package/assets/.appweaver/scripts/python/aw-xref.py +73 -2
  39. package/assets/.appweaver/scripts/python/validate_okf.py +10 -5
  40. package/assets/.appweaver/templates/okf-concept-template.md +10 -2
  41. package/assets/.appweaver/templates/proposed-inventory-template.md +100 -48
  42. package/assets/.appweaver/templates/source-map-template.md +14 -6
  43. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +3 -3
  44. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +5 -123
  45. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +784 -0
  46. package/assets/foundations/java/Hexagonal/pack-foundation.sh +357 -0
  47. package/assets/foundations/java/Hexagonal/unpack-foundation.sh +399 -0
  48. package/package.json +1 -1
@@ -631,6 +631,9 @@ function Invoke-LaneResolve {
631
631
  for ($i = 0; $i -lt $Rest.Count; $i++) {
632
632
  switch ($Rest[$i]) {
633
633
  { $_ -in '--kind','--id' } { $fwd += $Rest[$i]; $fwd += $Rest[++$i] }
634
+ # An EMPTY --feature-dir is dropped: a workflow renders the argument whole, and a
635
+ # feature that is not resolved yet means "the repo's declaration as it stands".
636
+ '--feature-dir' { $v = $Rest[++$i]; if ($v) { $fwd += '--feature-dir'; $fwd += $v } }
634
637
  default { Write-Error "lane-resolve: unknown arg '$($Rest[$i])'"; exit 1 }
635
638
  }
636
639
  }
@@ -1084,6 +1087,31 @@ elif op == "init":
1084
1087
  d["bootstrap_pending"] = True
1085
1088
  save(d)
1086
1089
  out["created"] = (not existed)
1090
+ elif op == "lanes":
1091
+ # WHICH DECLARED LANES THIS FEATURE HAS A SURFACE IN. Absent means every lane the repo
1092
+ # declares, which is the ordinary case and needs no record. A feature that genuinely has
1093
+ # no part of one lane's surface — a job-only or shared-kernel slice in a repo that also
1094
+ # has a UI — records the kinds it does have, and `lane-resolve --feature-dir` then reports
1095
+ # the other lane as not declared FOR THIS FEATURE, so no phase plans, gates or builds a
1096
+ # surface the feature does not own. `all` removes the record; an empty value only reads.
1097
+ # Refuses to create the file: init is its one creator, and a record with no version
1098
+ # spine would read as a feature nobody specified.
1099
+ want = os.environ.get("AW_LANES", "").strip()
1100
+ if want and not existed:
1101
+ out["ok"] = False
1102
+ out["error"] = "no active_version.json for this feature yet — it is created by specify or adopt"
1103
+ elif want == "all":
1104
+ d.pop("lanes", None)
1105
+ save(d)
1106
+ elif want:
1107
+ kinds = [k.strip() for k in want.split(",") if k.strip()]
1108
+ bad = [k for k in kinds if k not in ("backend", "frontend")]
1109
+ if bad or not kinds:
1110
+ out["ok"] = False
1111
+ out["error"] = "lanes takes backend, frontend or both (comma-separated), or all; got '%s'" % want
1112
+ else:
1113
+ d["lanes"] = [k for k in ("backend", "frontend") if k in kinds]
1114
+ save(d)
1087
1115
  elif op == "bootstrap-done":
1088
1116
  # THE ONLY THING THAT CLEARS THE MARKER, called by the phase that raised it once the
1089
1117
  # first draft is actually finished. It is a separate op, not a side effect of writing
@@ -1183,6 +1211,7 @@ elif op == "close":
1183
1211
  out["previous"] = prev; out["closed_change"] = closed
1184
1212
  out["open_changes"] = opens; out["open_count"] = len(opens)
1185
1213
  out["bootstrap_pending"] = bool(d.get("bootstrap_pending"))
1214
+ out["lanes"] = list(d.get("lanes") or []) # empty = every declared lane
1186
1215
  out["has_change"] = bool(out.get("active_change", "")) # clean branch signal for design
1187
1216
  # What a close from THIS state would produce. One bump() authority, read by BOTH
1188
1217
  # finalize-delta (to write the right number into the Change History rows it appends)
@@ -1194,10 +1223,10 @@ print(json.dumps(out))
1194
1223
  '@
1195
1224
 
1196
1225
  function Invoke-ActiveVersion {
1197
- param([string]$FeatureDir, [string]$Op, [string]$CrId = '', [string]$Force = '', [string]$Boot = '')
1226
+ param([string]$FeatureDir, [string]$Op, [string]$CrId = '', [string]$Force = '', [string]$Boot = '', [string]$Lanes = '')
1198
1227
  $py = Get-Py; if (-not $py) { Write-Error "version-$Op`: python3 required"; exit 1 }
1199
1228
  $env:AW_FD = $FeatureDir; $env:AW_OP = $Op; $env:AW_CR = $CrId; $env:AW_FORCE = $Force
1200
- $env:AW_BOOT = $Boot
1229
+ $env:AW_BOOT = $Boot; $env:AW_LANES = $Lanes
1201
1230
  # CrId names the change on BOTH open and close: many may be open at once, so a close
1202
1231
  # has to say which one it is closing rather than assuming the only one.
1203
1232
  $PyActiveVersion | & $py -
@@ -1216,6 +1245,32 @@ function Invoke-VersionState { # op in read|init (feature-dir only)
1216
1245
  Invoke-ActiveVersion -FeatureDir $fd -Op $Op -Boot $boot
1217
1246
  }
1218
1247
 
1248
+ # The lane kinds this feature has a surface in, recorded in its active_version.json. Twin
1249
+ # of bash cmd_feature_lanes: adopt records `backend` for a slice that owns no part of a
1250
+ # declared frontend's surface, and `lane-resolve --feature-dir` reads it back. No argument
1251
+ # reads; --clear drops the record so the feature follows every declared lane again.
1252
+ function Invoke-FeatureLanes {
1253
+ param([string[]]$Rest)
1254
+ $fdArg = ''; $lanes = ''
1255
+ for ($i = 0; $i -lt $Rest.Count; $i++) {
1256
+ switch ($Rest[$i]) {
1257
+ { $_ -in '--feature-dir','-FeatureDir' } { $fdArg = $Rest[++$i] }
1258
+ '--set' { $lanes = $Rest[++$i] }
1259
+ '--clear' { $lanes = 'all' }
1260
+ default { Write-Error "feature-lanes: unknown arg '$($Rest[$i])'"; exit 1 }
1261
+ }
1262
+ }
1263
+ $repo = Get-RepoRoot
1264
+ $fd = Resolve-FeatureDir -Arg $fdArg -RepoRoot $repo
1265
+ if (-not $fd) { Write-Error 'feature-lanes: no feature set and no --feature-dir'; exit 1 }
1266
+ $out = Invoke-ActiveVersion -FeatureDir $fd -Op 'lanes' -Lanes $lanes
1267
+ $out
1268
+ # A refused write is a failure the caller has to see: the orchestrator reports a failed
1269
+ # script from stderr, so the reason goes there too.
1270
+ $res = $out | ConvertFrom-Json
1271
+ if (-not $res.ok) { [Console]::Error.WriteLine("feature-lanes: $($res.error)"); exit 1 }
1272
+ }
1273
+
1219
1274
 
1220
1275
 
1221
1276
  # ─────────────────────────── feature-paths ─────────────────────────────────
@@ -1230,6 +1285,14 @@ function Invoke-FeaturePaths {
1230
1285
  if (-not $fd) { Write-Error 'feature-paths: no feature set (run /appweaver select-feature first)'; exit 1 }
1231
1286
  if (-not [System.IO.Path]::IsPathRooted($fd)) { $fd = Join-Path $repo $fd }
1232
1287
  $feature = Split-Path $fd -Leaf # the aggregate name (feature = specs/<Feature>)
1288
+ # feature_slug is the URL-safe form of that name, and it is what the UI stages use
1289
+ # as a route segment and a directory name (app/<slug>/page.tsx). It is derived here
1290
+ # rather than per workflow so every reader gets the same segment for one feature.
1291
+ # CamelCase splits on the case boundary before the non-alphanumeric squeeze, so
1292
+ # OrderManagement and "Order Management" both reach order-management.
1293
+ $featureSlug = $feature -creplace '([a-z0-9])([A-Z])', '$1-$2'
1294
+ $featureSlug = $featureSlug -creplace '([A-Z]+)([A-Z][a-z])', '$1-$2'
1295
+ $featureSlug = ($featureSlug.ToLowerInvariant() -replace '[^a-z0-9]+', '-').Trim('-')
1233
1296
  # The master documents of a feature: spec.md (WHAT/WHY) + one LANE PLAN per declared
1234
1297
  # lane (each lane's HOW) — backend-plan.md for the service lane, frontend-plan.md for
1235
1298
  # the frontend lane. `plan` writes them; nothing else does.
@@ -1264,6 +1327,7 @@ function Invoke-FeaturePaths {
1264
1327
  $specExists = (Test-Path $spec)
1265
1328
  Write-Json ([ordered]@{
1266
1329
  feature = $feature
1330
+ feature_slug = $featureSlug
1267
1331
  feature_dir = $fd
1268
1332
  spec_file = $spec
1269
1333
  backend_plan = $design
@@ -4394,6 +4458,7 @@ switch ($sub) {
4394
4458
  'version-read' { Invoke-VersionState 'read' $rest }
4395
4459
  'version-init' { Invoke-VersionState 'init' $rest }
4396
4460
  'version-bootstrap-done' { Invoke-VersionState 'bootstrap-done' $rest }
4461
+ 'feature-lanes' { Invoke-FeatureLanes -Rest $rest }
4397
4462
  'feature-paths' { Invoke-FeaturePaths -Rest $rest }
4398
4463
  'design-scaffold' { Invoke-DesignScaffold -Rest $rest }
4399
4464
  # The plan phase's name for the same op. Both spellings reach one implementation: