@hegemonart/get-design-done 1.57.1 → 1.57.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.
Files changed (237) hide show
  1. package/.claude-plugin/marketplace.json +26 -41
  2. package/.claude-plugin/plugin.json +23 -48
  3. package/CHANGELOG.md +139 -0
  4. package/README.md +166 -511
  5. package/SKILL.md +4 -6
  6. package/agents/README.md +33 -36
  7. package/agents/a11y-mapper.md +3 -3
  8. package/agents/component-benchmark-harvester.md +6 -6
  9. package/agents/component-benchmark-synthesizer.md +3 -3
  10. package/agents/compose-executor.md +3 -3
  11. package/agents/cost-forecaster.md +2 -2
  12. package/agents/design-auditor.md +7 -7
  13. package/agents/design-authority-watcher.md +15 -15
  14. package/agents/design-context-builder.md +4 -4
  15. package/agents/design-context-checker-gate.md +1 -1
  16. package/agents/design-discussant.md +2 -2
  17. package/agents/design-doc-writer.md +1 -1
  18. package/agents/design-executor.md +2 -2
  19. package/agents/design-figma-writer.md +2 -2
  20. package/agents/design-fixer.md +7 -7
  21. package/agents/design-integration-checker-gate.md +1 -1
  22. package/agents/design-integration-checker.md +1 -1
  23. package/agents/design-paper-writer.md +3 -3
  24. package/agents/design-pencil-writer.md +1 -1
  25. package/agents/design-planner.md +21 -0
  26. package/agents/design-reflector.md +39 -39
  27. package/agents/design-research-synthesizer.md +1 -0
  28. package/agents/design-start-writer.md +1 -1
  29. package/agents/design-update-checker.md +5 -5
  30. package/agents/design-verifier-gate.md +1 -1
  31. package/agents/design-verifier.md +52 -48
  32. package/agents/ds-generator.md +2 -2
  33. package/agents/ds-migration-planner.md +4 -4
  34. package/agents/email-executor.md +9 -9
  35. package/agents/experiment-result-ingester.md +3 -3
  36. package/agents/flutter-executor.md +5 -5
  37. package/agents/gdd-graph-refresh.md +3 -3
  38. package/agents/gdd-intel-updater.md +2 -2
  39. package/agents/motion-mapper.md +2 -2
  40. package/agents/motion-verifier.md +4 -4
  41. package/agents/pdf-executor.md +8 -8
  42. package/agents/perf-analyzer.md +17 -17
  43. package/agents/pr-commenter.md +9 -9
  44. package/agents/prototype-gate.md +2 -2
  45. package/agents/quality-gate-runner.md +1 -1
  46. package/agents/rollout-coordinator.md +3 -3
  47. package/agents/swift-executor.md +4 -4
  48. package/agents/ticket-sync-agent.md +6 -6
  49. package/agents/user-research-synthesizer.md +2 -2
  50. package/connections/connections.md +44 -45
  51. package/connections/cursor.md +72 -0
  52. package/connections/preview.md +3 -3
  53. package/hooks/first-run-nudge.cjs +171 -0
  54. package/hooks/gdd-intel-trigger.js +243 -0
  55. package/hooks/gdd-mcp-circuit-breaker.js +62 -7
  56. package/hooks/gdd-precompact-snapshot.js +50 -29
  57. package/hooks/gdd-protected-paths.js +150 -18
  58. package/hooks/gdd-risk-gate.js +93 -1
  59. package/hooks/gdd-sessionstart-recap.js +59 -24
  60. package/hooks/hooks.json +13 -4
  61. package/hooks/inject-using-gdd.cjs +188 -0
  62. package/hooks/update-check.cjs +511 -0
  63. package/package.json +9 -3
  64. package/reference/STATE-TEMPLATE.md +10 -13
  65. package/reference/audit-scoring.md +1 -1
  66. package/reference/cache-tier-doctrine.md +46 -0
  67. package/reference/config-schema.md +9 -9
  68. package/reference/i18n.md +1 -1
  69. package/reference/intel-schema.md +37 -2
  70. package/reference/meta-rules.md +4 -4
  71. package/reference/model-tiers.md +2 -2
  72. package/reference/registry.json +101 -94
  73. package/reference/runtime-models.md +11 -1
  74. package/reference/shared-preamble.md +13 -14
  75. package/reference/skill-graph.md +22 -3
  76. package/scripts/bootstrap.cjs +373 -0
  77. package/scripts/injection-patterns.cjs +58 -0
  78. package/scripts/lib/apply-reflections/incubator-proposals.cjs +57 -26
  79. package/scripts/lib/install/converters/codex-plugin.cjs +5 -2
  80. package/scripts/lib/install/converters/cursor.cjs +20 -0
  81. package/scripts/lib/issue-reporter/report-flow.cjs +1 -1
  82. package/scripts/lib/manifest/skills.json +75 -28
  83. package/scripts/lib/state/query-surface.cjs +67 -9
  84. package/scripts/lib/state/state-store.cjs +68 -26
  85. package/scripts/lib/worktree-resolve.cjs +4 -16
  86. package/sdk/cli/commands/stage.ts +17 -0
  87. package/sdk/cli/index.js +14 -0
  88. package/skills/README.md +46 -0
  89. package/skills/bootstrap-ds/SKILL.md +1 -1
  90. package/skills/cache-manager/SKILL.md +3 -3
  91. package/skills/cache-manager/cache-policy.md +1 -1
  92. package/skills/compare/SKILL.md +1 -1
  93. package/skills/design/SKILL.md +19 -0
  94. package/skills/explore/SKILL.md +11 -0
  95. package/skills/figma-write/SKILL.md +13 -2
  96. package/skills/new-cycle/SKILL.md +1 -1
  97. package/skills/paper-write/SKILL.md +54 -0
  98. package/skills/peer-cli-customize/SKILL.md +0 -1
  99. package/skills/peers/SKILL.md +1 -1
  100. package/skills/pencil-write/SKILL.md +54 -0
  101. package/skills/reflect/procedures/capability-gap-scan.md +0 -1
  102. package/skills/report-issue/SKILL.md +2 -2
  103. package/skills/report-issue/report-issue-procedure.md +0 -1
  104. package/skills/router/SKILL.md +2 -2
  105. package/skills/synthesize/SKILL.md +1 -1
  106. package/skills/turn-closeout/SKILL.md +1 -1
  107. package/skills/verify/verify-procedure.md +10 -11
  108. package/skills/warm-cache/SKILL.md +1 -1
  109. package/dist/claude-code/.claude/skills/add-backlog/SKILL.md +0 -48
  110. package/dist/claude-code/.claude/skills/analyze-dependencies/SKILL.md +0 -95
  111. package/dist/claude-code/.claude/skills/apply-reflections/SKILL.md +0 -109
  112. package/dist/claude-code/.claude/skills/apply-reflections/apply-reflections-procedure.md +0 -170
  113. package/dist/claude-code/.claude/skills/audit/SKILL.md +0 -79
  114. package/dist/claude-code/.claude/skills/bandit-status/SKILL.md +0 -94
  115. package/dist/claude-code/.claude/skills/benchmark/SKILL.md +0 -65
  116. package/dist/claude-code/.claude/skills/bootstrap-ds/SKILL.md +0 -43
  117. package/dist/claude-code/.claude/skills/brief/SKILL.md +0 -145
  118. package/dist/claude-code/.claude/skills/budget/SKILL.md +0 -45
  119. package/dist/claude-code/.claude/skills/cache-manager/SKILL.md +0 -66
  120. package/dist/claude-code/.claude/skills/cache-manager/cache-policy.md +0 -126
  121. package/dist/claude-code/.claude/skills/check-update/SKILL.md +0 -98
  122. package/dist/claude-code/.claude/skills/compare/SKILL.md +0 -82
  123. package/dist/claude-code/.claude/skills/compare/compare-rubric.md +0 -171
  124. package/dist/claude-code/.claude/skills/complete-cycle/SKILL.md +0 -81
  125. package/dist/claude-code/.claude/skills/connections/SKILL.md +0 -71
  126. package/dist/claude-code/.claude/skills/connections/connections-onboarding.md +0 -608
  127. package/dist/claude-code/.claude/skills/context/SKILL.md +0 -137
  128. package/dist/claude-code/.claude/skills/continue/SKILL.md +0 -24
  129. package/dist/claude-code/.claude/skills/darkmode/SKILL.md +0 -76
  130. package/dist/claude-code/.claude/skills/darkmode/darkmode-audit-procedure.md +0 -258
  131. package/dist/claude-code/.claude/skills/debug/SKILL.md +0 -41
  132. package/dist/claude-code/.claude/skills/debug/debug-feedback-loops.md +0 -119
  133. package/dist/claude-code/.claude/skills/design/SKILL.md +0 -99
  134. package/dist/claude-code/.claude/skills/design/design-procedure.md +0 -304
  135. package/dist/claude-code/.claude/skills/discover/SKILL.md +0 -78
  136. package/dist/claude-code/.claude/skills/discover/discover-procedure.md +0 -222
  137. package/dist/claude-code/.claude/skills/discuss/SKILL.md +0 -96
  138. package/dist/claude-code/.claude/skills/do/SKILL.md +0 -45
  139. package/dist/claude-code/.claude/skills/explore/SKILL.md +0 -107
  140. package/dist/claude-code/.claude/skills/explore/explore-procedure.md +0 -267
  141. package/dist/claude-code/.claude/skills/export/SKILL.md +0 -30
  142. package/dist/claude-code/.claude/skills/extract-learnings/SKILL.md +0 -114
  143. package/dist/claude-code/.claude/skills/fast/SKILL.md +0 -91
  144. package/dist/claude-code/.claude/skills/figma-extract/SKILL.md +0 -64
  145. package/dist/claude-code/.claude/skills/figma-write/SKILL.md +0 -39
  146. package/dist/claude-code/.claude/skills/graphify/SKILL.md +0 -49
  147. package/dist/claude-code/.claude/skills/health/SKILL.md +0 -99
  148. package/dist/claude-code/.claude/skills/health/health-mcp-detection.md +0 -44
  149. package/dist/claude-code/.claude/skills/health/health-skill-length-report.md +0 -69
  150. package/dist/claude-code/.claude/skills/help/SKILL.md +0 -87
  151. package/dist/claude-code/.claude/skills/instinct/SKILL.md +0 -111
  152. package/dist/claude-code/.claude/skills/list-assumptions/SKILL.md +0 -61
  153. package/dist/claude-code/.claude/skills/list-pins/SKILL.md +0 -27
  154. package/dist/claude-code/.claude/skills/live/SKILL.md +0 -98
  155. package/dist/claude-code/.claude/skills/locale/SKILL.md +0 -51
  156. package/dist/claude-code/.claude/skills/map/SKILL.md +0 -89
  157. package/dist/claude-code/.claude/skills/migrate/SKILL.md +0 -70
  158. package/dist/claude-code/.claude/skills/migrate-context/SKILL.md +0 -123
  159. package/dist/claude-code/.claude/skills/new-addendum/SKILL.md +0 -81
  160. package/dist/claude-code/.claude/skills/new-cycle/SKILL.md +0 -37
  161. package/dist/claude-code/.claude/skills/new-cycle/milestone-completeness-rubric.md +0 -87
  162. package/dist/claude-code/.claude/skills/new-project/SKILL.md +0 -53
  163. package/dist/claude-code/.claude/skills/new-skill/SKILL.md +0 -90
  164. package/dist/claude-code/.claude/skills/next/SKILL.md +0 -68
  165. package/dist/claude-code/.claude/skills/note/SKILL.md +0 -48
  166. package/dist/claude-code/.claude/skills/openrouter-status/SKILL.md +0 -86
  167. package/dist/claude-code/.claude/skills/optimize/SKILL.md +0 -97
  168. package/dist/claude-code/.claude/skills/override/SKILL.md +0 -86
  169. package/dist/claude-code/.claude/skills/pause/SKILL.md +0 -77
  170. package/dist/claude-code/.claude/skills/peer-cli-add/SKILL.md +0 -88
  171. package/dist/claude-code/.claude/skills/peer-cli-add/peer-cli-protocol.md +0 -161
  172. package/dist/claude-code/.claude/skills/peer-cli-customize/SKILL.md +0 -90
  173. package/dist/claude-code/.claude/skills/peers/SKILL.md +0 -96
  174. package/dist/claude-code/.claude/skills/pin/SKILL.md +0 -37
  175. package/dist/claude-code/.claude/skills/plan/SKILL.md +0 -105
  176. package/dist/claude-code/.claude/skills/plan/plan-procedure.md +0 -278
  177. package/dist/claude-code/.claude/skills/plant-seed/SKILL.md +0 -48
  178. package/dist/claude-code/.claude/skills/pr-branch/SKILL.md +0 -32
  179. package/dist/claude-code/.claude/skills/progress/SKILL.md +0 -107
  180. package/dist/claude-code/.claude/skills/quality-gate/SKILL.md +0 -90
  181. package/dist/claude-code/.claude/skills/quality-gate/threat-modeling.md +0 -101
  182. package/dist/claude-code/.claude/skills/quick/SKILL.md +0 -44
  183. package/dist/claude-code/.claude/skills/reapply-patches/SKILL.md +0 -32
  184. package/dist/claude-code/.claude/skills/recall/SKILL.md +0 -75
  185. package/dist/claude-code/.claude/skills/reflect/SKILL.md +0 -85
  186. package/dist/claude-code/.claude/skills/reflect/procedures/capability-gap-scan.md +0 -120
  187. package/dist/claude-code/.claude/skills/report-issue/SKILL.md +0 -53
  188. package/dist/claude-code/.claude/skills/report-issue/report-issue-procedure.md +0 -120
  189. package/dist/claude-code/.claude/skills/resume/SKILL.md +0 -93
  190. package/dist/claude-code/.claude/skills/review-backlog/SKILL.md +0 -46
  191. package/dist/claude-code/.claude/skills/review-decisions/SKILL.md +0 -42
  192. package/dist/claude-code/.claude/skills/roi/SKILL.md +0 -54
  193. package/dist/claude-code/.claude/skills/rollout-status/SKILL.md +0 -35
  194. package/dist/claude-code/.claude/skills/router/SKILL.md +0 -89
  195. package/dist/claude-code/.claude/skills/router/capability-gap-emitter.md +0 -65
  196. package/dist/claude-code/.claude/skills/router/router-pick-emitter.md +0 -78
  197. package/dist/claude-code/.claude/skills/router/router-rules.md +0 -84
  198. package/dist/claude-code/.claude/skills/scan/SKILL.md +0 -92
  199. package/dist/claude-code/.claude/skills/scan/scan-procedure.md +0 -732
  200. package/dist/claude-code/.claude/skills/settings/SKILL.md +0 -87
  201. package/dist/claude-code/.claude/skills/ship/SKILL.md +0 -48
  202. package/dist/claude-code/.claude/skills/sketch/SKILL.md +0 -78
  203. package/dist/claude-code/.claude/skills/sketch-wrap-up/SKILL.md +0 -92
  204. package/dist/claude-code/.claude/skills/skill-manifest/SKILL.md +0 -79
  205. package/dist/claude-code/.claude/skills/spike/SKILL.md +0 -67
  206. package/dist/claude-code/.claude/skills/spike-wrap-up/SKILL.md +0 -86
  207. package/dist/claude-code/.claude/skills/start/SKILL.md +0 -67
  208. package/dist/claude-code/.claude/skills/start/start-procedure.md +0 -115
  209. package/dist/claude-code/.claude/skills/state/SKILL.md +0 -106
  210. package/dist/claude-code/.claude/skills/stats/SKILL.md +0 -51
  211. package/dist/claude-code/.claude/skills/style/SKILL.md +0 -71
  212. package/dist/claude-code/.claude/skills/style/style-doc-procedure.md +0 -150
  213. package/dist/claude-code/.claude/skills/synthesize/SKILL.md +0 -94
  214. package/dist/claude-code/.claude/skills/timeline/SKILL.md +0 -66
  215. package/dist/claude-code/.claude/skills/todo/SKILL.md +0 -64
  216. package/dist/claude-code/.claude/skills/turn-closeout/SKILL.md +0 -95
  217. package/dist/claude-code/.claude/skills/undo/SKILL.md +0 -31
  218. package/dist/claude-code/.claude/skills/unlock-decision/SKILL.md +0 -54
  219. package/dist/claude-code/.claude/skills/unpin/SKILL.md +0 -31
  220. package/dist/claude-code/.claude/skills/update/SKILL.md +0 -56
  221. package/dist/claude-code/.claude/skills/using-gdd/SKILL.md +0 -78
  222. package/dist/claude-code/.claude/skills/verify/SKILL.md +0 -113
  223. package/dist/claude-code/.claude/skills/verify/verify-procedure.md +0 -512
  224. package/dist/claude-code/.claude/skills/warm-cache/SKILL.md +0 -81
  225. package/dist/claude-code/.claude/skills/watch-authorities/SKILL.md +0 -82
  226. package/dist/claude-code/.claude/skills/zoom-out/SKILL.md +0 -26
  227. package/hooks/first-run-nudge.sh +0 -82
  228. package/hooks/inject-using-gdd.sh +0 -72
  229. package/hooks/run-hook.cmd +0 -35
  230. package/hooks/update-check.sh +0 -251
  231. package/scripts/lib/audit-aggregator/index.cjs +0 -219
  232. package/scripts/lib/hedge-ensemble.cjs +0 -217
  233. package/skills/discover/SKILL.md +0 -78
  234. package/skills/discover/discover-procedure.md +0 -222
  235. package/skills/new-cycle/milestone-completeness-rubric.md +0 -87
  236. package/skills/scan/SKILL.md +0 -92
  237. package/skills/scan/scan-procedure.md +0 -732
