@hegemonart/get-design-done 1.0.7 → 1.13.3
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +82 -0
- package/README.md +57 -19
- package/SKILL.md +6 -4
- package/agents/design-authority-watcher.md +208 -0
- package/agents/design-context-builder.md +3 -3
- package/agents/design-discussant.md +1 -1
- package/agents/design-figma-writer.md +8 -8
- package/agents/design-update-checker.md +117 -0
- package/agents/token-mapper.md +1 -1
- package/connections/claude-design.md +0 -1
- package/connections/connections.md +10 -23
- package/connections/figma.md +81 -39
- package/connections/pinterest.md +0 -1
- package/hooks/hooks.json +8 -0
- package/hooks/update-check.sh +238 -0
- package/package.json +1 -1
- package/reference/authority-feeds.md +72 -0
- package/reference/schemas/authority-snapshot.schema.json +42 -0
- package/reference/schemas/config.schema.json +4 -0
- package/reference/schemas/marketplace.schema.json +2 -2
- package/reference/schemas/plugin.schema.json +1 -1
- package/scripts/tests/test-authority-rejected-kinds.sh +58 -0
- package/scripts/tests/test-authority-watcher-diff.sh +109 -0
- package/scripts/validate-schemas.cjs +18 -1
- package/skills/audit/SKILL.md +11 -1
- package/skills/check-update/SKILL.md +133 -0
- package/skills/complete-cycle/SKILL.md +10 -0
- package/skills/design/SKILL.md +5 -5
- package/skills/discover/SKILL.md +2 -2
- package/skills/explore/SKILL.md +2 -2
- package/skills/health/SKILL.md +10 -0
- package/skills/help/SKILL.md +10 -0
- package/skills/progress/SKILL.md +10 -0
- package/skills/reflect/SKILL.md +1 -0
- package/skills/scan/SKILL.md +9 -19
- package/skills/ship/SKILL.md +10 -0
- package/skills/watch-authorities/SKILL.md +82 -0
- package/connections/figma-writer.md +0 -139
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# get-design-done — update check (Phase 13.3)
|
|
3
|
+
# SessionStart hook. Silent-on-failure by policy (D-04): exits 0 on every error path.
|
|
4
|
+
# 24h-cached unauthenticated GET of /releases/latest. Renders .design/update-available.md
|
|
5
|
+
# only when a newer version exists AND it is not dismissed AND stage-guard allows.
|
|
6
|
+
|
|
7
|
+
set -u # intentionally no -e: we want to fall through to exit 0
|
|
8
|
+
|
|
9
|
+
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
|
|
10
|
+
PLUGIN_ROOT="${PLUGIN_ROOT//\\//}" # Windows → POSIX slashes
|
|
11
|
+
|
|
12
|
+
DESIGN_DIR="$(pwd)/.design"
|
|
13
|
+
CACHE="${DESIGN_DIR}/update-cache.json"
|
|
14
|
+
BANNER="${DESIGN_DIR}/update-available.md"
|
|
15
|
+
CONFIG="${DESIGN_DIR}/config.json"
|
|
16
|
+
STATE="${DESIGN_DIR}/STATE.md"
|
|
17
|
+
CACHE_TTL_SECONDS=86400 # 24h
|
|
18
|
+
|
|
19
|
+
# Silent logger — writes nothing by default. Set GDD_UPDATE_DEBUG=1 to enable stderr.
|
|
20
|
+
log() {
|
|
21
|
+
if [ "${GDD_UPDATE_DEBUG:-0}" = "1" ]; then
|
|
22
|
+
printf '[gdd update-check] %s\n' "$*" >&2
|
|
23
|
+
fi
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Ensure .design/ exists (bootstrap normally creates it; belt+suspenders).
|
|
27
|
+
mkdir -p "${DESIGN_DIR}" 2>/dev/null || exit 0
|
|
28
|
+
|
|
29
|
+
# ---- Read current plugin version (no jq) ----
|
|
30
|
+
PLUGIN_JSON="${PLUGIN_ROOT}/.claude-plugin/plugin.json"
|
|
31
|
+
|
|
32
|
+
read_current_tag() {
|
|
33
|
+
[ -f "${PLUGIN_JSON}" ] || return 1
|
|
34
|
+
grep -E '^[[:space:]]*"version"[[:space:]]*:' "${PLUGIN_JSON}" | head -n1 | \
|
|
35
|
+
sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# ---- Semver normalizer: "v1.0.7" -> "1 0 7 0"; "v1.0.7.3" -> "1 0 7 3" ----
|
|
39
|
+
normalize_semver() {
|
|
40
|
+
local t="${1#v}"
|
|
41
|
+
# strip any -pre/-beta suffix after first hyphen (unauth'd API rarely surfaces these, best-effort)
|
|
42
|
+
t="${t%%-*}"
|
|
43
|
+
# Replace dots with spaces; pad to 4 segments
|
|
44
|
+
# shellcheck disable=SC2086
|
|
45
|
+
set -- $(printf '%s' "${t}" | tr '.' ' ')
|
|
46
|
+
local a="${1:-0}" b="${2:-0}" c="${3:-0}" d="${4:-0}"
|
|
47
|
+
# Sanitize to digits only (POSIX: tr -cd 0-9 — BSD+GNU safe)
|
|
48
|
+
a="$(printf '%s' "$a" | tr -cd '0-9')"; a="${a:-0}"
|
|
49
|
+
b="$(printf '%s' "$b" | tr -cd '0-9')"; b="${b:-0}"
|
|
50
|
+
c="$(printf '%s' "$c" | tr -cd '0-9')"; c="${c:-0}"
|
|
51
|
+
d="$(printf '%s' "$d" | tr -cd '0-9')"; d="${d:-0}"
|
|
52
|
+
printf '%s %s %s %s' "$a" "$b" "$c" "$d"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ---- Classify delta: compare 4-segment tuples ----
|
|
56
|
+
# Args: current_tag latest_tag
|
|
57
|
+
# Prints: "newer|same|older|invalid" + "major|minor|patch|off-cadence|none"
|
|
58
|
+
classify_delta() {
|
|
59
|
+
local cur lat
|
|
60
|
+
cur="$(normalize_semver "$1")" || { printf 'invalid none'; return; }
|
|
61
|
+
lat="$(normalize_semver "$2")" || { printf 'invalid none'; return; }
|
|
62
|
+
# shellcheck disable=SC2086
|
|
63
|
+
set -- $cur; local ca="$1" cb="$2" cc="$3" cd="$4"
|
|
64
|
+
# shellcheck disable=SC2086
|
|
65
|
+
set -- $lat; local la="$1" lb="$2" lc="$3" ld="$4"
|
|
66
|
+
|
|
67
|
+
# Per-segment integer compare (lexicographic per segment by numeric value)
|
|
68
|
+
if [ "$la" -gt "$ca" ]; then printf 'newer major'; return
|
|
69
|
+
elif [ "$la" -lt "$ca" ]; then printf 'older major'; return
|
|
70
|
+
fi
|
|
71
|
+
if [ "$lb" -gt "$cb" ]; then printf 'newer minor'; return
|
|
72
|
+
elif [ "$lb" -lt "$cb" ]; then printf 'older minor'; return
|
|
73
|
+
fi
|
|
74
|
+
if [ "$lc" -gt "$cc" ]; then printf 'newer patch'; return
|
|
75
|
+
elif [ "$lc" -lt "$cc" ]; then printf 'older patch'; return
|
|
76
|
+
fi
|
|
77
|
+
if [ "$ld" -gt "$cd" ]; then printf 'newer off-cadence'; return
|
|
78
|
+
elif [ "$ld" -lt "$cd" ]; then printf 'older off-cadence'; return
|
|
79
|
+
fi
|
|
80
|
+
printf 'same none'
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# ---- Cache freshness check: returns 0 if fresh (<24h old), 1 if stale or missing ----
|
|
84
|
+
is_cache_fresh() {
|
|
85
|
+
[ -f "${CACHE}" ] || return 1
|
|
86
|
+
local now mtime age
|
|
87
|
+
now="$(date +%s)"
|
|
88
|
+
# BSD date -r on macOS; GNU stat -c on Linux; fall back to perl then python.
|
|
89
|
+
if mtime="$(date -r "${CACHE}" +%s 2>/dev/null)"; then :
|
|
90
|
+
elif mtime="$(stat -c %Y "${CACHE}" 2>/dev/null)"; then :
|
|
91
|
+
elif mtime="$(perl -e 'print((stat shift)[9])' "${CACHE}" 2>/dev/null)"; then :
|
|
92
|
+
else return 1
|
|
93
|
+
fi
|
|
94
|
+
[ -n "${mtime:-}" ] || return 1
|
|
95
|
+
age=$((now - mtime))
|
|
96
|
+
[ "${age}" -lt "${CACHE_TTL_SECONDS}" ]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# ---- Fetch latest release. Writes raw body to stdout on success, nothing on failure. ----
|
|
100
|
+
fetch_latest() {
|
|
101
|
+
command -v curl >/dev/null 2>&1 || { log "no curl"; return 1; }
|
|
102
|
+
local url="https://api.github.com/repos/hegemonart/get-design-done/releases/latest"
|
|
103
|
+
curl -sf --max-time 3 -H 'Accept: application/vnd.github+json' "${url}" 2>/dev/null || return 1
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# ---- Extract fields from the release JSON (no jq). Robust to whitespace; fails soft. ----
|
|
107
|
+
extract_tag() {
|
|
108
|
+
grep -E '"tag_name"[[:space:]]*:' | head -n1 | sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/'
|
|
109
|
+
}
|
|
110
|
+
# Body extraction: python3-only. If python3 is absent, we intentionally return empty
|
|
111
|
+
# (D-04 silent-on-failure posture). No awk/sed fallback — JSON string decoding in pure
|
|
112
|
+
# bash is fragile and untested; empty excerpt is the correct degraded state.
|
|
113
|
+
extract_body() {
|
|
114
|
+
command -v python3 >/dev/null 2>&1 || return 0
|
|
115
|
+
python3 -c 'import json,sys
|
|
116
|
+
try:
|
|
117
|
+
d=json.load(sys.stdin)
|
|
118
|
+
b=d.get("body","") or ""
|
|
119
|
+
print(b[:500])
|
|
120
|
+
except Exception:
|
|
121
|
+
pass' 2>/dev/null
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# ---- Read .design/STATE.md stage field. Returns "brief"|"explore"|"plan"|"design"|"verify"|"" ----
|
|
125
|
+
# Schema source: reference/STATE-TEMPLATE.md — `stage:` lives in both the frontmatter
|
|
126
|
+
# and the <position> block with identical values per the write contract. We take the
|
|
127
|
+
# first occurrence (head -n1), which is the frontmatter line.
|
|
128
|
+
read_state_stage() {
|
|
129
|
+
[ -f "${STATE}" ] || { printf ''; return; }
|
|
130
|
+
grep -E '^stage:' "${STATE}" 2>/dev/null | head -n1 | sed -E 's/^stage:[[:space:]]*"?([^"[:space:]]+)"?.*/\1/'
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# ---- Read .design/config.json for update_dismissed. Returns tag or empty. ----
|
|
134
|
+
read_dismissed() {
|
|
135
|
+
[ -f "${CONFIG}" ] || { printf ''; return; }
|
|
136
|
+
grep -E '"update_dismissed"[[:space:]]*:' "${CONFIG}" 2>/dev/null | head -n1 | \
|
|
137
|
+
sed -E 's/.*"update_dismissed"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# ---- Main control flow ----
|
|
141
|
+
# MANDATORY sourcing guard: wrap the entire main flow so that `source update-check.sh`
|
|
142
|
+
# (used by unit tests and interactive debugging) loads the function definitions without
|
|
143
|
+
# executing steps 1-6 and exiting the sourcing shell. This is non-negotiable — the
|
|
144
|
+
# semver self-test acceptance criterion sources this script.
|
|
145
|
+
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
146
|
+
|
|
147
|
+
CURRENT_TAG="$(read_current_tag)" || { log "no plugin.json"; exit 0; }
|
|
148
|
+
[ -n "${CURRENT_TAG:-}" ] || { log "no current version parsed"; exit 0; }
|
|
149
|
+
# Normalize to "vX.Y.Z" shape for display (plugin.json stores bare "1.0.7")
|
|
150
|
+
DISPLAY_CURRENT="v${CURRENT_TAG#v}"
|
|
151
|
+
|
|
152
|
+
# Optional --refresh forces a fresh fetch (called by plan 13.3-04's /gdd:check-update --refresh).
|
|
153
|
+
FORCE_REFRESH=0
|
|
154
|
+
for arg in "$@"; do
|
|
155
|
+
case "$arg" in
|
|
156
|
+
--refresh) FORCE_REFRESH=1 ;;
|
|
157
|
+
esac
|
|
158
|
+
done
|
|
159
|
+
|
|
160
|
+
# 1. Populate cache if missing/stale or forced.
|
|
161
|
+
if [ "${FORCE_REFRESH}" -eq 1 ] || ! is_cache_fresh; then
|
|
162
|
+
RAW="$(fetch_latest)" || RAW=""
|
|
163
|
+
if [ -n "${RAW}" ]; then
|
|
164
|
+
LATEST_TAG="$(printf '%s' "${RAW}" | extract_tag)"
|
|
165
|
+
BODY_EXCERPT="$(printf '%s' "${RAW}" | extract_body)"
|
|
166
|
+
# Strip control chars defensively (T-13.3-03)
|
|
167
|
+
BODY_EXCERPT="$(printf '%s' "${BODY_EXCERPT}" | tr -d '\000-\010\013\014\016-\037')"
|
|
168
|
+
if [ -n "${LATEST_TAG}" ]; then
|
|
169
|
+
read -r DELTA_STATE DELTA_KIND <<EOF
|
|
170
|
+
$(classify_delta "${DISPLAY_CURRENT}" "${LATEST_TAG}")
|
|
171
|
+
EOF
|
|
172
|
+
IS_NEWER=false
|
|
173
|
+
[ "${DELTA_STATE}" = "newer" ] && IS_NEWER=true
|
|
174
|
+
CHECKED_AT="$(date +%s)"
|
|
175
|
+
# Write cache atomically (write-to-tmp + rename) — T-13.3-04 mitigation
|
|
176
|
+
TMP="${CACHE}.tmp.$$"
|
|
177
|
+
{
|
|
178
|
+
printf '{\n'
|
|
179
|
+
printf ' "checked_at": %s,\n' "${CHECKED_AT}"
|
|
180
|
+
printf ' "current_tag": "%s",\n' "${DISPLAY_CURRENT}"
|
|
181
|
+
printf ' "latest_tag": "%s",\n' "${LATEST_TAG}"
|
|
182
|
+
printf ' "delta": "%s",\n' "${DELTA_KIND}"
|
|
183
|
+
printf ' "is_newer": %s,\n' "${IS_NEWER}"
|
|
184
|
+
# Escape the body for JSON — backslashes first, then quotes, then newlines.
|
|
185
|
+
ESC="$(printf '%s' "${BODY_EXCERPT}" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | awk '{printf "%s\\n", $0}')"
|
|
186
|
+
printf ' "changelog_excerpt": "%s"\n' "${ESC}"
|
|
187
|
+
printf '}\n'
|
|
188
|
+
} > "${TMP}" 2>/dev/null && mv "${TMP}" "${CACHE}" 2>/dev/null || rm -f "${TMP}" 2>/dev/null
|
|
189
|
+
fi
|
|
190
|
+
fi
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# 2. Read cache (whether freshly written or still valid).
|
|
194
|
+
[ -f "${CACHE}" ] || exit 0 # no cache, nothing to do — silent exit
|
|
195
|
+
|
|
196
|
+
C_LATEST="$(grep -E '"latest_tag"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"latest_tag"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')"
|
|
197
|
+
C_DELTA="$(grep -E '"delta"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"delta"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')"
|
|
198
|
+
C_NEWER="$(grep -E '"is_newer"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"is_newer"[[:space:]]*:[[:space:]]*(true|false).*/\1/')"
|
|
199
|
+
C_BODY="$(grep -E '"changelog_excerpt"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"changelog_excerpt"[[:space:]]*:[[:space:]]*"(.*)".*/\1/' | sed -E 's/\\n/\n/g')"
|
|
200
|
+
|
|
201
|
+
# 3. Gate: if cache says not newer, remove any stale banner and exit.
|
|
202
|
+
if [ "${C_NEWER:-false}" != "true" ]; then
|
|
203
|
+
rm -f "${BANNER}" 2>/dev/null
|
|
204
|
+
exit 0
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
# 4. Dismissal gate (D-13): if user already dismissed this exact tag, suppress.
|
|
208
|
+
DISMISSED="$(read_dismissed)"
|
|
209
|
+
if [ -n "${DISMISSED}" ] && [ "${DISMISSED}" = "${C_LATEST}" ]; then
|
|
210
|
+
rm -f "${BANNER}" 2>/dev/null
|
|
211
|
+
exit 0
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
# 5. State-machine guard (D-11/D-12): suppress during plan|design|verify.
|
|
215
|
+
STAGE="$(read_state_stage)"
|
|
216
|
+
case "${STAGE}" in
|
|
217
|
+
plan|design|verify)
|
|
218
|
+
rm -f "${BANNER}" 2>/dev/null
|
|
219
|
+
exit 0
|
|
220
|
+
;;
|
|
221
|
+
esac
|
|
222
|
+
|
|
223
|
+
# 6. All gates passed — render the banner atomically.
|
|
224
|
+
TMP="${BANNER}.tmp.$$"
|
|
225
|
+
{
|
|
226
|
+
printf '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'
|
|
227
|
+
printf ' 📦 Plugin update: %s → %s (%s)\n' "${DISPLAY_CURRENT}" "${C_LATEST}" "${C_DELTA}"
|
|
228
|
+
if [ -n "${C_BODY}" ]; then
|
|
229
|
+
printf '%s\n' "${C_BODY}"
|
|
230
|
+
fi
|
|
231
|
+
printf ' Install: /gdd:update Dismiss: /gdd:check-update --dismiss\n'
|
|
232
|
+
printf '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'
|
|
233
|
+
} > "${TMP}" 2>/dev/null && mv "${TMP}" "${BANNER}" 2>/dev/null || rm -f "${TMP}" 2>/dev/null
|
|
234
|
+
|
|
235
|
+
exit 0
|
|
236
|
+
fi
|
|
237
|
+
# When sourced (BASH_SOURCE != $0), fall through with function definitions loaded
|
|
238
|
+
# and without side effects. Sourcing callers must invoke functions explicitly.
|
package/package.json
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Authority Feeds — Whitelist
|
|
2
|
+
|
|
3
|
+
> **Scope:** Curated whitelist of **design authorities** — sources that ship specs, guidelines, or named-practitioner curation. Consumed by `agents/design-authority-watcher.md` at runtime. Rejected kinds are listed explicitly below and enforced by `scripts/tests/test-authority-rejected-kinds.sh`.
|
|
4
|
+
>
|
|
5
|
+
> **Anti-slop thesis:** No Dribbble. No Behance. No LinkedIn. No generic trending aggregators. See `.planning/PROJECT.md` and `.planning/phases/13.2-external-authority-watcher/13.2-CONTEXT.md` §D-08.
|
|
6
|
+
|
|
7
|
+
**Last reviewed:** 2026-04-19
|
|
8
|
+
**Feed count:** 26 (updated each time a feed is added or removed)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Spec sources (4-5 feeds)
|
|
13
|
+
|
|
14
|
+
- **[WAI-ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/)** — `kind: spec-source` · `url: https://github.com/w3c/aria-practices/releases.atom` · `cadence-hint: monthly` · *Normative accessibility patterns from the W3C ARIA working group; release-tagged on each APG update.*
|
|
15
|
+
- **[Material Design 3](https://m3.material.io/)** — `kind: spec-source` · `url: https://github.com/material-components/material-web/releases.atom` · `cadence-hint: weekly` · *Google's design system release notes; new tokens and components land here first.*
|
|
16
|
+
- **[Apple Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/)** — `kind: spec-source` · `url: https://developer.apple.com/news/releases/rss/releases.rss` · `cadence-hint: irregular` · *Apple developer release feed — HIG updates ship alongside SDK announcements.*
|
|
17
|
+
- **[Fluent 2 Design System](https://fluent2.microsoft.design/)** — `kind: spec-source` · `url: https://github.com/microsoft/fluentui/releases.atom` · `cadence-hint: weekly` · *Microsoft's cross-platform design system; normative component API and token changes.*
|
|
18
|
+
- **[W3C Design Tokens Community Group](https://www.w3.org/community/design-tokens/)** — `kind: spec-source` · `url: https://github.com/design-tokens/community-group/commits/main.atom` · `cadence-hint: monthly` · *Draft tokens format spec; commit feed surfaces spec edits before formal publication.*
|
|
19
|
+
|
|
20
|
+
## Component systems (6-8 feeds)
|
|
21
|
+
|
|
22
|
+
- **[Radix UI](https://www.radix-ui.com/)** — `kind: component-system` · `url: https://github.com/radix-ui/primitives/releases.atom` · `cadence-hint: weekly` · *Unstyled accessible primitives; release notes document ARIA behavior changes.*
|
|
23
|
+
- **[shadcn/ui](https://ui.shadcn.com/)** — `kind: component-system` · `url: https://github.com/shadcn-ui/ui/releases.atom` · `cadence-hint: weekly` · *Copy-paste component library built on Radix + Tailwind; release notes map to new patterns.*
|
|
24
|
+
- **[Shopify Polaris](https://polaris.shopify.com/)** — `kind: component-system` · `url: https://github.com/Shopify/polaris/releases.atom` · `cadence-hint: weekly` · *Shopify admin design system; commerce-tuned component patterns.*
|
|
25
|
+
- **[IBM Carbon](https://carbondesignsystem.com/)** — `kind: component-system` · `url: https://github.com/carbon-design-system/carbon/releases.atom` · `cadence-hint: weekly` · *IBM's enterprise design system; strong on data-dense patterns and accessibility.*
|
|
26
|
+
- **[GitHub Primer](https://primer.style/)** — `kind: component-system` · `url: https://github.com/primer/react/releases.atom` · `cadence-hint: weekly` · *GitHub's design system; opinionated developer-tool patterns.*
|
|
27
|
+
- **[Atlassian Design System](https://atlassian.design/)** — `kind: component-system` · `url: https://github.com/atlassian/design-system/releases.atom` · `cadence-hint: weekly` · *Jira/Confluence design system; strong on collaboration and editor patterns.*
|
|
28
|
+
- **[Ant Design](https://ant.design/)** — `kind: component-system` · `url: https://github.com/ant-design/ant-design/releases.atom` · `cadence-hint: weekly` · *Enterprise React component library with deep form and table patterns.*
|
|
29
|
+
- **[Mantine](https://mantine.dev/)** — `kind: component-system` · `url: https://github.com/mantinedev/mantine/releases.atom` · `cadence-hint: weekly` · *React components with hooks-first architecture; strong accessibility defaults.*
|
|
30
|
+
|
|
31
|
+
## Research institutions (2-3 feeds)
|
|
32
|
+
|
|
33
|
+
- **[Nielsen Norman Group Articles](https://www.nngroup.com/articles/)** — `kind: research` · `url: https://www.nngroup.com/feed/rss/` · `cadence-hint: weekly` · *UX research articles from the Nielsen Norman Group; heuristic updates and usability findings ship here.*
|
|
34
|
+
- **[Laws of UX](https://lawsofux.com/)** — `kind: research` · `url: https://github.com/jonyablonski/laws-of-ux/releases.atom` · `cadence-hint: monthly` · *Jon Yablonski's curated catalogue of psychology-rooted UX principles; release feed tracks new laws and revisions.*
|
|
35
|
+
- **[Baymard Institute](https://baymard.com/)** — `kind: research` · `url: https://baymard.com/blog/rss` · `cadence-hint: monthly` · *E-commerce UX research with empirical benchmarks; public surface of their large-scale usability studies.*
|
|
36
|
+
|
|
37
|
+
## Named practitioners (10-12 feeds)
|
|
38
|
+
|
|
39
|
+
- **[Adam Wathan](https://adamwathan.me/)** — `kind: named-practitioner` · `url: https://adamwathan.me/feed.xml` · `cadence-hint: monthly` · *Tailwind creator; utility-first CSS, component API design, refactoring patterns.*
|
|
40
|
+
- **[Ryan Mulligan](https://ryanmulligan.dev/)** — `kind: named-practitioner` · `url: https://ryanmulligan.dev/feed.xml` · `cadence-hint: monthly` · *CSS craft at spec-adjacent depth; cascade layers, container queries, color functions.*
|
|
41
|
+
- **[Rachel Andrew](https://rachelandrew.co.uk/)** — `kind: named-practitioner` · `url: https://rachelandrew.co.uk/feed/atom` · `cadence-hint: monthly` · *CSS Working Group member; grid, layout, and evolving layout-engine features.*
|
|
42
|
+
- **[Josh W. Comeau](https://www.joshwcomeau.com/)** — `kind: named-practitioner` · `url: https://www.joshwcomeau.com/rss.xml` · `cadence-hint: monthly` · *Interactive explainers on CSS, animation, and React rendering; durable reference-quality deep dives.*
|
|
43
|
+
- **[Ahmad Shadeed](https://ishadeed.com/)** — `kind: named-practitioner` · `url: https://ishadeed.com/rss.xml` · `cadence-hint: monthly` · *CSS layout and component articles grounded in real interface patterns.*
|
|
44
|
+
- **[Sara Soueidan](https://www.sarasoueidan.com/)** — `kind: named-practitioner` · `url: https://www.sarasoueidan.com/feed.xml` · `cadence-hint: quarterly` · *SVG, accessibility, and inclusive design with spec-level rigor.*
|
|
45
|
+
- **[Lea Verou](https://lea.verou.me/)** — `kind: named-practitioner` · `url: https://lea.verou.me/feed/atom` · `cadence-hint: quarterly` · *CSS Working Group invited expert; writes about the spec surface before it ships.*
|
|
46
|
+
- **[Scott Jehl](https://scottjehl.com/)** — `kind: named-practitioner` · `url: https://scottjehl.com/feed/` · `cadence-hint: monthly` · *Progressive enhancement and web performance; long-form durable analysis.*
|
|
47
|
+
- **[Heydon Pickering](https://heydonworks.com/)** — `kind: named-practitioner` · `url: https://heydonworks.com/feed.xml` · `cadence-hint: irregular` · *Accessibility-first component design; Inclusive Components author.*
|
|
48
|
+
- **[Una Kravets](https://una.im/)** — `kind: named-practitioner` · `url: https://una.im/feed.xml` · `cadence-hint: monthly` · *Chrome DevRel on CSS; surfaces and explains new platform capabilities.*
|
|
49
|
+
|
|
50
|
+
## User-added Are.na channels (user-extensible)
|
|
51
|
+
|
|
52
|
+
Are.na channels are user-curated reference collections. Add your own channel by appending an entry to this section following the schema shown in the commented template below. The watcher fetches `https://api.are.na/v2/channels/<slug>/contents` and treats each block addition as a new entry.
|
|
53
|
+
|
|
54
|
+
<!--
|
|
55
|
+
- **[My Design Refs](https://are.na/my-handle/my-design-refs)** — `kind: arena` · `url: https://api.are.na/v2/channels/my-design-refs/contents` · `cadence-hint: irregular` · *Personal channel of pattern references.*
|
|
56
|
+
-->
|
|
57
|
+
|
|
58
|
+
## Rejected kinds
|
|
59
|
+
|
|
60
|
+
The following hosts and feed kinds are **explicitly rejected** from this whitelist. This list is enforced by `scripts/tests/test-authority-rejected-kinds.sh` — any merge that adds a matching URL fails CI.
|
|
61
|
+
|
|
62
|
+
- **dribbble.com** — visual-trend aggregator; no normative content, no named-practitioner curation.
|
|
63
|
+
- **behance.net** — portfolio aggregator; same category.
|
|
64
|
+
- **linkedin.com** — social feed; signal-to-noise ratio incompatible with the plugin's anti-slop thesis.
|
|
65
|
+
- **medium.com/topic/\*** — generic topic feeds; named Medium authors may appear as `named-practitioner` entries, but topic-level feeds are rejected wholesale.
|
|
66
|
+
- **"trending"-style aggregators** (e.g., product-hunt daily digests, "top 10 UI" roundups) — curatorial output indistinguishable from advertising.
|
|
67
|
+
|
|
68
|
+
Rationale: the whitelist is restricted to sources that ship specs, guidelines, or named-practitioner curation (PROJECT.md, ROADMAP.md SC 8, CONTEXT.md D-08).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
**How to propose a new feed:** open a PR that adds an entry to the appropriate `## <kind>` section. Are.na channel additions go in the Are.na section and do not require approval beyond CI-green. All other additions are reviewed against the anti-slop thesis.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/hegemonart/get-design-done/main/reference/schemas/authority-snapshot.schema.json",
|
|
4
|
+
"title": "AuthoritySnapshot",
|
|
5
|
+
"description": "Structure of .design/authority-snapshot.json produced by agents/design-authority-watcher.md. See .planning/phases/13.2-external-authority-watcher/13.2-CONTEXT.md §D-12.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["version", "generated_at", "feeds"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"version": { "const": 1 },
|
|
11
|
+
"generated_at": { "type": "string", "format": "date-time" },
|
|
12
|
+
"feeds": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": { "$ref": "#/definitions/feedState" }
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"definitions": {
|
|
18
|
+
"feedState": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": ["last_fetched_at", "entries"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"last_fetched_at": { "type": "string", "format": "date-time" },
|
|
24
|
+
"etag": { "type": "string" },
|
|
25
|
+
"entries": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"maxItems": 200,
|
|
28
|
+
"items": { "$ref": "#/definitions/entry" }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"entry": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": ["id", "hash"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"id": { "type": "string", "minLength": 1 },
|
|
38
|
+
"hash": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
},
|
|
40
|
+
"update_dismissed": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Latest plugin tag (e.g. \"v1.0.7.3\") whose update nudge the user has dismissed. Set by /gdd:check-update --dismiss and by hooks/update-check.sh on the --dismiss code path. When a newer tag ships, the nudge reappears."
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"required": ["description", "version"],
|
|
26
26
|
"properties": {
|
|
27
27
|
"description": { "type": "string", "minLength": 1 },
|
|
28
|
-
"version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d
|
|
28
|
+
"version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$" }
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"plugins": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"name": { "type": "string", "minLength": 1 },
|
|
49
49
|
"source": { "type": "string", "minLength": 1 },
|
|
50
50
|
"description": { "type": "string", "minLength": 1 },
|
|
51
|
-
"version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d
|
|
51
|
+
"version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$" },
|
|
52
52
|
"author": {
|
|
53
53
|
"type": "object",
|
|
54
54
|
"additionalProperties": true,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test-authority-rejected-kinds.sh
|
|
3
|
+
#
|
|
4
|
+
# Asserts that reference/authority-feeds.md does NOT contain trend-aggregator
|
|
5
|
+
# hosts OUTSIDE the explicit "## Rejected kinds" section. Enforces the anti-slop
|
|
6
|
+
# thesis structurally (CONTEXT.md D-08, D-28).
|
|
7
|
+
#
|
|
8
|
+
# Exit 0 = clean. Exit 1 = at least one rejected host appeared in the active
|
|
9
|
+
# whitelist, or the rejected-kinds section itself was removed.
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
WHITELIST="${WHITELIST:-reference/authority-feeds.md}"
|
|
14
|
+
|
|
15
|
+
if [ ! -f "$WHITELIST" ]; then
|
|
16
|
+
echo "FAIL: $WHITELIST not found." >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Split the file at the "## Rejected kinds" heading. Everything BEFORE it is
|
|
21
|
+
# the active whitelist; everything AFTER is the rejection manifest (which is
|
|
22
|
+
# allowed to mention these hosts — that's the whole point).
|
|
23
|
+
ACTIVE_SECTION="$(awk '/^## Rejected kinds/{exit} {print}' "$WHITELIST")"
|
|
24
|
+
|
|
25
|
+
REJECTED_PATTERNS=(
|
|
26
|
+
'dribbble\.com'
|
|
27
|
+
'behance\.net'
|
|
28
|
+
'linkedin\.com'
|
|
29
|
+
'medium\.com/topic'
|
|
30
|
+
'producthunt\.com/posts'
|
|
31
|
+
'top[[:space:]]*10[[:space:]]*ui'
|
|
32
|
+
'trending-ui'
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
FAIL=0
|
|
36
|
+
for pat in "${REJECTED_PATTERNS[@]}"; do
|
|
37
|
+
if echo "$ACTIVE_SECTION" | grep -iEq "$pat"; then
|
|
38
|
+
echo "FAIL: rejected pattern '$pat' matched in active whitelist section of $WHITELIST." >&2
|
|
39
|
+
FAIL=1
|
|
40
|
+
fi
|
|
41
|
+
done
|
|
42
|
+
|
|
43
|
+
if [ "$FAIL" -ne 0 ]; then
|
|
44
|
+
echo "" >&2
|
|
45
|
+
echo "The whitelist must not contain trend-aggregator hosts outside the '## Rejected kinds' block." >&2
|
|
46
|
+
echo "See .planning/phases/13.2-external-authority-watcher/13.2-CONTEXT.md §D-08." >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Also assert the rejected-kinds section itself is present — regression against
|
|
51
|
+
# someone deleting the section entirely.
|
|
52
|
+
if ! grep -q '^## Rejected kinds$' "$WHITELIST"; then
|
|
53
|
+
echo "FAIL: '## Rejected kinds' section is missing from $WHITELIST." >&2
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo "OK: $WHITELIST passes rejected-kinds check."
|
|
58
|
+
exit 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test-authority-watcher-diff.sh
|
|
3
|
+
#
|
|
4
|
+
# Structural-only v1: validates that the frozen authority-report baseline at
|
|
5
|
+
# test-fixture/baselines/phase-13.2/authority-report.expected.md preserves the
|
|
6
|
+
# shape the watcher-diff test depends on. Full end-to-end byte-diff against a
|
|
7
|
+
# live watcher run is deferred — CI cannot spawn Claude Code agents.
|
|
8
|
+
#
|
|
9
|
+
# What this test asserts (structural-only v1):
|
|
10
|
+
# 1. The fixture directory exists and is non-empty.
|
|
11
|
+
# 2. The baseline file exists, is non-empty, and starts with an Authority
|
|
12
|
+
# Report header.
|
|
13
|
+
# 3. The baseline contains the canonical classification section headings in
|
|
14
|
+
# the D-21 weighted order (spec > heuristic > pattern > craft).
|
|
15
|
+
# 4. The baseline declares a total-entries line consistent with the count of
|
|
16
|
+
# bulleted entries under its classification sections.
|
|
17
|
+
# 5. The baseline ends with a `**Skipped:**` footer.
|
|
18
|
+
#
|
|
19
|
+
# Exit 0 = structural shape preserved. Exit 1 = shape drift detected.
|
|
20
|
+
#
|
|
21
|
+
# Full end-to-end byte-diff (running the watcher against the fixtures and
|
|
22
|
+
# diffing stdout against the baseline) is a follow-up tracked in STATE.md
|
|
23
|
+
# "Open follow-ups". When the agent runtime becomes available in CI this
|
|
24
|
+
# script graduates from structural-only v1 to the full diff check.
|
|
25
|
+
|
|
26
|
+
set -euo pipefail
|
|
27
|
+
|
|
28
|
+
FIXTURE_DIR="test-fixture/authority-feeds"
|
|
29
|
+
BASELINE="test-fixture/baselines/phase-13.2/authority-report.expected.md"
|
|
30
|
+
|
|
31
|
+
if [ ! -d "$FIXTURE_DIR" ]; then
|
|
32
|
+
echo "FAIL: fixture dir $FIXTURE_DIR missing." >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Count actual fixture files (should be 4 frozen feeds + 1 README; we only
|
|
37
|
+
# care that at least one XML/JSON fixture is present).
|
|
38
|
+
FIXTURE_COUNT=$(find "$FIXTURE_DIR" -maxdepth 1 -type f \( -name '*.atom' -o -name '*.rss' -o -name '*.json' \) | wc -l | tr -d ' ')
|
|
39
|
+
if [ "$FIXTURE_COUNT" -lt 1 ]; then
|
|
40
|
+
echo "FAIL: $FIXTURE_DIR contains no feed fixtures (.atom/.rss/.json)." >&2
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [ ! -f "$BASELINE" ]; then
|
|
45
|
+
echo "FAIL: baseline $BASELINE missing." >&2
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [ ! -s "$BASELINE" ]; then
|
|
50
|
+
echo "FAIL: baseline $BASELINE is empty." >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Header: must start with "# Authority Report"
|
|
55
|
+
if ! head -1 "$BASELINE" | grep -q '^# Authority Report'; then
|
|
56
|
+
echo "FAIL: baseline does not begin with '# Authority Report' header." >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Totals line must declare a non-negative surfaced-entries count.
|
|
61
|
+
if ! grep -qE '^[0-9]+ entries surfaced across [0-9]+ feeds\. [0-9]+ skipped\.$' "$BASELINE"; then
|
|
62
|
+
echo "FAIL: baseline is missing the 'N entries surfaced across M feeds. K skipped.' totals line." >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Classification sections — at least one of the four non-skip buckets must
|
|
67
|
+
# appear. (Empty buckets are omitted by D-21, but a well-shaped baseline
|
|
68
|
+
# always has at least one.)
|
|
69
|
+
SECTION_HITS=0
|
|
70
|
+
for heading in '^## spec-change' '^## heuristic-update' '^## pattern-guidance' '^## craft-tip'; do
|
|
71
|
+
if grep -qE "$heading" "$BASELINE"; then
|
|
72
|
+
SECTION_HITS=$((SECTION_HITS + 1))
|
|
73
|
+
fi
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
if [ "$SECTION_HITS" -lt 1 ]; then
|
|
77
|
+
echo "FAIL: baseline does not contain any classification heading (spec-change / heuristic-update / pattern-guidance / craft-tip)." >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Count consistency check: the header's "N entries surfaced" must match the
|
|
82
|
+
# total bulleted entries across the four classification sections.
|
|
83
|
+
HEADER_COUNT=$(grep -oE '^[0-9]+ entries surfaced' "$BASELINE" | head -1 | grep -oE '^[0-9]+')
|
|
84
|
+
|
|
85
|
+
# Extract the body between the first "## spec-change|heuristic-update|pattern-guidance|craft-tip"
|
|
86
|
+
# heading and the closing "---" horizontal rule before the Skipped footer.
|
|
87
|
+
BULLET_COUNT=$(awk '
|
|
88
|
+
/^## (spec-change|heuristic-update|pattern-guidance|craft-tip)/ { in_section=1; next }
|
|
89
|
+
/^---$/ { in_section=0 }
|
|
90
|
+
in_section && /^- / { count++ }
|
|
91
|
+
END { print count+0 }
|
|
92
|
+
' "$BASELINE")
|
|
93
|
+
|
|
94
|
+
if [ "$HEADER_COUNT" != "$BULLET_COUNT" ]; then
|
|
95
|
+
echo "FAIL: baseline header declares $HEADER_COUNT entries but the classification sections contain $BULLET_COUNT bullets." >&2
|
|
96
|
+
echo " Counts MUST match — regenerate the baseline or fix the header." >&2
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Footer: must have a Skipped line.
|
|
101
|
+
if ! grep -qE '^\*\*Skipped:\*\*' "$BASELINE"; then
|
|
102
|
+
echo "FAIL: baseline is missing the '**Skipped:**' footer line." >&2
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
echo "OK: authority-report baseline shape preserved (structural-only v1)."
|
|
107
|
+
echo " Fixtures: $FIXTURE_COUNT files under $FIXTURE_DIR"
|
|
108
|
+
echo " Entries: $HEADER_COUNT (header) = $BULLET_COUNT (bullets)"
|
|
109
|
+
exit 0
|
|
@@ -69,6 +69,14 @@ const PAIRS = [
|
|
|
69
69
|
data: null,
|
|
70
70
|
required: false,
|
|
71
71
|
},
|
|
72
|
+
{
|
|
73
|
+
name: 'authority-snapshot',
|
|
74
|
+
schema: 'reference/schemas/authority-snapshot.schema.json',
|
|
75
|
+
// .design/authority-snapshot.json is runtime-only (gitignored via .design/).
|
|
76
|
+
// Only schema-compile it; Phase 13.2-02's watcher emits the data file at runtime.
|
|
77
|
+
data: null,
|
|
78
|
+
required: false,
|
|
79
|
+
},
|
|
72
80
|
];
|
|
73
81
|
|
|
74
82
|
const USE_NPX = !process.argv.includes('--no-npx');
|
|
@@ -76,11 +84,20 @@ const USE_NPX = !process.argv.includes('--no-npx');
|
|
|
76
84
|
/**
|
|
77
85
|
* Try running ajv-cli via npx. Returns { ok, stdout, stderr, status, fetchFailed }.
|
|
78
86
|
* fetchFailed=true if npx couldn't fetch the package (offline); caller should fall back.
|
|
87
|
+
*
|
|
88
|
+
* We pass `-c ajv-formats` so schemas declaring `format: "date-time"` (etc.) are
|
|
89
|
+
* validated against the standard JSON Schema formats plugin rather than being
|
|
90
|
+
* rejected as unknown formats under ajv's strict mode. Schemas that declare no
|
|
91
|
+
* formats (e.g., plugin, marketplace) are unaffected.
|
|
79
92
|
*/
|
|
80
93
|
function runAjv(args) {
|
|
94
|
+
const injected = [...args];
|
|
95
|
+
// Inject `-c ajv-formats` after the sub-command (compile/validate) but before -s flags.
|
|
96
|
+
// Simpler: just append; ajv-cli accepts -c at any position.
|
|
97
|
+
injected.push('-c', 'ajv-formats');
|
|
81
98
|
const result = spawnSync(
|
|
82
99
|
'npx',
|
|
83
|
-
['--yes', 'ajv-cli@5', ...
|
|
100
|
+
['--yes', '-p', 'ajv-cli@5', '-p', 'ajv-formats@3', 'ajv', ...injected],
|
|
84
101
|
{ encoding: 'utf8', cwd: REPO_ROOT }
|
|
85
102
|
);
|
|
86
103
|
const combined = (result.stdout || '') + (result.stderr || '');
|
package/skills/audit/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: gdd-audit
|
|
3
3
|
description: "Run design audit — wraps design-verifier + design-auditor + design-reflector. --retroactive audits the full cycle scope."
|
|
4
4
|
argument-hint: "[--retroactive] [--quick] [--no-reflect]"
|
|
5
|
-
tools: Read, Write, Task, Glob
|
|
5
|
+
tools: Read, Write, Task, Glob, Bash
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# /gdd:audit
|
|
@@ -51,4 +51,14 @@ Run only `design-auditor` (skip `design-integration-checker`). Faster health che
|
|
|
51
51
|
- Do not modify source files.
|
|
52
52
|
- Do not rerun stages; this is a read-only audit.
|
|
53
53
|
|
|
54
|
+
## Step 7 — Update notice (post-closeout surface)
|
|
55
|
+
|
|
56
|
+
After the consolidated audit summary has been printed (and any reflection-proposal count appended), emit the plugin-update banner if one is present:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
[ -f .design/update-available.md ] && cat .design/update-available.md
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Written by `hooks/update-check.sh`; suppressed mid-pipeline and when the latest release is dismissed.
|
|
63
|
+
|
|
54
64
|
## AUDIT COMPLETE
|