@hegemonart/get-design-done 1.0.7 → 1.14.1

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 (56) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +129 -2
  4. package/README.md +186 -53
  5. package/SKILL.md +6 -4
  6. package/agents/design-authority-watcher.md +208 -0
  7. package/agents/design-component-generator.md +221 -0
  8. package/agents/design-context-builder.md +83 -6
  9. package/agents/design-discussant.md +1 -1
  10. package/agents/design-figma-writer.md +8 -8
  11. package/agents/design-paper-writer.md +131 -0
  12. package/agents/design-pencil-writer.md +99 -0
  13. package/agents/design-research-synthesizer.md +13 -1
  14. package/agents/design-update-checker.md +117 -0
  15. package/agents/design-verifier.md +51 -0
  16. package/agents/token-mapper.md +1 -1
  17. package/connections/21st-dev.md +98 -0
  18. package/connections/claude-design.md +0 -1
  19. package/connections/connections.md +50 -33
  20. package/connections/figma.md +81 -39
  21. package/connections/magic-patterns.md +105 -0
  22. package/connections/paper-design.md +137 -0
  23. package/connections/pencil-dev.md +88 -0
  24. package/connections/pinterest.md +0 -1
  25. package/hooks/budget-enforcer.js +13 -2
  26. package/hooks/gdd-read-injection-scanner.js +4 -9
  27. package/hooks/hooks.json +8 -0
  28. package/hooks/update-check.sh +251 -0
  29. package/package.json +1 -1
  30. package/reference/ai-native-tool-interface.md +102 -0
  31. package/reference/authority-feeds.md +72 -0
  32. package/reference/schemas/authority-snapshot.schema.json +42 -0
  33. package/reference/schemas/config.schema.json +4 -0
  34. package/reference/schemas/marketplace.schema.json +2 -2
  35. package/reference/schemas/plugin.schema.json +1 -1
  36. package/scripts/aggregate-agent-metrics.js +20 -0
  37. package/scripts/build-intel.cjs +13 -5
  38. package/scripts/injection-patterns.cjs +17 -0
  39. package/scripts/run-injection-scanner-ci.cjs +1 -10
  40. package/scripts/tests/test-authority-rejected-kinds.sh +58 -0
  41. package/scripts/tests/test-authority-watcher-diff.sh +113 -0
  42. package/scripts/validate-schemas.cjs +18 -1
  43. package/skills/audit/SKILL.md +11 -1
  44. package/skills/check-update/SKILL.md +135 -0
  45. package/skills/complete-cycle/SKILL.md +10 -0
  46. package/skills/design/SKILL.md +5 -5
  47. package/skills/discover/SKILL.md +2 -2
  48. package/skills/explore/SKILL.md +55 -3
  49. package/skills/health/SKILL.md +10 -0
  50. package/skills/help/SKILL.md +10 -0
  51. package/skills/progress/SKILL.md +10 -0
  52. package/skills/reflect/SKILL.md +1 -0
  53. package/skills/scan/SKILL.md +9 -19
  54. package/skills/ship/SKILL.md +10 -0
  55. package/skills/watch-authorities/SKILL.md +82 -0
  56. package/connections/figma-writer.md +0 -139
