aw-spec-cli 0.1.21 → 0.1.23
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/STACK-PROFILES.md +87 -8
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +30 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +47 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +41 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +62 -2
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +18 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +4 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +115 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +5 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +225 -27
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -15
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +39 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +28 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +3 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +104 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +159 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +386 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +153 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +203 -212
- package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +191 -224
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +4 -1
- package/assets/.appweaver/scripts/python/aw-crstate.py +127 -2
- package/assets/.appweaver/scripts/python/aw-gaps.py +119 -0
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +17 -1
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +84 -4
- package/assets/.appweaver/scripts/python/aw-plangate.py +216 -0
- package/assets/.appweaver/scripts/python/aw-principles.py +108 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +6 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +141 -4
- package/assets/.appweaver/stack-profiles/angular.json +26 -0
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +38 -0
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +38 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +19 -0
- package/assets/.appweaver/stack-profiles/nextjs.json +26 -0
- package/assets/.appweaver/stack-profiles/node-express.json +26 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +15 -0
- package/assets/.appweaver/stack-profiles/react-vite.json +26 -0
- package/assets/.appweaver/stack-profiles/sveltekit.json +26 -0
- package/assets/.appweaver/stack-profiles/vue-vite.json +26 -0
- package/assets/.appweaver/templates/ui-model-template.md +67 -0
- package/assets/.appweaver/templates/workflow-model-template.md +62 -0
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +3 -3
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +5 -123
- package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +784 -0
- package/assets/foundations/java/Hexagonal/pack-foundation.sh +357 -0
- package/assets/foundations/java/Hexagonal/unpack-foundation.sh +399 -0
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +44 -0
- package/package.json +1 -1
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# pack-foundation.sh — Java foundation packer for AW-Spec
|
|
4
|
+
#
|
|
5
|
+
# Packs the Java Hexagonal foundation into a single AW-Spec foundation pack.
|
|
6
|
+
#
|
|
7
|
+
# Source foundation:
|
|
8
|
+
# foundation/appweaver.hexagonal
|
|
9
|
+
#
|
|
10
|
+
# The packer does NOT rename the Java package.
|
|
11
|
+
# The Java package replacement is performed during unpacking.
|
|
12
|
+
#
|
|
13
|
+
# Java foundation sentinel:
|
|
14
|
+
# io.appweaver
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
# ./pack-foundation.sh \
|
|
18
|
+
# --source-dir /path/to/appweaver-java-library/foundation/appweaver.hexagonal \
|
|
19
|
+
# --out-file ./Hexagonal.pack.txt
|
|
20
|
+
#
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
# ------------------------------------------------------------------ defaults ---
|
|
25
|
+
|
|
26
|
+
SENTINEL='io.appweaver'
|
|
27
|
+
FOUNDATION='Hexagonal'
|
|
28
|
+
SOURCE_DIR=''
|
|
29
|
+
OUT_FILE=''
|
|
30
|
+
ALLOW_SECRETS=0
|
|
31
|
+
|
|
32
|
+
usage() {
|
|
33
|
+
cat >&2 <<'EOF'
|
|
34
|
+
Usage: pack-foundation.sh --source-dir <dir> [--out-file <file>]
|
|
35
|
+
[--sentinel <name>] [--foundation <name>]
|
|
36
|
+
[--allow-secrets]
|
|
37
|
+
|
|
38
|
+
-s, --source-dir <dir> Java foundation directory (required)
|
|
39
|
+
-o, --out-file <file> Output pack file (default: ./Hexagonal.pack.txt)
|
|
40
|
+
--sentinel <name> Java package sentinel (default: io.appweaver)
|
|
41
|
+
--foundation <name> Foundation name (default: Hexagonal)
|
|
42
|
+
--allow-secrets Pack even if credential markers exist
|
|
43
|
+
-h, --help Show this help
|
|
44
|
+
|
|
45
|
+
Positional fallback:
|
|
46
|
+
pack-foundation.sh <source-dir> [out-file]
|
|
47
|
+
EOF
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# -------------------------------------------------------------- argument parsing
|
|
51
|
+
|
|
52
|
+
while [ $# -gt 0 ]; do
|
|
53
|
+
case "$1" in
|
|
54
|
+
-s|--source-dir)
|
|
55
|
+
SOURCE_DIR="${2:?--source-dir needs a value}"
|
|
56
|
+
shift 2
|
|
57
|
+
;;
|
|
58
|
+
|
|
59
|
+
-o|--out-file)
|
|
60
|
+
OUT_FILE="${2:?--out-file needs a value}"
|
|
61
|
+
shift 2
|
|
62
|
+
;;
|
|
63
|
+
|
|
64
|
+
--sentinel)
|
|
65
|
+
SENTINEL="${2:?--sentinel needs a value}"
|
|
66
|
+
shift 2
|
|
67
|
+
;;
|
|
68
|
+
|
|
69
|
+
--foundation)
|
|
70
|
+
FOUNDATION="${2:?--foundation needs a value}"
|
|
71
|
+
shift 2
|
|
72
|
+
;;
|
|
73
|
+
|
|
74
|
+
--allow-secrets)
|
|
75
|
+
ALLOW_SECRETS=1
|
|
76
|
+
shift
|
|
77
|
+
;;
|
|
78
|
+
|
|
79
|
+
-h|--help)
|
|
80
|
+
usage
|
|
81
|
+
exit 0
|
|
82
|
+
;;
|
|
83
|
+
|
|
84
|
+
--)
|
|
85
|
+
shift
|
|
86
|
+
break
|
|
87
|
+
;;
|
|
88
|
+
|
|
89
|
+
-*)
|
|
90
|
+
echo "Error: unknown option: $1" >&2
|
|
91
|
+
usage
|
|
92
|
+
exit 2
|
|
93
|
+
;;
|
|
94
|
+
|
|
95
|
+
*)
|
|
96
|
+
if [ -z "$SOURCE_DIR" ]; then
|
|
97
|
+
SOURCE_DIR="$1"
|
|
98
|
+
elif [ -z "$OUT_FILE" ]; then
|
|
99
|
+
OUT_FILE="$1"
|
|
100
|
+
else
|
|
101
|
+
echo "Error: unexpected argument: $1" >&2
|
|
102
|
+
usage
|
|
103
|
+
exit 2
|
|
104
|
+
fi
|
|
105
|
+
shift
|
|
106
|
+
;;
|
|
107
|
+
esac
|
|
108
|
+
done
|
|
109
|
+
|
|
110
|
+
[ -n "$SOURCE_DIR" ] || {
|
|
111
|
+
echo "Error: --source-dir is required." >&2
|
|
112
|
+
usage
|
|
113
|
+
exit 2
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
[ -d "$SOURCE_DIR" ] || {
|
|
117
|
+
echo "Error: SourceDir is not a folder: $SOURCE_DIR" >&2
|
|
118
|
+
exit 1
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
SRC="$(cd "$SOURCE_DIR" && pwd -P)"
|
|
122
|
+
|
|
123
|
+
[ -n "$OUT_FILE" ] || {
|
|
124
|
+
OUT_FILE="$(pwd)/$FOUNDATION.pack.txt"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# -------------------------------------------------------------- exclusions ------
|
|
128
|
+
|
|
129
|
+
# Java/Maven/IDE/build artifacts that should never be included in the foundation.
|
|
130
|
+
EXCLUDE_DIRS=(
|
|
131
|
+
target
|
|
132
|
+
.gradle
|
|
133
|
+
.git
|
|
134
|
+
.idea
|
|
135
|
+
.vscode
|
|
136
|
+
.settings
|
|
137
|
+
TestResults
|
|
138
|
+
logs
|
|
139
|
+
artifacts
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
EXCLUDE_FILES=(
|
|
143
|
+
'*.class'
|
|
144
|
+
'*.log'
|
|
145
|
+
'*.db'
|
|
146
|
+
'*.db-shm'
|
|
147
|
+
'*.db-wal'
|
|
148
|
+
'*.sqlite'
|
|
149
|
+
'.env.*'
|
|
150
|
+
'*.pfx'
|
|
151
|
+
'*.pem'
|
|
152
|
+
'*.key'
|
|
153
|
+
'*.snk'
|
|
154
|
+
'id_rsa'
|
|
155
|
+
'id_rsa.pub'
|
|
156
|
+
'secrets.json'
|
|
157
|
+
'.DS_Store'
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# -------------------------------------------------------------- secret patterns -
|
|
161
|
+
|
|
162
|
+
SECRET_NAMES=(
|
|
163
|
+
'Private key block'
|
|
164
|
+
'AWS access key id'
|
|
165
|
+
'Azure DevOps PAT-ish'
|
|
166
|
+
'Generic password assignment'
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
SECRET_RX=(
|
|
170
|
+
'BEGIN (RSA |OPENSSH |EC |DSA )?PRIVATE KEY'
|
|
171
|
+
'AKIA[0-9A-Z]{16}'
|
|
172
|
+
'[A-Za-z0-9]{52}AZDO[A-Za-z0-9]'
|
|
173
|
+
'password[[:space:]]*=[[:space:]]*["'\''][^"'\'']+'
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
is_excluded() {
|
|
177
|
+
local rel="$1"
|
|
178
|
+
local seg leaf g
|
|
179
|
+
local -a segs
|
|
180
|
+
|
|
181
|
+
IFS='/' read -ra segs <<< "$rel"
|
|
182
|
+
|
|
183
|
+
for seg in "${segs[@]}"; do
|
|
184
|
+
for g in "${EXCLUDE_DIRS[@]}"; do
|
|
185
|
+
[ "$seg" = "$g" ] && return 0
|
|
186
|
+
done
|
|
187
|
+
done
|
|
188
|
+
|
|
189
|
+
leaf="${rel##*/}"
|
|
190
|
+
|
|
191
|
+
for g in "${EXCLUDE_FILES[@]}"; do
|
|
192
|
+
case "$leaf" in
|
|
193
|
+
$g)
|
|
194
|
+
return 0
|
|
195
|
+
;;
|
|
196
|
+
esac
|
|
197
|
+
done
|
|
198
|
+
|
|
199
|
+
return 1
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
is_binary() {
|
|
203
|
+
local f="$1"
|
|
204
|
+
local n1 n2
|
|
205
|
+
|
|
206
|
+
n1="$(head -c 8000 "$f" | wc -c | tr -d '[:space:]')"
|
|
207
|
+
n2="$(head -c 8000 "$f" | LC_ALL=C tr -d '\000' | wc -c | tr -d '[:space:]')"
|
|
208
|
+
|
|
209
|
+
[ "$n1" != "$n2" ]
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# ----------------------------------------------------------- collect + sort -----
|
|
213
|
+
|
|
214
|
+
picked_files=()
|
|
215
|
+
picked_dirs=()
|
|
216
|
+
|
|
217
|
+
# Collect files.
|
|
218
|
+
while IFS= read -r full; do
|
|
219
|
+
rel="${full#"$SRC"}"
|
|
220
|
+
rel="${rel#/}"
|
|
221
|
+
|
|
222
|
+
[ -n "$rel" ] || continue
|
|
223
|
+
|
|
224
|
+
is_excluded "$rel" && continue
|
|
225
|
+
|
|
226
|
+
picked_files+=("$rel")
|
|
227
|
+
done < <(find "$SRC" -type f | LC_ALL=C sort)
|
|
228
|
+
|
|
229
|
+
# Collect directories.
|
|
230
|
+
#
|
|
231
|
+
# All non-excluded directories are packed so that empty directories
|
|
232
|
+
# are preserved during unpacking.
|
|
233
|
+
while IFS= read -r full; do
|
|
234
|
+
rel="${full#"$SRC"}"
|
|
235
|
+
rel="${rel#/}"
|
|
236
|
+
|
|
237
|
+
# Do not include the source root itself.
|
|
238
|
+
[ -n "$rel" ] || continue
|
|
239
|
+
|
|
240
|
+
is_excluded "$rel" && continue
|
|
241
|
+
|
|
242
|
+
picked_dirs+=("$rel")
|
|
243
|
+
done < <(find "$SRC" -type d | LC_ALL=C sort)
|
|
244
|
+
|
|
245
|
+
[ "${#picked_files[@]}" -gt 0 ] || {
|
|
246
|
+
echo "Error: No files to pack under: $SRC" >&2
|
|
247
|
+
exit 1
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
# ----------------------------------------------------------- secret scan --------
|
|
251
|
+
|
|
252
|
+
findings=()
|
|
253
|
+
|
|
254
|
+
for rel in "${picked_files[@]}"; do
|
|
255
|
+
f="$SRC/$rel"
|
|
256
|
+
|
|
257
|
+
for i in "${!SECRET_RX[@]}"; do
|
|
258
|
+
if LC_ALL=C grep -aEq -- "${SECRET_RX[$i]}" "$f" 2>/dev/null; then
|
|
259
|
+
findings+=(" $rel -> ${SECRET_NAMES[$i]}")
|
|
260
|
+
fi
|
|
261
|
+
done
|
|
262
|
+
done
|
|
263
|
+
|
|
264
|
+
if [ "${#findings[@]}" -gt 0 ]; then
|
|
265
|
+
|
|
266
|
+
if [ "$ALLOW_SECRETS" -eq 1 ]; then
|
|
267
|
+
echo "WARNING: Potential secret(s) detected — packing anyway:" >&2
|
|
268
|
+
printf '%s\n' "${findings[@]}" >&2
|
|
269
|
+
else
|
|
270
|
+
echo "Error: Potential secret(s) detected — refusing to pack:" >&2
|
|
271
|
+
printf '%s\n' "${findings[@]}" >&2
|
|
272
|
+
echo "Remove the secrets or use --allow-secrets if this is intentional." >&2
|
|
273
|
+
exit 1
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
# ----------------------------------------------------------- sentinel check ------
|
|
279
|
+
|
|
280
|
+
hits=0
|
|
281
|
+
|
|
282
|
+
for rel in "${picked_files[@]}"; do
|
|
283
|
+
if LC_ALL=C grep -aFq -- "$SENTINEL" "$SRC/$rel" 2>/dev/null; then
|
|
284
|
+
hits=$((hits + 1))
|
|
285
|
+
fi
|
|
286
|
+
done
|
|
287
|
+
|
|
288
|
+
if [ "$hits" -eq 0 ]; then
|
|
289
|
+
echo "WARNING: Sentinel '$SENTINEL' not found in any file." >&2
|
|
290
|
+
echo "Expected Java foundation package references such as:" >&2
|
|
291
|
+
echo " package io.appweaver...." >&2
|
|
292
|
+
else
|
|
293
|
+
echo "Sentinel '$SENTINEL' found in $hits file(s)."
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
# ----------------------------------------------------------- write the pack ------
|
|
297
|
+
|
|
298
|
+
outdir="$(dirname "$OUT_FILE")"
|
|
299
|
+
|
|
300
|
+
[ -d "$outdir" ] || mkdir -p "$outdir"
|
|
301
|
+
|
|
302
|
+
{
|
|
303
|
+
printf '%s\n' '# AW-SPEC FOUNDATION PACK'
|
|
304
|
+
printf '# foundation: %s\n' "$FOUNDATION"
|
|
305
|
+
printf '# sentinel: %s\n' "$SENTINEL"
|
|
306
|
+
printf '# generated: %s\n' "$(date -u +%Y-%m-%dT%H:%M:%S.0000000Z)"
|
|
307
|
+
printf '# files: %s\n' "${#picked_files[@]}"
|
|
308
|
+
printf '# directories: %s\n' "${#picked_dirs[@]}"
|
|
309
|
+
printf '%s\n' '# format: aw-spec-pack/v1'
|
|
310
|
+
printf '%s\n' '# --- Java foundation replacement contract ---'
|
|
311
|
+
printf '%s\n' '# Java content: io.appweaver -> <lowercase-app-name>'
|
|
312
|
+
printf '%s\n' '# Java path: io/appweaver -> <lowercase-app-name>'
|
|
313
|
+
printf '%s\n' '# Application directory preserves the user-provided name.'
|
|
314
|
+
printf '%s\n' '# ============================================================'
|
|
315
|
+
printf '\n'
|
|
316
|
+
} > "$OUT_FILE"
|
|
317
|
+
|
|
318
|
+
# ----------------------------------------------------------- write directories ---
|
|
319
|
+
|
|
320
|
+
for rel in "${picked_dirs[@]}"; do
|
|
321
|
+
{
|
|
322
|
+
printf '<<<DIR path="%s">>>\n' "$rel"
|
|
323
|
+
printf '%s\n' '<<<ENDDIR>>>'
|
|
324
|
+
} >> "$OUT_FILE"
|
|
325
|
+
done
|
|
326
|
+
|
|
327
|
+
# ----------------------------------------------------------- write files ---------
|
|
328
|
+
|
|
329
|
+
for rel in "${picked_files[@]}"; do
|
|
330
|
+
|
|
331
|
+
f="$SRC/$rel"
|
|
332
|
+
|
|
333
|
+
if is_binary "$f"; then
|
|
334
|
+
|
|
335
|
+
{
|
|
336
|
+
printf '<<<FILE path="%s" encoding="base64">>>\n' "$rel"
|
|
337
|
+
base64 < "$f" | tr -d '\n'
|
|
338
|
+
printf '\n'
|
|
339
|
+
printf '%s\n' '<<<ENDFILE>>>'
|
|
340
|
+
} >> "$OUT_FILE"
|
|
341
|
+
|
|
342
|
+
else
|
|
343
|
+
|
|
344
|
+
{
|
|
345
|
+
printf '<<<FILE path="%s">>>\n' "$rel"
|
|
346
|
+
|
|
347
|
+
# Normalize CRLF -> LF.
|
|
348
|
+
awk '{ sub(/\r$/, ""); print }' "$f"
|
|
349
|
+
|
|
350
|
+
printf '%s\n' '<<<ENDFILE>>>'
|
|
351
|
+
} >> "$OUT_FILE"
|
|
352
|
+
|
|
353
|
+
fi
|
|
354
|
+
|
|
355
|
+
done
|
|
356
|
+
|
|
357
|
+
echo "Packed ${#picked_files[@]} file(s) and ${#picked_dirs[@]} directorie(s) -> $OUT_FILE"
|