aw-spec-cli 0.1.15 → 0.1.17
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/.appweaver/DESIGN-FORMAT.md +18 -18
- package/assets/.appweaver/ORCH-DIALECT.md +1 -3
- package/assets/.appweaver/RULE-PARTITION.md +29 -13
- package/assets/.appweaver/STACK-PROFILES.md +10 -9
- package/assets/.appweaver/orchestrator/.state/smoke.state.json +32 -0
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +4 -1
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +251 -0
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +104 -35
- package/assets/.appweaver/orchestrator/orchestrator.py +5 -4
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +94 -36
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/domain-model-template.skeleton.md +115 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +2 -9
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +16 -40
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +38 -17
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +8 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +10 -11
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +673 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +535 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +643 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +78 -626
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +7 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +16 -14
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +243 -144
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +882 -464
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +32 -91
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +832 -477
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +2 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +132 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +38 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +271 -892
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +1096 -2911
- package/assets/.appweaver/scripts/bash/aw-xref.sh +1 -2
- package/assets/.appweaver/scripts/bash/common.sh +47 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +936 -2766
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +1 -2
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +174 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +6 -2
- package/assets/.appweaver/scripts/python/aw-xref.py +185 -292
- package/assets/.appweaver/templates/constitution-ui-template.md +1 -1
- package/assets/.appweaver/templates/delta-design-template.md +120 -30
- package/assets/.appweaver/templates/delta-domain-model-template.md +81 -0
- package/assets/.appweaver/templates/delta-spec-template.md +43 -17
- package/assets/.appweaver/templates/design-template.md +68 -98
- package/assets/.appweaver/templates/domain-model-template.md +130 -0
- package/assets/.appweaver/templates/okf-concept-template.md +2 -2
- package/assets/.appweaver/templates/source-map-template.md +3 -3
- package/assets/.appweaver/templates/spec-template.md +100 -122
- package/assets/.appweaver/templates/ui-delta-design-template.md +159 -0
- package/assets/.appweaver/templates/ui-design-template.md +46 -75
- package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +7 -18
- package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +34 -39
- package/assets/guardrails/requirement-spec.txt +2 -2
- package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
- package/package.json +1 -1
- package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +0 -105
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +0 -251
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +0 -749
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +0 -253
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +0 -540
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan-ui.orch.yaml +0 -597
- package/assets/.appweaver/orchestrator/workflows/aw-spec-story-plan.orch.yaml +0 -945
- package/assets/.appweaver/orchestrator/workflows/aw-spec-sync-stories.orch.yaml +0 -1040
- package/assets/.appweaver/templates/story-template.md +0 -147
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
#
|
|
7
7
|
# aw-xref.ps1 record --using X --design <design.md> [--origin ...] [--date YYYY-MM-DD] [--root DIR]
|
|
8
8
|
# aw-xref.ps1 list --aggregate Y [--root DIR] [--bundle knowledge]
|
|
9
|
-
# aw-xref.ps1 concept-upsert --aggregate X [--source-files a,b,c] [--
|
|
9
|
+
# aw-xref.ps1 concept-upsert --aggregate X [--source-files a,b,c] [--description D] [--origin ...] [--root DIR]
|
|
10
10
|
# aw-xref.ps1 concept-overview --aggregate X (--text PROSE | --text-file F) [--root DIR]
|
|
11
11
|
# aw-xref.ps1 concept-paths --aggregate X | --feature-dir <dir> [--root DIR] [--bundle knowledge]
|
|
12
|
-
# aw-xref.ps1 concept-coverage --aggregate X | --feature-dir <dir> [--ids "FR-001,BR-002"] [--max-list N] [--root DIR] [--bundle knowledge]
|
|
13
12
|
$ErrorActionPreference = "Stop"
|
|
14
13
|
$core = Join-Path $PSScriptRoot "..\python\aw-xref.py"
|
|
15
14
|
& python3 $core @args
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""aw-payload-parity.py — prove the two shells run the SAME python.
|
|
3
|
+
|
|
4
|
+
Most of aw-spec-actions is one python program embedded twice: as a `<<'PY'` heredoc in
|
|
5
|
+
aw-spec-actions.sh and as a `$PyName = @'…'@` here-string in aw-spec-actions.ps1. The
|
|
6
|
+
contract is that each pair is BYTE-IDENTICAL, and nothing checked it — so a fix applied to
|
|
7
|
+
one shell and forgotten in the other is a gate that behaves differently on Windows, in
|
|
8
|
+
silence. Three of the ops with no twin at all are on the forward chain (resolve-hooks, with
|
|
9
|
+
call sites in 21 of the workflows, and checklist-read / checklist-apply, which produce the
|
|
10
|
+
analyze phases' LIFT-FAILURE findings), and every one of them was read in bash when the
|
|
11
|
+
workflows were reviewed.
|
|
12
|
+
|
|
13
|
+
WHAT IT CHECKS
|
|
14
|
+
1. Every bash payload has a byte-identical PowerShell twin.
|
|
15
|
+
2. Every PowerShell payload has a byte-identical bash twin.
|
|
16
|
+
Payloads with no twin are listed, not counted against a hard-coded number: the split is
|
|
17
|
+
whatever the files say today, and pinning it would need editing on every legitimate change.
|
|
18
|
+
|
|
19
|
+
DUAL-AUTHORED BY DECISION. The ops in ACCEPTED_BASH_ONLY are bash-only on purpose (their
|
|
20
|
+
PowerShell path is written natively rather than shared) and are reported separately, so the
|
|
21
|
+
exit code reacts only to a NEW divergence. Moving one out of that list means it gained a
|
|
22
|
+
shared payload; adding one means the decision was taken to dual-author it — and either way
|
|
23
|
+
the reviewer has to say so in the same commit.
|
|
24
|
+
|
|
25
|
+
exit 0 every payload is paired, or unpaired only by accepted decision
|
|
26
|
+
exit 1 a new unpaired payload, or a pair that has drifted apart
|
|
27
|
+
|
|
28
|
+
Usage: aw-payload-parity.py [--root DIR] [--verbose]
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import argparse
|
|
32
|
+
import hashlib
|
|
33
|
+
import os
|
|
34
|
+
import re
|
|
35
|
+
import sys
|
|
36
|
+
|
|
37
|
+
SH_REL = ".appweaver/scripts/bash/aw-spec-actions.sh"
|
|
38
|
+
PS_REL = ".appweaver/scripts/powershell/aw-spec-actions.ps1"
|
|
39
|
+
|
|
40
|
+
# Bash payloads with no shared PowerShell twin BY DECISION, not by oversight. Each is
|
|
41
|
+
# implemented natively on the PowerShell side and the two must be reviewed in pairs.
|
|
42
|
+
ACCEPTED_BASH_ONLY = {
|
|
43
|
+
"cmd_resolve_hooks",
|
|
44
|
+
"cmd_list_contexts",
|
|
45
|
+
"cmd_context_paths",
|
|
46
|
+
"cmd_list_features",
|
|
47
|
+
# The two change-listing ops. Both walk changes/<cr-id>/ and read a header line out of
|
|
48
|
+
# each delta document — directory enumeration and a regex, which PowerShell does
|
|
49
|
+
# natively without paying for a python spawn per invocation. Short enough to review as
|
|
50
|
+
# a pair, which is the bar for this list.
|
|
51
|
+
"cmd_cr_list",
|
|
52
|
+
"cmd_cr_paths",
|
|
53
|
+
# Aggregate overlap between open model deltas: two markdown regexes over a directory
|
|
54
|
+
# listing. Native on both sides for the same reason as the pair above.
|
|
55
|
+
"cmd_cr_overlap",
|
|
56
|
+
# Header stamping and wave discovery are a few lines of regex over a markdown header.
|
|
57
|
+
# PowerShell does that natively at a fraction of the cost of spawning python, and both
|
|
58
|
+
# sides are short enough to review as a pair — which is the bar for this list.
|
|
59
|
+
"_stamp_header",
|
|
60
|
+
"_max_open_wave",
|
|
61
|
+
"cmd_checklist_read",
|
|
62
|
+
"cmd_checklist_apply",
|
|
63
|
+
"cmd_compose_constitution",
|
|
64
|
+
"cmd_constitution_verify",
|
|
65
|
+
"cmd_component_verify",
|
|
66
|
+
"cmd_cr_archive",
|
|
67
|
+
"cmd_version_stamp",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def bash_payloads(text):
|
|
72
|
+
"""[(owning function, payload, first line, last line)] in file order."""
|
|
73
|
+
out, owner, lines, i = [], "(top level)", text.split("\n"), 0
|
|
74
|
+
while i < len(lines):
|
|
75
|
+
m = re.match(r"^([A-Za-z_][A-Za-z0-9_]*)\(\)\s*\{", lines[i])
|
|
76
|
+
if m:
|
|
77
|
+
owner = m.group(1)
|
|
78
|
+
if re.search(r"<<'PY'\s*$", lines[i]):
|
|
79
|
+
j, body = i + 1, []
|
|
80
|
+
while j < len(lines) and lines[j] != "PY":
|
|
81
|
+
body.append(lines[j])
|
|
82
|
+
j += 1
|
|
83
|
+
out.append((owner, "\n".join(body), i + 2, j))
|
|
84
|
+
i = j
|
|
85
|
+
i += 1
|
|
86
|
+
return out
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def ps_payloads(text):
|
|
90
|
+
"""[(variable name, payload, first line, last line)] in file order."""
|
|
91
|
+
out, lines, i = [], text.split("\n"), 0
|
|
92
|
+
while i < len(lines):
|
|
93
|
+
m = re.match(r"^\$(Py[A-Za-z0-9_]*)\s*=\s*@'\s*$", lines[i])
|
|
94
|
+
if m:
|
|
95
|
+
j, body = i + 1, []
|
|
96
|
+
while j < len(lines) and lines[j] != "'@":
|
|
97
|
+
body.append(lines[j])
|
|
98
|
+
j += 1
|
|
99
|
+
out.append((m.group(1), "\n".join(body), i + 2, j))
|
|
100
|
+
i = j
|
|
101
|
+
i += 1
|
|
102
|
+
return out
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def digest(s):
|
|
106
|
+
return hashlib.sha256(s.encode("utf-8")).hexdigest()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def main():
|
|
110
|
+
ap = argparse.ArgumentParser(description="check bash/PowerShell python-payload parity")
|
|
111
|
+
ap.add_argument("--root", default="", help="kit root (default: this script's kit)")
|
|
112
|
+
ap.add_argument("--verbose", action="store_true", help="list every matched pair too")
|
|
113
|
+
args = ap.parse_args()
|
|
114
|
+
|
|
115
|
+
root = args.root or os.path.normpath(
|
|
116
|
+
os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", ".."))
|
|
117
|
+
sh_path, ps_path = os.path.join(root, SH_REL), os.path.join(root, PS_REL)
|
|
118
|
+
for p in (sh_path, ps_path):
|
|
119
|
+
if not os.path.isfile(p):
|
|
120
|
+
print("aw-payload-parity: not found: %s" % p, file=sys.stderr)
|
|
121
|
+
return 2
|
|
122
|
+
|
|
123
|
+
sh = bash_payloads(open(sh_path, encoding="utf-8").read())
|
|
124
|
+
ps = ps_payloads(open(ps_path, encoding="utf-8").read())
|
|
125
|
+
|
|
126
|
+
ps_by_hash = {}
|
|
127
|
+
for name, body, a, b in ps:
|
|
128
|
+
ps_by_hash.setdefault(digest(body), []).append((name, a, b))
|
|
129
|
+
sh_by_hash = {}
|
|
130
|
+
for owner, body, a, b in sh:
|
|
131
|
+
sh_by_hash.setdefault(digest(body), []).append((owner, a, b))
|
|
132
|
+
|
|
133
|
+
paired, accepted, unpaired_sh, unpaired_ps = [], [], [], []
|
|
134
|
+
for owner, body, a, b in sh:
|
|
135
|
+
twin = ps_by_hash.get(digest(body))
|
|
136
|
+
if twin:
|
|
137
|
+
paired.append((owner, twin[0][0]))
|
|
138
|
+
elif owner in ACCEPTED_BASH_ONLY:
|
|
139
|
+
accepted.append((owner, a, b))
|
|
140
|
+
else:
|
|
141
|
+
unpaired_sh.append((owner, a, b))
|
|
142
|
+
for name, body, a, b in ps:
|
|
143
|
+
if not sh_by_hash.get(digest(body)):
|
|
144
|
+
unpaired_ps.append((name, a, b))
|
|
145
|
+
|
|
146
|
+
print("payload parity: %d bash, %d powershell, %d byte-identical pair(s)"
|
|
147
|
+
% (len(sh), len(ps), len(paired)))
|
|
148
|
+
if args.verbose:
|
|
149
|
+
for owner, name in paired:
|
|
150
|
+
print(" ok %-34s == $%s" % (owner, name))
|
|
151
|
+
if accepted:
|
|
152
|
+
print("\ndual-authored by decision (%d) — PowerShell implements these natively, so a "
|
|
153
|
+
"change to one must be mirrored by hand:" % len(accepted))
|
|
154
|
+
for owner, a, b in accepted:
|
|
155
|
+
print(" -- %-34s %s:%d-%d" % (owner, os.path.basename(sh_path), a, b))
|
|
156
|
+
|
|
157
|
+
failed = bool(unpaired_sh or unpaired_ps)
|
|
158
|
+
if unpaired_sh:
|
|
159
|
+
print("\nFAIL — bash payloads with no byte-identical PowerShell twin:")
|
|
160
|
+
for owner, a, b in unpaired_sh:
|
|
161
|
+
print(" !! %-34s %s:%d-%d" % (owner, os.path.basename(sh_path), a, b))
|
|
162
|
+
if unpaired_ps:
|
|
163
|
+
print("\nFAIL — PowerShell payloads with no byte-identical bash twin:")
|
|
164
|
+
for name, a, b in unpaired_ps:
|
|
165
|
+
print(" !! $%-33s %s:%d-%d" % (name, os.path.basename(ps_path), a, b))
|
|
166
|
+
if failed:
|
|
167
|
+
print("\nA payload changed in one shell and not the other, or a new op shipped to one "
|
|
168
|
+
"shell only. Copy the payload verbatim into its twin — they are byte-identical "
|
|
169
|
+
"by contract — or, if the op is deliberately dual-authored, add its function to "
|
|
170
|
+
"ACCEPTED_BASH_ONLY in this file and say why in the commit.")
|
|
171
|
+
return 1 if failed else 0
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
sys.exit(main())
|
|
@@ -901,9 +901,13 @@ def cmd_resolve(args):
|
|
|
901
901
|
# when implement writes into it. Every phase that READS the subtree — implement,
|
|
902
902
|
# build, run, onboard — leaves the check on.
|
|
903
903
|
|
|
904
|
+
# Named in the "no <kind> lane is declared, and %s needs one" message, for a caller that
|
|
905
|
+
# passed --require but no --command of its own. `implement` covers both lanes in one
|
|
906
|
+
# command and requires neither kind, so it passes no --require at all and never reaches
|
|
907
|
+
# these.
|
|
904
908
|
KIND_PHASES = {
|
|
905
|
-
"backend": "implement
|
|
906
|
-
"frontend": "
|
|
909
|
+
"backend": "implement's service lane / build / run",
|
|
910
|
+
"frontend": "implement's frontend lane",
|
|
907
911
|
}
|
|
908
912
|
|
|
909
913
|
|