@@ -0,0 +1,88 @@
1
+ # pencil.dev — Connection Specification
2
+
3
+ This file is the connection specification for pencil.dev within the get-design-done pipeline. pencil.dev uses git-tracked `.pen` files as its source of truth — no MCP server is required. See `connections/connections.md` for the full connection index and capability matrix.
4
+
5
+ ---
6
+
7
+ ## Setup
8
+
9
+ ### Prerequisites
10
+ - pencil.dev VS Code or Cursor extension installed from the marketplace
11
+ - One or more `.pen` files in the project (typically at project root or in `src/`)
12
+
13
+ ### Verification
14
+
15
+ Run in the project directory:
16
+ ```bash
17
+ find . -name "*.pen" -not -path "*/node_modules/*" | head -5
18
+ ```
19
+ One or more results = pencil.dev is in use.
20
+
21
+ No MCP server install needed — the pipeline reads and writes `.pen` files directly via standard file tools.
22
+
23
+ ---
24
+
25
+ ## Probe Pattern
26
+
27
+ pencil.dev does not use MCP tools. Probe is file-based.
28
+
29
+ ```bash
30
+ PEN_FILES=$(find . -name "*.pen" -not -path "*/node_modules/*" 2>/dev/null)
31
+ if [ -n "$PEN_FILES" ]; then
32
+ echo "pencil-dev: available"
33
+ else
34
+ echo "pencil-dev: not_configured"
35
+ fi
36
+ ```
37
+
38
+ Write result to STATE.md `<connections>`: `pencil-dev: available` or `pencil-dev: not_configured`.
39
+
40
+ ---
41
+
42
+ ## .pen File Format
43
+
44
+ `.pen` files are YAML-front-matter component specs:
45
+
46
+ ```yaml
47
+ ---
48
+ component: Button
49
+ variant: primary
50
+ state: default
51
+ design-tokens:
52
+ bg: brand-primary-500
53
+ text: white
54
+ radius: 6px
55
+ padding: "8px 16px"
56
+ ---
57
+
58
+ Notes: Primary CTA button. Use for the main action in any modal or form.
59
+ ```
60
+
61
+ - `component` — component name (must match the implementation filename)
62
+ - `variant` — variant label (matches Storybook story name where applicable)
63
+ - `state` — `default | hover | focus | disabled | error`
64
+ - `design-tokens` — key/value map of token names to values (CSS variables or literal values)
65
+ - Body prose — optional implementation notes
66
+
67
+ `.pen` files are **git-tracked source of truth**. Commits to `.pen` files must be atomic — spec and implementation changes committed together when possible.
68
+
69
+ ---
70
+
71
+ ## Pipeline Integration
72
+
73
+ | Stage | What pencil.dev provides |
74
+ |-------|--------------------------|
75
+ | explore | `.pen` file discovery; synthesizer merges `.pen` declarations with code grep results |
76
+ | verify | Spec-vs-implementation diff: `.pen` declared token values vs. actual token values in code |
77
+ | design | `design-pencil-writer` agent: annotate + roundtrip modes; atomic git commits on `.pen` writes |
78
+
79
+ **Architectural advantage:** Both the design spec (`.pen` file) and implementation (source code) are version-controlled. Pre-merge diff verification is uniquely strong compared to tools where the design lives outside git.
80
+
81
+ ---
82
+
83
+ ## Fallback Behavior
84
+
85
+ When `pencil-dev: not_configured`:
86
+ - All pencil.dev steps are skipped silently.
87
+ - A one-line diagnostic is printed: `pencil.dev not configured — no .pen files found.`
88
+ - Pipeline continues normally.
@@ -123,7 +123,6 @@ refero: not_configured
123
123
  preview: available
124
124
  storybook: not_configured
125
125
  chromatic: not_configured
126
- figma_writer: not_configured
127
126
  graphify: not_configured
128
127
  pinterest: available
129
128
  claude_design: not_configured
@@ -32,6 +32,7 @@ const { spawn } = require('child_process');
32
32
  const BUDGET_PATH = path.join(process.cwd(), '.design', 'budget.json');
33
33
  const MANIFEST_PATH = path.join(process.cwd(), '.design', 'cache-manifest.json');
34
34
  const TELEMETRY_PATH = path.join(process.cwd(), '.design', 'telemetry', 'costs.jsonl');
35
+ const PHASE_TOTALS_PATH = path.join(process.cwd(), '.design', 'telemetry', 'phase-totals.json');
35
36
  const STATE_PATH = path.join(process.cwd(), '.design', 'STATE.md');
36
37
 
37
38
  // ---- budget.json loader with defaults per D-12 ----
@@ -49,8 +50,18 @@ function loadBudget() {
49
50
  catch { return defaults; }
50
51
  }
51
52
 