@@ -1,82 +0,0 @@
1
- ---
2
- name: gdd-watch-authorities
3
- description: "Fetches the design-authority feed whitelist, diffs against .design/authority-snapshot.json, and writes .design/authority-report.md (consumed by /gdd:reflect). Authority monitoring only - no trend-watching."
4
- argument-hint: "[--refresh] [--since <date>] [--feed <name>] [--schedule <weekly|daily|monthly>]"
5
- tools: Read, Write, Task, Bash
6
- ---
7
-
8
- # /gdd:watch-authorities
9
-
10
- Runs `design-authority-watcher` on demand. Fetches the curated design-authority feed whitelist, diffs against the prior snapshot, classifies new entries into five buckets, and writes `.design/authority-report.md`. Phase 11's reflector picks up the report automatically when you next run `/gdd:reflect`.
11
-
12
- Authority-monitoring only. Not trend-watching. See `reference/authority-feeds.md` §"Rejected kinds" for what this skill will never fetch.
13
-
14
- ## Steps
15
-
16
- 1. **Parse args.** Extract optional flags: `--refresh`, `--since <date>`, `--feed <name>`, `--schedule <cadence>`. Anything that doesn't match one of these is an error - print `Unknown flag: <arg>. Valid flags: --refresh --since <date> --feed <name> --schedule <weekly|daily|monthly>.` and STOP.
17
-
18
- Mutual exclusion rules:
19
- - `--schedule` is handled entirely by this skill - it does not combine with the other three. If `--schedule` is present alongside any of `--refresh | --since | --feed`, print `--schedule cannot combine with other flags. Schedule registration runs this skill with no flags at the configured cadence.` and STOP.
20
- - `--refresh` and `--since` are mutually exclusive - print `--refresh and --since are mutually exclusive. --refresh re-seeds the snapshot silently; --since surfaces a backlog from a boundary date. Pick one.` and STOP.
21
-
22
- 2. **Handle `--schedule <cadence>` branch** (early-return).
23
-
24
- If `--schedule` is set:
25
- - Validate cadence ∈ {`weekly`, `daily`, `monthly`}; else print `Unknown cadence: <value>. Use one of: weekly, daily, monthly.` and STOP.
26
- - Probe for the scheduled-tasks MCP via ToolSearch:
27
-
28
- ```
29
- ToolSearch({ query: "scheduled-tasks", max_results: 3 })
30
- ```
31
-
32
- - If the probe returns an empty result set: print `scheduled-tasks MCP not connected. Install it with: claude mcp add scheduled-tasks ... then retry with --schedule.` - this is a documented fallback (not an error). Terminate with `## WATCH COMPLETE` and exit 0.
33
- - If the probe returns one or more `scheduled-tasks` tools: register the cron. Discover the MCP's registration tool name at runtime from the ToolSearch result and follow its schema. Target command: `/gdd:watch-authorities` with NO flags (the cron invokes the default diff-and-report behavior). Cadence → cron expression mapping:
34
- - `weekly` → `0 9 * * 1` (Mondays 09:00 local)
35
- - `daily` → `0 9 * * *` (every day 09:00 local)
36
- - `monthly` → `0 9 1 * *` (1st of each month 09:00 local)
37
- - After registration: print `Scheduled /gdd:watch-authorities to run <cadence>.` and terminate with `## WATCH COMPLETE`.
38
-
39
- 3. **Validate `--since <date>`** (if present).
40
-
41
- Accept ISO8601 (`YYYY-MM-DD` or `YYYY-MM-DDTHH:MM:SSZ`). Sanity-check via Bash `date -d "<value>" +%s` (GNU) or the POSIX equivalent `python3 -c "from datetime import datetime; datetime.fromisoformat('<value>'.replace('Z','+00:00'))"`. On parse failure: print `Invalid --since value: <value>. Use ISO8601 (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ).` and STOP.
42
-
43
- If the parsed date is earlier than `2020-01-01`, ask: `Very old --since value: <value>. Did you mean something more recent? Proceed? [y/N]`. On anything other than `y`/`Y`, STOP.
44
-
45
- 4. **Spawn the watcher.**
46
-
47
- Build the `Task(subagent_type="design-authority-watcher", ...)` prompt. The prompt supplies the agent's required-reading block (watcher step 0), echoes the invocation flags verbatim (watcher Flags section), and instructs the agent to follow its own fetch/diff/classify/write loop:
48
-
49
- ```
50
- Task("design-authority-watcher", """
51
- <required_reading>
52
- @reference/authority-feeds.md
53
- @.design/authority-snapshot.json
54
- @.design/STATE.md
55
- </required_reading>
56
-
57
- Invocation flags: <joined flag list or "none">
58
-
59
- Fetch the feeds listed in reference/authority-feeds.md, diff against .design/authority-snapshot.json,
60
- classify new entries per the D-17 decision table, write .design/authority-snapshot.json and
61
- .design/authority-report.md.
62
-
63
- Terminate with ## WATCH COMPLETE.
64
- """)
65
- ```
66
-
67
- `<joined flag list>` is the subset of `--refresh | --since <date> | --feed <name>` actually passed - e.g., `--refresh`, `--since 2026-03-01`, `--feed wai-aria-apg`, `--refresh --feed radix-ui-releases`, or literally `none` when no flags were supplied.
68
-
69
- 5. **Print summary.**
70
-
71
- After the agent returns:
72
- - If STATE.md gained a `<blocker type="contract-violation">` on this run (snapshot version mismatch, hash-format violation, or over-200 entries per feed), surface the blocker verbatim and stop - do not print the default "review and reflect" line.
73
- - Otherwise print the agent's one-line stdout summary (normal mode: `Surfaced N entries across M feeds. K skipped. See .design/authority-report.md.`; first-run / refresh mode: `Seeded snapshot for N feeds — next run will surface new entries.`) followed by: `Review and reflect: /gdd:reflect`.
74
-
75
- 6. **Terminate with `## WATCH COMPLETE`.**
76
-
77
- ## Do Not
78
-
79
- - Do not modify `agents/design-authority-watcher.md`.
80
- - Do not modify `agents/design-reflector.md` - Phase 13.2 does not touch the reflector agent (CONTEXT.md D-25).
81
- - Do not write to `.design/authority-snapshot.json` or `.design/authority-report.md` directly - those are the agent's writes.
82
- - Do not fetch URLs outside `reference/authority-feeds.md`. The whitelist is the allow-list.
@@ -1,26 +0,0 @@
1
- ---
2
- name: zoom-out
3
- description: "Asks the agent to go up a layer of abstraction and map the relevant modules and callers using the project's CONTEXT.md vocabulary. Use when the user is working in an unfamiliar area of code and needs orientation before deep work."
4
- disable-model-invocation: true
5
- argument-hint: "[scope]"
6
- ---
7
-
8
- Source: mattpocock/skills (MIT) - adapted with permission. See `../NOTICE` for the full attribution block.
9
-
10
- # Zoom Out
11
-
12
- **Role:** Give the user a map, not a fix.
13
-
14
- I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary (`CONTEXT.md`) vocabulary.
15
-
16
- When invoked, produce a one-screen map that names:
17
-
18
- 1. **Modules in scope** - one-line description of each, using terms from `CONTEXT.md` (see `./../reference/context-md-format.md` for the schema). Do not invent terms.
19
- 2. **Callers** - who calls these modules from elsewhere, with file paths.
20
- 3. **Seams** - where data crosses module boundaries, named per `./../reference/architecture-vocabulary.md`.
21
-
22
- Do not propose fixes. Do not write code. The output is a map.
23
-
24
- If `CONTEXT.md` is absent, suggest `/gdd:discuss` to start one, but still produce the map using basenames and inferred terms.
25
-
26
- ## ZOOM-OUT COMPLETE
@@ -1,82 +0,0 @@
1
- #!/usr/bin/env bash
2
- # get-design-done — first-run nudge (Phase 14.7)
3
- # SessionStart hook. Silent-on-failure by policy: exits 0 on every error path.
4
- # Prints exactly one restrained line pointing at /gdd:start when all gates pass,
5
- # and nothing otherwise.
6
-
7
- set -u # intentionally no -e: we want to fall through to exit 0
8
-
9
- # Silent logger — writes nothing by default. Set GDD_NUDGE_DEBUG=1 to enable stderr.
10
- log() {
11
- if [ "${GDD_NUDGE_DEBUG:-0}" = "1" ]; then
12
- printf '[gdd first-run-nudge] %s\n' "$*" >&2
13
- fi
14
- }
15
-
16
- DESIGN_DIR="$(pwd)/.design"
17
- STATE="${DESIGN_DIR}/STATE.md"
18
- CONFIG="${DESIGN_DIR}/config.json"
19
- DISMISS_FLAG="${HOME:-$USERPROFILE}/.claude/gdd-nudge-dismissed"
20
-
21
- # Gate 1 — repo already has GDD state, suppress.
22
- has_design_state() {
23
- [ -f "${CONFIG}" ] || [ -f "${STATE}" ]
24
- }
25
-
26
- # Gate 2 — per-install dismissal flag.
27
- is_dismissed() {
28
- [ -f "${DISMISS_FLAG}" ]
29
- }
30
-
31
- # Gate 3 — STATE.md stage belongs to an active pipeline window.
32
- # Inherits the shape used by Phase 13.3 update-check.sh.
33
- read_state_stage() {
34
- [ -f "${STATE}" ] || { printf ''; return; }
35
- grep -E '^stage:' "${STATE}" 2>/dev/null | head -n1 | \
36
- sed -E 's/^stage:[[:space:]]*"?([^"[:space:]]+)"?.*/\1/'
37
- }
38
-
39
- is_active_stage() {
40
- local s
41
- s="$(read_state_stage)"
42
- case "${s}" in
43
- plan|design|verify|executing|discussing) return 0 ;;
44
- *) return 1 ;;
45
- esac
46
- }
47
-
48
- # Gate 4 — recent session history has a gdd:* command. We cannot reliably read
49
- # session history from a hook in all runtimes; when the signal is unavailable,
50
- # treat it as "unknown → not suppressed". This preserves the nudge's
51
- # usefulness without creating false suppression.
52
- has_recent_gdd_command() {
53
- # Placeholder: no portable transcript path exposed to SessionStart hooks today.
54
- # Keep the function for future wiring; for now always returns non-zero (unknown).
55
- return 1
56
- }
57
-
58
- # MANDATORY sourcing guard: unit tests source this script to test the helper
59
- # functions without executing the main flow. Non-negotiable.
60
- if [ "${BASH_SOURCE[0]}" = "$0" ]; then
61
- if has_design_state; then
62
- log "design state present — suppress"
63
- exit 0
64
- fi
65
- if is_dismissed; then
66
- log "dismissal flag present — suppress"
67
- exit 0
68
- fi
69
- if is_active_stage; then
70
- log "active stage — suppress"
71
- exit 0
72
- fi
73
- if has_recent_gdd_command; then
74
- log "recent gdd:* command detected — suppress"
75
- exit 0
76
- fi
77
- # All gates passed — emit the locked one-line nudge.
78
- printf 'Tip: run /gdd:start to let GDD inspect this codebase and suggest one first fix.\n'
79
- exit 0
80
- fi
81
- # When sourced (BASH_SOURCE != $0), fall through with function definitions loaded
82
- # and without side effects.
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env bash
2
- # hooks/inject-using-gdd.sh — SessionStart per-harness context injector (D-07).
3
- #
4
- # The forcing function GDD lacked: on every session start / /clear / compact this
5
- # reads skills/using-gdd/SKILL.md (the bootstrap discipline contract) and emits it
6
- # as the host harness's SessionStart "additionalContext" shape so the agent is
7
- # primed with the 1%-rule + red-flags + skill-priority before it acts.
8
- #
9
- # Ported MECHANISM (not content) from obra/superpowers (MIT): one polyglot script,
10
- # env-var branch, pure-bash escape_for_json (no jq/python dependency). See NOTICE.
11
- #
12
- # Three emitted shapes (ONE JSON object on stdout, nothing else):
13
- # Cursor (CURSOR_PLUGIN_ROOT set) -> {"additional_context": "<escaped>"}
14
- # Claude Code (CLAUDE_PLUGIN_ROOT set, no Cursor)
15
- # -> {"hookSpecificOutput":
16
- # {"hookEventName":"SessionStart",
17
- # "additionalContext":"<escaped>"}}
18
- # SDK-standard (neither; e.g. COPILOT_CLI) -> {"additionalContext": "<escaped>"}
19
- #
20
- # Branch order: check Cursor BEFORE Claude Code — a Cursor session may also export
21
- # CLAUDE_PLUGIN_ROOT, and Cursor's own var must win.
22
- #
23
- # NO-CASCADE (D-06): this script is wired ONLY under the SessionStart hook event in
24
- # hooks/hooks.json. Subagent spawns do not fire SessionStart, so the inject cannot
25
- # cascade into a subagent's context. (Structural guarantee; behavioral proof = P33.)
26
-
27
- set -u
28
-
29
- # --- Resolve the plugin root so we can locate skills/using-gdd/SKILL.md ---------
30
- # Prefer the harness-provided roots; fall back to this script's parent dir so the
31
- # emitter is runnable straight from hooks/ in tests and in bare shells.
32
- SELF_DIR="$(cd "$(dirname "$0")" && pwd)"
33
- ROOT="${CURSOR_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-${SELF_DIR}/..}}"
34
- ROOT="${ROOT//\\//}" # normalize Windows backslashes to forward slashes
35
- SKILL="${ROOT}/skills/using-gdd/SKILL.md"
36
-
37
- # Defensive: if the skill file is missing we must STILL emit a syntactically valid
38
- # JSON object (an empty additionalContext) so the SessionStart pipeline never
39
- # breaks on a partial install. Never crash the session start.
40
- if [[ -r "${SKILL}" ]]; then
41
- CONTENT="$(cat "${SKILL}")"
42
- else
43
- CONTENT=""
44
- fi
45
-
46
- # --- escape_for_json (superpowers pattern; pure bash param-substitution) --------
47
- # Order matters: backslash FIRST (so escapes we add next aren't re-escaped), then
48
- # double-quote, then the control chars newline / tab / carriage-return. Emits the
49
- # value WITH surrounding double-quotes so callers can splice it directly.
50
- escape_for_json() {
51
- local s="$1"
52
- s="${s//\\/\\\\}" # \ -> \\
53
- s="${s//\"/\\\"}" # " -> \"
54
- s="${s//$'\t'/\\t}" # tab -> \t
55
- s="${s//$'\r'/\\r}" # CR -> \r
56
- s="${s//$'\n'/\\n}" # LF -> \n (do last: newlines are the record separator)
57
- printf '"%s"' "$s"
58
- }
59
-
60
- ESCAPED="$(escape_for_json "${CONTENT}")"
61
-
62
- # --- Branch on harness env vars and emit the matching single JSON object --------
63
- if [[ -n "${CURSOR_PLUGIN_ROOT:-}" ]]; then
64
- # Cursor: top-level additional_context.
65
- printf '{"additional_context": %s}\n' "${ESCAPED}"
66
- elif [[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]]; then
67
- # Claude Code: hookSpecificOutput envelope (mirrors hooks/gdd-decision-injector.js).
68
- printf '{"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": %s}}\n' "${ESCAPED}"
69
- else
70
- # SDK-standard (COPILOT_CLI or none): top-level additionalContext.
71
- printf '{"additionalContext": %s}\n' "${ESCAPED}"
72
- fi
@@ -1,35 +0,0 @@
1
- @echo off
2
- REM hooks/run-hook.cmd — Windows polyglot wrapper that invokes a GDD .sh hook
3
- REM through bash.
4
- REM
5
- REM Workaround for Claude Code's Windows auto-bash bug: CC can mis-handle a
6
- REM SessionStart `command` that points directly at a `.sh` file on Windows
7
- REM shells. This .cmd shim locates bash and runs the script explicitly, so the
8
- REM SessionStart inject (hooks/inject-using-gdd.sh) fires on Windows too.
9
- REM
10
- REM Usage: run-hook.cmd <script-name.sh> [args...]
11
- REM Default (no arg): inject-using-gdd.sh — the SessionStart using-gdd injector.
12
- REM The host harness's env (CLAUDE_PLUGIN_ROOT / CURSOR_PLUGIN_ROOT / COPILOT_CLI)
13
- REM is inherited by bash and drives the emitter's per-harness branch.
14
- setlocal
15
-
16
- REM Script to run, relative to this .cmd's own directory (%~dp0 ends with a backslash).
17
- set "HOOK_SCRIPT=%~1"
18
- if "%HOOK_SCRIPT%"=="" set "HOOK_SCRIPT=inject-using-gdd.sh"
19
- if not "%~1"=="" shift
20
-
21
- set "HOOK_PATH=%~dp0%HOOK_SCRIPT%"
22
-
23
- REM Prefer bash on PATH; fall back to a typical Git-for-Windows install location.
24
- where bash >nul 2>nul
25
- if %ERRORLEVEL%==0 (
26
- bash "%HOOK_PATH%" %*
27
- ) else if exist "%ProgramFiles%\Git\bin\bash.exe" (
28
- "%ProgramFiles%\Git\bin\bash.exe" "%HOOK_PATH%" %*
29
- ) else (
30
- REM No bash available: emit a valid empty SDK-shape JSON object so the
31
- REM SessionStart pipeline still receives parseable output and never breaks.
32
- echo {"additionalContext": ""}
33
- )
34
-
35
- endlocal
@@ -1,251 +0,0 @@
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.