@windyroad/architect 0.9.2 → 0.10.0
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/agents/agent.md
CHANGED
|
@@ -17,7 +17,7 @@ You are the Architect. You review proposed changes against the project's archite
|
|
|
17
17
|
|
|
18
18
|
## Your Role
|
|
19
19
|
|
|
20
|
-
1. Read
|
|
20
|
+
1. Read `docs/decisions/README.md` — the generated **Decisions Compendium**. It carries every ADR's chosen option, confirmation criteria, and relationship graph in a compact form (~40 KB vs ~1.6 MB for the full body set; ~40× reduction). **This is the routine load surface for compliance review** (per ADR-077). If `docs/decisions/README.md` does not exist, fall back to globbing `docs/decisions/*.md` (skip the absent README) — the project may predate ADR-077 or be a fresh install. If `docs/decisions/` itself does not exist, that is fine; proceed noting that no prior decisions are recorded. **Load a specific ADR's full body** (`docs/decisions/<NNN>-*.md`) **only when the compendium entry is insufficient for the current review** — deep-dive on a contested change, evolving a decision, ratifying a new ADR via `/wr-architect:create-adr`, or confirming a substance question the compendium summary does not resolve. The per-ADR body remains the authoritative substance (ADR-031); the compendium is a derived view.
|
|
21
21
|
2. Read the file(s) being edited to understand the current state and proposed change
|
|
22
22
|
3. Review the proposed change against existing decisions (if any)
|
|
23
23
|
4. Determine if the change requires a new decision to be documented
|
package/package.json
CHANGED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# generate-decisions-compendium.sh — generate docs/decisions/README.md from
|
|
3
|
+
# per-ADR files. Per ADR-077 (Generated decisions compendium as token-cheap
|
|
4
|
+
# load surface for routine architect-agent compliance).
|
|
5
|
+
#
|
|
6
|
+
# Usage: bash packages/architect/scripts/generate-decisions-compendium.sh [decisions_dir]
|
|
7
|
+
# Writes: <decisions_dir>/README.md (idempotent — same input set + bodies
|
|
8
|
+
# produce byte-identical output).
|
|
9
|
+
#
|
|
10
|
+
# Distributed via the ADR-049 $PATH shim at:
|
|
11
|
+
# packages/architect/bin/wr-architect-generate-decisions-compendium
|
|
12
|
+
# Hooks and skills MUST invoke the shim, not this script directly — the
|
|
13
|
+
# shim resolves the canonical body relative to its own location, so it
|
|
14
|
+
# works in adopter installs where the package lives under
|
|
15
|
+
# ~/.claude/plugins/cache/windyroad/wr-architect/<version>/.
|
|
16
|
+
#
|
|
17
|
+
# ADR-031 authoritative-state invariant: per-ADR bodies are the
|
|
18
|
+
# authoritative source of substance; this compendium is a derived/cached
|
|
19
|
+
# view. The compendium is NEVER edited compendium-side first.
|
|
20
|
+
#
|
|
21
|
+
# ADR-077 Confirmation item (b): generator must be idempotent — running
|
|
22
|
+
# it twice produces identical output.
|
|
23
|
+
|
|
24
|
+
set -uo pipefail
|
|
25
|
+
|
|
26
|
+
DECISIONS_DIR="${1:-docs/decisions}"
|
|
27
|
+
COMPENDIUM="$DECISIONS_DIR/README.md"
|
|
28
|
+
|
|
29
|
+
if [ ! -d "$DECISIONS_DIR" ]; then
|
|
30
|
+
echo "generate-decisions-compendium: decisions directory not found: $DECISIONS_DIR" >&2
|
|
31
|
+
exit 2
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# --- Field extractors ------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
# Read a frontmatter scalar field (single line `key: value`).
|
|
37
|
+
# Strips surrounding quotes and leading/trailing whitespace.
|
|
38
|
+
get_frontmatter_field() {
|
|
39
|
+
local file="$1" field="$2"
|
|
40
|
+
awk -v f="$field" '
|
|
41
|
+
/^---$/ { fm = !fm; if (!fm) exit; next }
|
|
42
|
+
fm && $0 ~ "^"f":" {
|
|
43
|
+
sub("^"f": *", "")
|
|
44
|
+
gsub(/^["'"'"']|["'"'"']$/, "")
|
|
45
|
+
sub(/^ +/, ""); sub(/ +$/, "")
|
|
46
|
+
print
|
|
47
|
+
exit
|
|
48
|
+
}
|
|
49
|
+
' "$file"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Read the first "# Title" line after the frontmatter block.
|
|
53
|
+
get_title() {
|
|
54
|
+
awk '
|
|
55
|
+
/^---$/ { fm = !fm; next }
|
|
56
|
+
!fm && /^# / { sub(/^# /, ""); print; exit }
|
|
57
|
+
' "$1"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Extract a section by its `## Heading` line, up to (but not including) the
|
|
61
|
+
# next `## ` heading or EOF.
|
|
62
|
+
get_section() {
|
|
63
|
+
local file="$1" heading="$2"
|
|
64
|
+
awk -v h="$heading" '
|
|
65
|
+
$0 == "## " h { in_sec = 1; next }
|
|
66
|
+
in_sec && /^## / { exit }
|
|
67
|
+
in_sec { print }
|
|
68
|
+
' "$file"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Extract the "Chosen option:" line from the Decision Outcome section.
|
|
72
|
+
# Matches the common MADR shapes:
|
|
73
|
+
# Chosen option: **"X"**, because Y.
|
|
74
|
+
# Chosen option: X, because Y.
|
|
75
|
+
# Chosen: X.
|
|
76
|
+
get_chosen() {
|
|
77
|
+
get_section "$1" "Decision Outcome" \
|
|
78
|
+
| awk '/^Chosen/ { print; exit }' \
|
|
79
|
+
| head -1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Extract top-level bullet lines (`- ...`) from a section. Skips nested
|
|
83
|
+
# ` - ...` sub-bullets to keep the compendium dense. Capped at N entries.
|
|
84
|
+
get_bullets() {
|
|
85
|
+
local file="$1" section="$2" cap="${3:-5}"
|
|
86
|
+
get_section "$file" "$section" \
|
|
87
|
+
| awk '/^- / { sub(/^- */, ""); print }' \
|
|
88
|
+
| head -"$cap"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Compact-join bullets onto one line, truncating each to N chars + "…".
|
|
92
|
+
# Joins with "; ". Strips markdown emphasis to keep the line scannable.
|
|
93
|
+
compact_join_bullets() {
|
|
94
|
+
local per_item="${1:-120}"
|
|
95
|
+
awk -v n="$per_item" '
|
|
96
|
+
{
|
|
97
|
+
# Strip leading checkbox markers `[ ]` / `[x]` (from Confirmation).
|
|
98
|
+
sub(/^\[[ x]\] */, "")
|
|
99
|
+
# Strip markdown bold/italic markers for compactness.
|
|
100
|
+
gsub(/\*\*/, "")
|
|
101
|
+
gsub(/`/, "")
|
|
102
|
+
# Drop nested-bullet continuation lines that survived earlier filters.
|
|
103
|
+
if (length($0) == 0) next
|
|
104
|
+
if (length($0) > n) line = substr($0, 1, n) "…"
|
|
105
|
+
else line = $0
|
|
106
|
+
if (out == "") out = line
|
|
107
|
+
else out = out "; " line
|
|
108
|
+
}
|
|
109
|
+
END { print out }
|
|
110
|
+
'
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Extract ADR-NNN references from Related bullets. Compact "ADR-NNN" listing
|
|
114
|
+
# is sufficient for routine compliance graph navigation; full relationship
|
|
115
|
+
# prose (amends/extends/relates/composes) is preserved in the per-ADR body.
|
|
116
|
+
extract_related_ids() {
|
|
117
|
+
awk '
|
|
118
|
+
{
|
|
119
|
+
while (match($0, /ADR-[0-9]+/)) {
|
|
120
|
+
ref = substr($0, RSTART, RLENGTH)
|
|
121
|
+
if (!seen[ref]++) {
|
|
122
|
+
if (out == "") out = ref
|
|
123
|
+
else out = out ", " ref
|
|
124
|
+
}
|
|
125
|
+
$0 = substr($0, RSTART + RLENGTH)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
END { print out }
|
|
129
|
+
'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# --- Sanitisers ------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
# Strip markdown links `[text](url)` -> `text`.
|
|
135
|
+
strip_links() {
|
|
136
|
+
sed -E 's/\[([^]]+)\]\([^)]+\)/\1/g'
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# Collapse to a single line: replace newlines + carriage returns with spaces,
|
|
140
|
+
# squeeze runs of spaces, trim leading/trailing whitespace.
|
|
141
|
+
oneline() {
|
|
142
|
+
tr '\n\r' ' ' | tr -s ' ' | sed 's/^ *//; s/ *$//'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Truncate a string to N chars + ellipsis if longer. Avoids slicing inside
|
|
146
|
+
# a markdown emphasis pair (e.g. `**text**`) — if the truncation would land
|
|
147
|
+
# inside `**...**`, round back to before the opening pair.
|
|
148
|
+
truncate_with_ellipsis() {
|
|
149
|
+
local s="$1" n="$2"
|
|
150
|
+
if [ "${#s}" -le "$n" ]; then
|
|
151
|
+
printf '%s' "$s"
|
|
152
|
+
return
|
|
153
|
+
fi
|
|
154
|
+
printf '%s' "${s:0:n}…"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# --- Per-ADR entry emitter -------------------------------------------------
|
|
158
|
+
|
|
159
|
+
emit_entry() {
|
|
160
|
+
local file="$1"
|
|
161
|
+
local id title status oversight superseded
|
|
162
|
+
local chosen drivers confirmation related
|
|
163
|
+
|
|
164
|
+
id=$(basename "$file" | grep -oE '^[0-9]+')
|
|
165
|
+
title=$(get_title "$file")
|
|
166
|
+
status=$(get_frontmatter_field "$file" "status")
|
|
167
|
+
oversight=$(get_frontmatter_field "$file" "human-oversight")
|
|
168
|
+
superseded=$(get_frontmatter_field "$file" "supersedes")
|
|
169
|
+
|
|
170
|
+
# Chosen-option line — truncate to a comfortable summary length.
|
|
171
|
+
chosen=$(get_chosen "$file" | strip_links | oneline)
|
|
172
|
+
chosen=$(printf '%s' "$chosen" | awk -v n=240 '{ if (length($0) > n) print substr($0,1,n) "…"; else print }')
|
|
173
|
+
|
|
174
|
+
# Confirmation: cap 5 bullets, ≤ 110 chars each, joined with "; " on one line.
|
|
175
|
+
# This is the routine-compliance scannable view; the full Confirmation list
|
|
176
|
+
# remains in the per-ADR body for deep-dive surfaces.
|
|
177
|
+
confirmation=$(get_bullets "$file" "Confirmation" 5 | strip_links | compact_join_bullets 110)
|
|
178
|
+
|
|
179
|
+
# Related: extract ADR-NNN graph references only. Full relationship prose
|
|
180
|
+
# (amends / extends / relates / composes) stays in the per-ADR body.
|
|
181
|
+
related=$(get_bullets "$file" "Related" 20 | strip_links | extract_related_ids)
|
|
182
|
+
|
|
183
|
+
# Decision Drivers intentionally NOT emitted in the routine view (per
|
|
184
|
+
# ADR-077 Decision Outcome — drivers belong on the deep-dive surface, not
|
|
185
|
+
# the routine compliance load). If a future iteration needs them, add a
|
|
186
|
+
# `--with-drivers` flag rather than emit by default.
|
|
187
|
+
|
|
188
|
+
# Header line — ID + Title + status badges.
|
|
189
|
+
{
|
|
190
|
+
echo ""
|
|
191
|
+
echo "### ADR-${id} — ${title}"
|
|
192
|
+
# Status / oversight / supersession badges on one compact line.
|
|
193
|
+
local badges="**Status:** ${status:-?}"
|
|
194
|
+
if [ -n "$oversight" ]; then
|
|
195
|
+
badges="${badges} | **Oversight:** ${oversight}"
|
|
196
|
+
fi
|
|
197
|
+
if [ -n "$superseded" ] && [ "$superseded" != "[]" ]; then
|
|
198
|
+
badges="${badges} | **Supersedes:** ${superseded}"
|
|
199
|
+
fi
|
|
200
|
+
echo "${badges}"
|
|
201
|
+
if [ -n "$chosen" ]; then
|
|
202
|
+
echo "**Chosen:** ${chosen}"
|
|
203
|
+
fi
|
|
204
|
+
if [ -n "$confirmation" ]; then
|
|
205
|
+
echo "**Confirmation:** ${confirmation}"
|
|
206
|
+
fi
|
|
207
|
+
if [ -n "$related" ]; then
|
|
208
|
+
echo "**Related:** ${related}"
|
|
209
|
+
fi
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# --- Compendium emission ---------------------------------------------------
|
|
214
|
+
|
|
215
|
+
# Collect + sort ADR files. README.md and any sibling -history.md / -summary.md
|
|
216
|
+
# style files (future P194 etc.) are excluded.
|
|
217
|
+
files=()
|
|
218
|
+
while IFS= read -r f; do
|
|
219
|
+
files+=("$f")
|
|
220
|
+
done < <(find "$DECISIONS_DIR" -maxdepth 1 -type f -name '*.md' \
|
|
221
|
+
! -name 'README.md' \
|
|
222
|
+
! -name '*-history.md' \
|
|
223
|
+
! -name '*-summary.md' \
|
|
224
|
+
2>/dev/null | sort)
|
|
225
|
+
|
|
226
|
+
total=${#files[@]}
|
|
227
|
+
|
|
228
|
+
# Header is deterministic — NO timestamp, NO date. The compendium must be
|
|
229
|
+
# idempotent (same input bodies => byte-identical output) so the ADR-077
|
|
230
|
+
# drift-detection bats can compare the committed file against a fresh
|
|
231
|
+
# generator run and detect any divergence as substance drift, not as
|
|
232
|
+
# date-stamp churn.
|
|
233
|
+
{
|
|
234
|
+
echo "# Decisions Compendium"
|
|
235
|
+
echo ""
|
|
236
|
+
echo "<!-- AUTO-GENERATED by packages/architect/scripts/generate-decisions-compendium.sh per ADR-077 — do NOT hand-edit; regenerate via \`wr-architect-generate-decisions-compendium\`. -->"
|
|
237
|
+
echo ""
|
|
238
|
+
echo "Compact rendered index of every ADR's chosen option, confirmation criteria, and relationship graph. **Authoritative substance lives in the per-ADR body** (\`<NNN>-<slug>.<status>.md\`); this compendium is a derived view for routine \`wr-architect:agent\` compliance review."
|
|
239
|
+
echo ""
|
|
240
|
+
echo "For deep-dive — creating, evolving, ratifying, or contesting a decision — open the per-ADR file directly. \`/wr-architect:create-adr\`, \`/wr-architect:capture-adr\`, and \`/wr-architect:review-decisions\` all keep the full body in scope. Decision Drivers, Considered Options bodies, Pros and Cons, Consequences narrative, and Reassessment Criteria are intentionally NOT in this routine view — they live in the per-ADR body."
|
|
241
|
+
echo ""
|
|
242
|
+
echo "**Total ADRs:** ${total}"
|
|
243
|
+
echo ""
|
|
244
|
+
echo "---"
|
|
245
|
+
for f in "${files[@]}"; do
|
|
246
|
+
emit_entry "$f"
|
|
247
|
+
done
|
|
248
|
+
} > "$COMPENDIUM"
|
|
249
|
+
|
|
250
|
+
echo "generate-decisions-compendium: wrote $COMPENDIUM (${total} ADRs)" >&2
|