52
- // ---- cumulative phase spend from telemetry (D-02 per_phase_cap_usd check) ----
53
+ // ---- cumulative phase spend (WR-02) ----
54
+ // Reads from the lightweight phase-totals.json written by aggregate-agent-metrics.js
55
+ // instead of replaying the full costs.jsonl on every hook invocation.
56
+ // Falls back to 0 when the file doesn't exist yet (early in a session).
53
57
  function currentPhaseSpend(phase) {
58
+ if (fs.existsSync(PHASE_TOTALS_PATH)) {
59
+ try {
60
+ const data = JSON.parse(fs.readFileSync(PHASE_TOTALS_PATH, 'utf8'));
61
+ return Number(data.totals?.[phase] || 0);
62
+ } catch { /* fall through */ }
63
+ }
64
+ // Fallback: replay JSONL when phase-totals.json not yet written (first spawn of session).
54
65
  if (!fs.existsSync(TELEMETRY_PATH)) return 0;
55
66
  const lines = fs.readFileSync(TELEMETRY_PATH, 'utf8').split(/\r?\n/).filter(Boolean);
56
67
  let sum = 0;
@@ -118,7 +129,7 @@ function spawnAggregator() {
118
129
  cwd: process.cwd(),
119
130
  detached: true,
120
131
  stdio: 'ignore',
121
- env: process.env,
132
+ env: { PATH: process.env.PATH }, // IN-02: minimal env; aggregator needs no secrets
122
133
  });
123
134
  child.unref();
124
135
  } catch {
@@ -6,16 +6,11 @@
6
6
  */
7
7
 
8
8
  const readline = require('readline');
9
+ const path = require('path');
10
+ const { INJECTION_PATTERNS: RAW_PATTERNS } = require(path.join(__dirname, '..', 'scripts', 'injection-patterns.cjs'));
9
11
 
10
- const INJECTION_PATTERNS = [
11
- /ignore\s+(all\s+)?(previous|prior|above)\s+instructions?/i,
12
- /disregard\s+(all\s+)?(previous|prior|above)\s+instructions?/i,
13
- /you\s+are\s+now\s+a\s+different/i,
14
- /system\s*:\s*you\s+are/i,
15
- /<\s*\/?\s*(system|assistant|human)\s*>/i,
16
- /\[INST\]/i,
17
- /###\s*instruction/i,
18
- ];
12
+ // The hook needs bare RegExp objects; extract them from the shared {name,re} entries.
13
+ const INJECTION_PATTERNS = RAW_PATTERNS.map(p => p.re);
19
14
 
20
15
  async function main() {
21
16
  const rl = readline.createInterface({ input: process.stdin });
package/hooks/hooks.json CHANGED
@@ -8,6 +8,14 @@
8
8
  "command": "bash \"${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.sh\""
9
9
  }
10
10
  ]
11
+ },
12
+ {
13
+ "hooks": [
14
+ {
15
+ "type": "command",
16
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/update-check.sh\""
17
+ }
18
+ ]
11
19
  }
12
20
  ],
13
21
  "PreToolUse": [
@@ -0,0 +1,251 @@
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
+ # Strip double-quotes so the JSON round-trip sed read-back cannot be injected via a
169
+ # crafted release body. Body is display-only — losing quotes is acceptable.
170
+ BODY_EXCERPT="$(printf '%s' "${BODY_EXCERPT}" | tr -d '"')"
171
+ # Validate LATEST_TAG is a safe semver string before trusting it (CR-02).
172
+ if ! printf '%s' "${LATEST_TAG}" | grep -qE '^v?[0-9]+\.[0-9]+(\.[0-9]+)*$'; then
173
+ log "LATEST_TAG '${LATEST_TAG}' failed semver safety check — aborting cache write"
174
+ LATEST_TAG=""
175
+ fi
176
+ if [ -n "${LATEST_TAG}" ]; then
177
+ read -r DELTA_STATE DELTA_KIND <<EOF
178
+ $(classify_delta "${DISPLAY_CURRENT}" "${LATEST_TAG}")
179
+ EOF
180
+ IS_NEWER=false
181
+ [ "${DELTA_STATE}" = "newer" ] && IS_NEWER=true
182
+ CHECKED_AT="$(date +%s)"
183
+ # Write cache atomically (write-to-tmp + rename) — T-13.3-04 mitigation
184
+ TMP="${CACHE}.tmp.$$"
185
+ {
186
+ printf '{\n'
187
+ printf ' "checked_at": %s,\n' "${CHECKED_AT}"
188
+ printf ' "current_tag": "%s",\n' "${DISPLAY_CURRENT}"
189
+ printf ' "latest_tag": "%s",\n' "${LATEST_TAG}"
190
+ printf ' "delta": "%s",\n' "${DELTA_KIND}"
191
+ printf ' "is_newer": %s,\n' "${IS_NEWER}"
192
+ # Escape the body for JSON — backslashes first, then quotes, then newlines.
193
+ ESC="$(printf '%s' "${BODY_EXCERPT}" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | awk '{printf "%s\\n", $0}')"
194
+ printf ' "changelog_excerpt": "%s"\n' "${ESC}"
195
+ printf '}\n'
196
+ } > "${TMP}" 2>/dev/null && mv "${TMP}" "${CACHE}" 2>/dev/null || rm -f "${TMP}" 2>/dev/null
197
+ fi
198
+ fi
199
+ fi
200
+
201
+ # 2. Read cache (whether freshly written or still valid).
202
+ [ -f "${CACHE}" ] || exit 0 # no cache, nothing to do — silent exit
203
+
204
+ C_LATEST="$(grep -E '"latest_tag"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"latest_tag"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')"
205
+ C_DELTA="$(grep -E '"delta"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"delta"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')"
206
+ # Allowlist-gate C_DELTA before it reaches any shell context (WR-04).
207
+ case "${C_DELTA:-}" in
208
+ major|minor|patch|off-cadence|none) : ;;
209
+ *) C_DELTA="unknown" ;;
210
+ esac
211
+ C_NEWER="$(grep -E '"is_newer"' "${CACHE}" 2>/dev/null | head -n1 | sed -E 's/.*"is_newer"[[:space:]]*:[[:space:]]*(true|false).*/\1/')"
212
+ 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')"
213
+
214
+ # 3. Gate: if cache says not newer, remove any stale banner and exit.
215
+ if [ "${C_NEWER:-false}" != "true" ]; then
216
+ rm -f "${BANNER}" 2>/dev/null
217
+ exit 0
218
+ fi
219
+
220
+ # 4. Dismissal gate (D-13): if user already dismissed this exact tag, suppress.
221
+ DISMISSED="$(read_dismissed)"
222
+ if [ -n "${DISMISSED}" ] && [ "${DISMISSED}" = "${C_LATEST}" ]; then
223
+ rm -f "${BANNER}" 2>/dev/null
224
+ exit 0
225
+ fi
226
+
227
+ # 5. State-machine guard (D-11/D-12): suppress during plan|design|verify.
228
+ STAGE="$(read_state_stage)"
229
+ case "${STAGE}" in
230
+ plan|design|verify)
231
+ rm -f "${BANNER}" 2>/dev/null
232
+ exit 0
233
+ ;;
234
+ esac
235
+
236
+ # 6. All gates passed — render the banner atomically.
237
+ TMP="${BANNER}.tmp.$$"
238
+ {
239
+ printf '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'
240
+ printf ' 📦 Plugin update: %s → %s (%s)\n' "${DISPLAY_CURRENT}" "${C_LATEST}" "${C_DELTA}"
241
+ if [ -n "${C_BODY}" ]; then
242
+ printf '%s\n' "${C_BODY}"
243
+ fi
244
+ printf ' Install: /gdd:update Dismiss: /gdd:check-update --dismiss\n'
245
+ printf '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'
246
+ } > "${TMP}" 2>/dev/null && mv "${TMP}" "${BANNER}" 2>/dev/null || rm -f "${TMP}" 2>/dev/null
247
+
248
+ exit 0
249
+ fi
250
+ # When sourced (BASH_SOURCE != $0), fall through with function definitions loaded
251
+ # and without side effects. Sourcing callers must invoke functions explicitly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hegemonart/get-design-done",
3
- "version": "1.0.7",
3
+ "version": "1.14.1",
4
4
  "description": "A Claude Code plugin for systematic design improvement",
5
5
  "author": "Hegemon",
6
6
  "homepage": "https://github.com/hegemonart/get-design-done",
@@ -0,0 +1,102 @@
1
+ # AI-Native Design Tool Interface — Capability Contract
2
+
3
+ This file defines the capability-based contract that AI-native design tools must implement to integrate with the get-design-done pipeline. Two sub-categories are defined: **canvas** and **component-generator**. Future tools implement one sub-category and plug in via the same probe/read/write or probe/generate/adopt surface.
4
+
5
+ ---
6
+
7
+ ## Sub-Categories
8
+
9
+ ### Canvas Tools
10
+
11
+ Canvas tools treat the design canvas as both source AND destination. They expose a bidirectional read+write surface.
12
+
13
+ **Contract:**
14
+
15
+ ```
16
+ probe() → { available | unavailable | not_configured }
17
+
18
+ read(selection) → {
19
+ jsx: string, // React JSX of component tree
20
+ styles: object, // computed CSS styles
21
+ screenshot: base64_png, // visual snapshot
22
+ metadata: object // component name, bounds, id
23
+ }
24
+
25
+ write(proposal) → { confirmed | rejected }
26
+ ```
27
+
28
+ **Implementations:**
29
+ - `connections/paper-design.md` — MCP-based; 24-tool server; budget: 100 calls/week (free)
30
+ - `connections/pencil-dev.md` — file-based; `.pen` YAML spec files; git-tracked; no MCP
31
+
32
+ **Pipeline stages:** `explore` (read) + `verify` (screenshot) + `design` (write via writer agent)
33
+
34
+ ---
35
+
36
+ ### Component Generators
37
+
38
+ Component generators produce UI component code from a natural-language description and an optional design-system target. They expose a generative one-way (or roundtrip) surface.
39
+
40
+ **Contract:**
41
+
42
+ ```
43
+ probe() → { available | unavailable | not_configured }
44
+
45
+ generate(description: string, ds: "shadcn"|"tailwind"|"mantine"|"chakra") → {
46
+ code: string, // component source code
47
+ preview_url: string, // hosted preview URL
48
+ variants: array, // multiple generated variations
49
+ component_id: string // for adopt/annotate operations
50
+ }
51
+
52
+ adopt(variant: object) → { confirmed | rejected }
53
+ ```
54
+
55
+ **Implementations:**
56
+ - `connections/21st-dev.md` — Magic MCP; `npx @21st-dev/magic@latest init`; marketplace prior-art gate
57
+ - `connections/magic-patterns.md` — Claude connector (`mcp__magic_patterns*`) + API key fallback; DS-aware generation
58
+
59
+ **Pipeline stages:** `explore` (prior-art gate for 21st.dev) + `design` (generate + adopt)
60
+
61
+ ---
62
+
63
+ ## Shared Probe Pattern
64
+
65
+ All AI-native tools use the three-value status schema from `connections/connections.md`:
66
+
67
+ | Status | Meaning |
68
+ |--------|---------|
69
+ | `available` | Tool confirmed present and responsive |
70
+ | `unavailable` | Tool present but errored (rate-limited, auth failure) |
71
+ | `not_configured` | ToolSearch returned empty or no .pen files found |
72
+
73
+ STATE.md format: `<tool-name>: <status>` in the `<connections>` block.
74
+
75
+ ---
76
+
77
+ ## Extending with Future Tools
78
+
79
+ To add a new AI-native design tool:
80
+
81
+ 1. Determine sub-category: **canvas** (bidirectional design source) or **component-generator** (code generator).
82
+ 2. Create `connections/<tool-name>.md` following the frozen template in `connections/figma.md`.
83
+ 3. Implement `probe()` using ToolSearch or file-based check. Write status to STATE.md.
84
+ 4. For **canvas**: expose `read()` and `write()` surfaces via the corresponding agent.
85
+ 5. For **component-generator**: implement `generate()` and `adopt()` in `agents/design-component-generator.md` as a new `<!-- impl: <tool> -->` section.
86
+ 6. Add a row to `connections/connections.md` capability matrix with `canvas` or `generator` column marked.
87
+ 7. Append to `test-fixture/baselines/current/connection-list.txt` in sorted order.
88
+
89
+ ---
90
+
91
+ ## Candidate Tools (Backlog)
92
+
93
+ | Tool | Sub-category | Priority | Notes |
94
+ |------|-------------|----------|-------|
95
+ | Subframe | canvas | high | MCP-based; production-ready components; check for `mcp__subframe*` |
96
+ | v0.dev | generator | high | Vercel product; generates shadcn/tailwind; check for `mcp__v0*` |
97
+ | Galileo AI | generator | medium | Enterprise DS generation; API key required |
98
+ | Builder.io Visual Copilot | canvas + generator | medium | Figma plugin + code export; check for `mcp__builder*` |
99
+ | Locofy | generator | low | Figma→React/Next.js; Figma plugin-based |
100
+ | Anima | canvas | low | Figma→React; Figma plugin-based |
101
+ | Plasmic | generator | medium | Headless CMS + visual builder; `mcp__plasmic*` |
102
+ | TeleportHQ | generator | low | Code export + collaboration |
@@ -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
+ }