design-agent-skills 1.4.2

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 (262) hide show
  1. package/README.md +380 -0
  2. package/VERSION +1 -0
  3. package/bin/cli.mjs +45 -0
  4. package/bootstrap.sh +32 -0
  5. package/install.sh +689 -0
  6. package/package.json +36 -0
  7. package/skills/accessibility-agents/SKILL.md +52 -0
  8. package/skills/accessibility-agents/stub.yaml +5 -0
  9. package/skills/accessibility-catalogue/SKILL.md +45 -0
  10. package/skills/accessibility-catalogue/stub.yaml +3 -0
  11. package/skills/addyosmani-quality/SKILL.md +72 -0
  12. package/skills/addyosmani-quality/stub.yaml +6 -0
  13. package/skills/ai-graphic-design-skill/SKILL.md +65 -0
  14. package/skills/ai-graphic-design-skill/stub.yaml +5 -0
  15. package/skills/algorithmic-art/SKILL.md +59 -0
  16. package/skills/algorithmic-art/stub.yaml +5 -0
  17. package/skills/animate-css-skill/SKILL.md +55 -0
  18. package/skills/animate-css-skill/stub.yaml +5 -0
  19. package/skills/animate-skill/SKILL.md +64 -0
  20. package/skills/animate-skill/stub.yaml +5 -0
  21. package/skills/anthropics-skills/SKILL.md +72 -0
  22. package/skills/anthropics-skills/stub.yaml +12 -0
  23. package/skills/antvis-chart-skills/SKILL.md +61 -0
  24. package/skills/antvis-chart-skills/stub.yaml +6 -0
  25. package/skills/apple-hig-skills/SKILL.md +66 -0
  26. package/skills/apple-hig-skills/stub.yaml +6 -0
  27. package/skills/baseline-ui/SKILL.md +54 -0
  28. package/skills/baseline-ui/stub.yaml +5 -0
  29. package/skills/bencium-ux-designer/SKILL.md +54 -0
  30. package/skills/bencium-ux-designer/stub.yaml +5 -0
  31. package/skills/brand-design-md/SKILL.md +65 -0
  32. package/skills/brand-design-md/stub.yaml +5 -0
  33. package/skills/callstack-agent-skills/SKILL.md +56 -0
  34. package/skills/callstack-agent-skills/stub.yaml +6 -0
  35. package/skills/cc-slidev/SKILL.md +54 -0
  36. package/skills/cc-slidev/stub.yaml +5 -0
  37. package/skills/claud3/SKILL.md +54 -0
  38. package/skills/claud3/stub.yaml +5 -0
  39. package/skills/claude-pm-skills/SKILL.md +53 -0
  40. package/skills/claude-pm-skills/stub.yaml +5 -0
  41. package/skills/claude-wireframe-skill/SKILL.md +63 -0
  42. package/skills/claude-wireframe-skill/stub.yaml +5 -0
  43. package/skills/claude2figma/SKILL.md +54 -0
  44. package/skills/claude2figma/stub.yaml +5 -0
  45. package/skills/claudedesignskills/SKILL.md +59 -0
  46. package/skills/claudedesignskills/stub.yaml +5 -0
  47. package/skills/cloudai-threejs/SKILL.md +51 -0
  48. package/skills/cloudai-threejs/stub.yaml +6 -0
  49. package/skills/cloudflare-web-perf/SKILL.md +60 -0
  50. package/skills/cloudflare-web-perf/stub.yaml +5 -0
  51. package/skills/color-expert/SKILL.md +62 -0
  52. package/skills/color-expert/stub.yaml +5 -0
  53. package/skills/composio-artifacts/SKILL.md +63 -0
  54. package/skills/composio-artifacts/stub.yaml +5 -0
  55. package/skills/content-catalogue/SKILL.md +105 -0
  56. package/skills/content-catalogue/stub.yaml +3 -0
  57. package/skills/coreyhaines-marketing/SKILL.md +59 -0
  58. package/skills/coreyhaines-marketing/stub.yaml +6 -0
  59. package/skills/creative-director/SKILL.md +60 -0
  60. package/skills/creative-director/stub.yaml +5 -0
  61. package/skills/css-animation-skill/SKILL.md +63 -0
  62. package/skills/css-animation-skill/stub.yaml +5 -0
  63. package/skills/d3js-skill/SKILL.md +58 -0
  64. package/skills/d3js-skill/stub.yaml +5 -0
  65. package/skills/data-analysis-skill/SKILL.md +64 -0
  66. package/skills/data-analysis-skill/stub.yaml +5 -0
  67. package/skills/data-viz-agent/SKILL.md +60 -0
  68. package/skills/data-viz-agent/stub.yaml +5 -0
  69. package/skills/deanpeters-pm-skills/SKILL.md +76 -0
  70. package/skills/deanpeters-pm-skills/stub.yaml +6 -0
  71. package/skills/design-auditor/SKILL.md +62 -0
  72. package/skills/design-auditor/stub.yaml +5 -0
  73. package/skills/design-brief/SKILL.md +58 -0
  74. package/skills/design-brief/stub.yaml +5 -0
  75. package/skills/design-catalogue/SKILL.md +346 -0
  76. package/skills/design-catalogue/stub.yaml +3 -0
  77. package/skills/design-consultation/SKILL.md +58 -0
  78. package/skills/design-consultation/stub.yaml +5 -0
  79. package/skills/design-engineering-catalogue/SKILL.md +92 -0
  80. package/skills/design-engineering-catalogue/stub.yaml +3 -0
  81. package/skills/design-for-ai/SKILL.md +58 -0
  82. package/skills/design-for-ai/stub.yaml +5 -0
  83. package/skills/design-html/SKILL.md +59 -0
  84. package/skills/design-html/stub.yaml +5 -0
  85. package/skills/design-lab/SKILL.md +54 -0
  86. package/skills/design-lab/stub.yaml +5 -0
  87. package/skills/design-review-garrytan/SKILL.md +58 -0
  88. package/skills/design-review-garrytan/stub.yaml +5 -0
  89. package/skills/design-tokens-skill/SKILL.md +68 -0
  90. package/skills/design-tokens-skill/stub.yaml +5 -0
  91. package/skills/design-with-claude/SKILL.md +51 -0
  92. package/skills/design-with-claude/stub.yaml +5 -0
  93. package/skills/designer-skills/SKILL.md +52 -0
  94. package/skills/designer-skills/stub.yaml +5 -0
  95. package/skills/digidai-pm/SKILL.md +60 -0
  96. package/skills/digidai-pm/stub.yaml +5 -0
  97. package/skills/distinctive-frontend/SKILL.md +55 -0
  98. package/skills/distinctive-frontend/stub.yaml +5 -0
  99. package/skills/email-html-mjml/SKILL.md +54 -0
  100. package/skills/email-html-mjml/stub.yaml +5 -0
  101. package/skills/emilkowalski-skill/SKILL.md +60 -0
  102. package/skills/emilkowalski-skill/stub.yaml +7 -0
  103. package/skills/excalidraw-agents365/SKILL.md +56 -0
  104. package/skills/excalidraw-agents365/stub.yaml +5 -0
  105. package/skills/excalidraw-diagram/SKILL.md +58 -0
  106. package/skills/excalidraw-diagram/stub.yaml +5 -0
  107. package/skills/expo-skills/SKILL.md +56 -0
  108. package/skills/expo-skills/stub.yaml +21 -0
  109. package/skills/extract-design-md/SKILL.md +58 -0
  110. package/skills/extract-design-md/stub.yaml +5 -0
  111. package/skills/extract-design-system/SKILL.md +53 -0
  112. package/skills/extract-design-system/stub.yaml +5 -0
  113. package/skills/fal-ai-skills/SKILL.md +56 -0
  114. package/skills/fal-ai-skills/stub.yaml +6 -0
  115. package/skills/figma-catalogue/SKILL.md +57 -0
  116. package/skills/figma-catalogue/stub.yaml +3 -0
  117. package/skills/figma-official-skills/SKILL.md +80 -0
  118. package/skills/figma-official-skills/stub.yaml +6 -0
  119. package/skills/figma-skill/SKILL.md +52 -0
  120. package/skills/figma-skill/stub.yaml +5 -0
  121. package/skills/figma-variables-tokens-generator/SKILL.md +54 -0
  122. package/skills/figma-variables-tokens-generator/stub.yaml +5 -0
  123. package/skills/fixing-accessibility/SKILL.md +54 -0
  124. package/skills/fixing-accessibility/stub.yaml +5 -0
  125. package/skills/fixing-motion-performance/SKILL.md +54 -0
  126. package/skills/fixing-motion-performance/stub.yaml +5 -0
  127. package/skills/framer-motion-skills/SKILL.md +55 -0
  128. package/skills/framer-motion-skills/stub.yaml +5 -0
  129. package/skills/frontend-design/SKILL.md +65 -0
  130. package/skills/frontend-design/stub.yaml +5 -0
  131. package/skills/frontend-slides/SKILL.md +59 -0
  132. package/skills/frontend-slides/stub.yaml +5 -0
  133. package/skills/generative-media-skills/SKILL.md +56 -0
  134. package/skills/generative-media-skills/stub.yaml +4 -0
  135. package/skills/google-fonts-skill/SKILL.md +69 -0
  136. package/skills/google-fonts-skill/stub.yaml +4 -0
  137. package/skills/google-stitch-skills/SKILL.md +71 -0
  138. package/skills/google-stitch-skills/stub.yaml +6 -0
  139. package/skills/gsap-skills/SKILL.md +55 -0
  140. package/skills/gsap-skills/stub.yaml +5 -0
  141. package/skills/guizang-ppt/SKILL.md +58 -0
  142. package/skills/guizang-ppt/stub.yaml +5 -0
  143. package/skills/hand-drawn-diagrams/SKILL.md +57 -0
  144. package/skills/hand-drawn-diagrams/stub.yaml +5 -0
  145. package/skills/hig-doctor/SKILL.md +59 -0
  146. package/skills/hig-doctor/stub.yaml +6 -0
  147. package/skills/huashu-design/SKILL.md +64 -0
  148. package/skills/huashu-design/stub.yaml +5 -0
  149. package/skills/hyperframes/SKILL.md +60 -0
  150. package/skills/hyperframes/stub.yaml +5 -0
  151. package/skills/impeccable/SKILL.md +75 -0
  152. package/skills/impeccable/stub.yaml +8 -0
  153. package/skills/ink-google/SKILL.md +58 -0
  154. package/skills/ink-google/stub.yaml +5 -0
  155. package/skills/interface-design-dammyjay/SKILL.md +55 -0
  156. package/skills/interface-design-dammyjay/stub.yaml +5 -0
  157. package/skills/liquid-glass-skill/SKILL.md +54 -0
  158. package/skills/liquid-glass-skill/stub.yaml +5 -0
  159. package/skills/logo-designer-skill/SKILL.md +56 -0
  160. package/skills/logo-designer-skill/stub.yaml +5 -0
  161. package/skills/make-interfaces-better/SKILL.md +60 -0
  162. package/skills/make-interfaces-better/stub.yaml +5 -0
  163. package/skills/markdown-viewer-skills/SKILL.md +70 -0
  164. package/skills/markdown-viewer-skills/stub.yaml +6 -0
  165. package/skills/marp-slide-quality/SKILL.md +63 -0
  166. package/skills/marp-slide-quality/stub.yaml +5 -0
  167. package/skills/marp-slides/SKILL.md +63 -0
  168. package/skills/marp-slides/stub.yaml +5 -0
  169. package/skills/mastepanoski-skills/SKILL.md +52 -0
  170. package/skills/mastepanoski-skills/stub.yaml +5 -0
  171. package/skills/microsoft-skills/SKILL.md +51 -0
  172. package/skills/microsoft-skills/stub.yaml +6 -0
  173. package/skills/mobile-app-design/SKILL.md +67 -0
  174. package/skills/mobile-app-design/stub.yaml +5 -0
  175. package/skills/mobile-app-ui-design/SKILL.md +65 -0
  176. package/skills/mobile-app-ui-design/stub.yaml +5 -0
  177. package/skills/motion-catalogue/SKILL.md +69 -0
  178. package/skills/motion-catalogue/stub.yaml +3 -0
  179. package/skills/motion-design-skill/SKILL.md +55 -0
  180. package/skills/motion-design-skill/stub.yaml +5 -0
  181. package/skills/nanobanan-ppt/SKILL.md +64 -0
  182. package/skills/nanobanan-ppt/stub.yaml +5 -0
  183. package/skills/neo-user-journey/SKILL.md +62 -0
  184. package/skills/neo-user-journey/stub.yaml +5 -0
  185. package/skills/nimbalyst-skills/SKILL.md +59 -0
  186. package/skills/nimbalyst-skills/stub.yaml +7 -0
  187. package/skills/open-design/SKILL.md +55 -0
  188. package/skills/open-design/stub.yaml +4 -0
  189. package/skills/openai-skills/SKILL.md +67 -0
  190. package/skills/openai-skills/stub.yaml +6 -0
  191. package/skills/p5js-hermes/SKILL.md +62 -0
  192. package/skills/p5js-hermes/stub.yaml +5 -0
  193. package/skills/phuryn-pm-skills/SKILL.md +56 -0
  194. package/skills/phuryn-pm-skills/stub.yaml +6 -0
  195. package/skills/plan-design-review/SKILL.md +58 -0
  196. package/skills/plan-design-review/stub.yaml +5 -0
  197. package/skills/platform-design-skills/SKILL.md +52 -0
  198. package/skills/platform-design-skills/stub.yaml +6 -0
  199. package/skills/pm-skills/SKILL.md +55 -0
  200. package/skills/pm-skills/stub.yaml +5 -0
  201. package/skills/react-doctor/SKILL.md +55 -0
  202. package/skills/react-doctor/stub.yaml +5 -0
  203. package/skills/remotion/SKILL.md +59 -0
  204. package/skills/remotion/stub.yaml +5 -0
  205. package/skills/revealjs-skill/SKILL.md +54 -0
  206. package/skills/revealjs-skill/stub.yaml +5 -0
  207. package/skills/shadcn-ui/SKILL.md +54 -0
  208. package/skills/shadcn-ui/stub.yaml +5 -0
  209. package/skills/shader-dev/SKILL.md +60 -0
  210. package/skills/shader-dev/stub.yaml +5 -0
  211. package/skills/simota-agent-skills/SKILL.md +53 -0
  212. package/skills/simota-agent-skills/stub.yaml +5 -0
  213. package/skills/sleek-design-mobile-apps/SKILL.md +56 -0
  214. package/skills/sleek-design-mobile-apps/stub.yaml +4 -0
  215. package/skills/slidev-skill/SKILL.md +54 -0
  216. package/skills/slidev-skill/stub.yaml +5 -0
  217. package/skills/softaworks-agent-toolkit/SKILL.md +58 -0
  218. package/skills/softaworks-agent-toolkit/stub.yaml +6 -0
  219. package/skills/software-mansion-skills/SKILL.md +63 -0
  220. package/skills/software-mansion-skills/stub.yaml +11 -0
  221. package/skills/superdesign-skill/SKILL.md +53 -0
  222. package/skills/superdesign-skill/stub.yaml +4 -0
  223. package/skills/swiftui-claude-skills/SKILL.md +54 -0
  224. package/skills/swiftui-claude-skills/stub.yaml +5 -0
  225. package/skills/swiftui-patterns/SKILL.md +54 -0
  226. package/skills/swiftui-patterns/stub.yaml +5 -0
  227. package/skills/taste-design-stitch/SKILL.md +58 -0
  228. package/skills/taste-design-stitch/stub.yaml +5 -0
  229. package/skills/taste-skill/SKILL.md +74 -0
  230. package/skills/taste-skill/stub.yaml +5 -0
  231. package/skills/threejs-claude-skill-package/SKILL.md +54 -0
  232. package/skills/threejs-claude-skill-package/stub.yaml +5 -0
  233. package/skills/threejs-ecs-ts/SKILL.md +54 -0
  234. package/skills/threejs-ecs-ts/stub.yaml +5 -0
  235. package/skills/tui-design-skill/SKILL.md +56 -0
  236. package/skills/tui-design-skill/stub.yaml +5 -0
  237. package/skills/ui-craft/SKILL.md +58 -0
  238. package/skills/ui-craft/stub.yaml +5 -0
  239. package/skills/ui-ux-pro-max/SKILL.md +64 -0
  240. package/skills/ui-ux-pro-max/stub.yaml +7 -0
  241. package/skills/ux-designer-skill/SKILL.md +62 -0
  242. package/skills/ux-designer-skill/stub.yaml +5 -0
  243. package/skills/ux-ui-mastery/SKILL.md +53 -0
  244. package/skills/ux-ui-mastery/stub.yaml +5 -0
  245. package/skills/vercel-skills/SKILL.md +65 -0
  246. package/skills/vercel-skills/stub.yaml +6 -0
  247. package/skills/wcag-ai-skill/SKILL.md +52 -0
  248. package/skills/wcag-ai-skill/stub.yaml +5 -0
  249. package/skills/wcag-audit-patterns/SKILL.md +53 -0
  250. package/skills/wcag-audit-patterns/stub.yaml +5 -0
  251. package/skills/webgpu-claude-skill/SKILL.md +54 -0
  252. package/skills/webgpu-claude-skill/stub.yaml +5 -0
  253. package/skills/wiggle-claude-skill/SKILL.md +63 -0
  254. package/skills/wiggle-claude-skill/stub.yaml +5 -0
  255. package/skills/wireframe-skill/SKILL.md +63 -0
  256. package/skills/wireframe-skill/stub.yaml +5 -0
  257. package/skills/wireframer/SKILL.md +59 -0
  258. package/skills/wireframer/stub.yaml +5 -0
  259. package/skills/wondelai-skills/SKILL.md +57 -0
  260. package/skills/wondelai-skills/stub.yaml +11 -0
  261. package/skills/work-with-design-systems/SKILL.md +67 -0
  262. package/skills/work-with-design-systems/stub.yaml +5 -0
package/install.sh ADDED
@@ -0,0 +1,689 @@
1
+ #!/usr/bin/env bash
2
+ # design-agent-skills installer — works with bash 3.2+
3
+ # Usage: ./install.sh [--scope=user|project] [install|status|update|fix|help]
4
+ set -euo pipefail
5
+
6
+ REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ SKILLS_SRC="$REPO_DIR/skills"
8
+ LOCKFILE="$REPO_DIR/design-agent-skills.lock"
9
+
10
+ # ── Parse global flags ────────────────────────────────────────────────────────
11
+ SCOPE="user"
12
+ INCLUDE_EXPERIMENTAL=0
13
+ ARGS=()
14
+ for arg in "$@"; do
15
+ case "$arg" in
16
+ --scope=user) SCOPE="user" ;;
17
+ --scope=project) SCOPE="project" ;;
18
+ --include-experimental) INCLUDE_EXPERIMENTAL=1 ;;
19
+ *) ARGS+=("$arg") ;;
20
+ esac
21
+ done
22
+ set -- "${ARGS[@]+"${ARGS[@]}"}"
23
+
24
+ # ── Agent registry (name:config_root:skills_dir) ──────────────────────────────
25
+ USER_AGENTS="
26
+ claude:$HOME/.claude:$HOME/.claude/skills
27
+ cursor:$HOME/.cursor:$HOME/.cursor/skills
28
+ codex:$HOME/.codex:$HOME/.codex/skills
29
+ opencode:$HOME/.config/opencode:$HOME/.config/opencode/skills
30
+ droid:$HOME/.factory:$HOME/.factory/skills
31
+ "
32
+
33
+ PROJECT_AGENTS="
34
+ claude:$(pwd)/.claude:$(pwd)/.claude/skills
35
+ cursor:$(pwd)/.cursor:$(pwd)/.cursor/skills
36
+ opencode:$(pwd)/.opencode:$(pwd)/.opencode/skills
37
+ "
38
+
39
+ # ── Helpers ───────────────────────────────────────────────────────────────────
40
+
41
+ agent_list_for_scope() {
42
+ if [ "$SCOPE" = "project" ]; then
43
+ echo "$PROJECT_AGENTS"
44
+ else
45
+ echo "$USER_AGENTS"
46
+ fi
47
+ }
48
+
49
+ detected_agents() {
50
+ agent_list_for_scope | grep -v '^$' | while IFS=: read -r name root _skills; do
51
+ if [ "$SCOPE" = "project" ]; then
52
+ # Project scope: include if the config dir exists OR we're creating it
53
+ [ -d "$(dirname "$root")" ] && echo "$name:$root:$_skills"
54
+ else
55
+ [ -d "$root" ] && echo "$name:$root:$_skills"
56
+ fi
57
+ done
58
+ }
59
+
60
+ stub_yaml_value() {
61
+ # $1=key $2=stub.yaml path — minimal key: value parser
62
+ grep "^${1}:" "$2" | sed 's/^[^:]*: *//' | tr -d '"'
63
+ }
64
+
65
+ stub_yaml_list() {
66
+ # $1=key $2=stub.yaml path — parse block-sequence list (- item per line)
67
+ awk -v key="$1" '
68
+ $0 ~ ("^" key ":") { in_list=1; next }
69
+ in_list && /^[[:space:]]*-[[:space:]]/ {
70
+ line=$0; sub(/^[[:space:]]*-[[:space:]]+/,"",line); gsub(/"/,"",line)
71
+ print line; next
72
+ }
73
+ in_list && /^[^[:space:]]/ { exit }
74
+ ' "$2"
75
+ }
76
+
77
+ stub_tier() {
78
+ local yaml="$1/stub.yaml"
79
+ [ -f "$yaml" ] && stub_yaml_value tier "$yaml" 2>/dev/null || echo "experimental"
80
+ }
81
+
82
+ is_allowed_tier() {
83
+ local src="$1"
84
+ [ "$INCLUDE_EXPERIMENTAL" -eq 1 ] && return 0
85
+ local tier
86
+ tier="$(stub_tier "$src")"
87
+ [ "$tier" != "experimental" ]
88
+ }
89
+
90
+ stub_type() {
91
+ local yaml="$1/stub.yaml"
92
+ if [ -f "$yaml" ]; then
93
+ local t
94
+ t="$(stub_yaml_value type "$yaml")"
95
+ echo "${t:-skill}"
96
+ else
97
+ echo "skill"
98
+ fi
99
+ }
100
+
101
+ raw_url_from_stub() {
102
+ # Derive raw GitHub URL from stub.yaml fields
103
+ local yaml="$1"
104
+ local upstream upstream_path version repo branch
105
+ upstream="$(stub_yaml_value upstream "$yaml")"
106
+ upstream_path="$(stub_yaml_value upstream_path "$yaml")"
107
+ version="$(stub_yaml_value version "$yaml")"
108
+ repo="$(echo "$upstream" | sed 's|https://github.com/||')"
109
+ branch="$([ "$version" = "latest" ] && echo "main" || echo "$version")"
110
+ echo "https://raw.githubusercontent.com/$repo/$branch/$upstream_path"
111
+ }
112
+
113
+ is_stub() {
114
+ # Stub = SKILL.md still has das: frontmatter block
115
+ local md="$1/SKILL.md"
116
+ [ -f "$md" ] && grep -q "^das:" "$md"
117
+ }
118
+
119
+ has_stub_manifest() {
120
+ [ -f "$1/stub.yaml" ]
121
+ }
122
+
123
+ sha256_file() {
124
+ if command -v sha256sum >/dev/null 2>&1; then
125
+ sha256sum "$1" | awk '{print $1}'
126
+ else
127
+ shasum -a 256 "$1" | awk '{print $1}'
128
+ fi
129
+ }
130
+
131
+ lockfile_sha() {
132
+ # $1=skill — returns stored sha256 from lockfile, empty if not found
133
+ [ -f "$LOCKFILE" ] || return
134
+ awk -v s="$1" -F'\t' 'NF>=2 && $1==s { print $2; exit }' "$LOCKFILE"
135
+ }
136
+
137
+ lockfile_upsert() {
138
+ # $1=skill $2=sha256 $3=upstream_url
139
+ local skill="$1" sha="$2" url="$3"
140
+ local ts
141
+ ts="$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u)"
142
+ local tmp
143
+ tmp="$(mktemp)"
144
+ # Copy header and all lines except existing entry for this skill
145
+ if [ -f "$LOCKFILE" ]; then
146
+ grep -v "^${skill} " "$LOCKFILE" > "$tmp" || true
147
+ else
148
+ printf '# design-agent-skills.lock — generated by install.sh\n' >> "$tmp"
149
+ printf '# skill\tsha256\tupstream\tlocked_at\n' >> "$tmp"
150
+ fi
151
+ printf '%s\t%s\t%s\t%s\n' "$skill" "$sha" "$url" "$ts" >> "$tmp"
152
+ mv "$tmp" "$LOCKFILE"
153
+ }
154
+
155
+ skill_state() {
156
+ local target="$1" src="$2"
157
+ local stype
158
+ stype="$(stub_type "$src")"
159
+ if [ "$stype" = "package" ] || [ "$stype" = "platform" ]; then
160
+ local yaml="$src/stub.yaml"
161
+ local skills_dir
162
+ skills_dir="$(dirname "$target")"
163
+ # Check for block-list installed_as first
164
+ local list_items
165
+ list_items="$(stub_yaml_list installed_as "$yaml" 2>/dev/null || true)"
166
+ if [ -n "$list_items" ]; then
167
+ local total=0 found=0
168
+ while IFS= read -r item; do
169
+ total=$((total + 1))
170
+ local t="$skills_dir/$item"
171
+ if [ -d "$t" ] && ! grep -q "^das:" "$t/SKILL.md" 2>/dev/null; then
172
+ found=$((found + 1))
173
+ fi
174
+ done <<< "$list_items"
175
+ if [ "$found" -eq 0 ]; then
176
+ echo "package"
177
+ elif [ "$found" -eq "$total" ]; then
178
+ echo "installed"
179
+ else
180
+ echo "${found}/${total}"
181
+ fi
182
+ return
183
+ fi
184
+ # Scalar installed_as
185
+ local installed_as
186
+ installed_as="$(stub_yaml_value installed_as "$yaml" 2>/dev/null || true)"
187
+ [ -z "$installed_as" ] && installed_as="$(basename "$src")"
188
+ local installed_target="$skills_dir/$installed_as"
189
+ if [ -d "$installed_target" ] && ! grep -q "^das:" "$installed_target/SKILL.md" 2>/dev/null; then
190
+ echo "installed"
191
+ else
192
+ echo "package"
193
+ fi
194
+ return
195
+ fi
196
+ if [ -L "$target" ] && [ ! -e "$target" ]; then
197
+ echo "BROKEN"
198
+ elif [ -L "$target" ] && is_stub "$src"; then
199
+ echo "stub"
200
+ elif [ -L "$target" ]; then
201
+ echo "upgraded"
202
+ elif [ -d "$target" ]; then
203
+ is_stub "$target" && echo "stub" || echo "upgraded"
204
+ else
205
+ echo "-"
206
+ fi
207
+ }
208
+
209
+ skill_names() {
210
+ for d in "$SKILLS_SRC"/*/; do
211
+ [ -d "$d" ] && basename "${d%/}"
212
+ done
213
+ }
214
+
215
+ # ── Commands ──────────────────────────────────────────────────────────────────
216
+
217
+ cmd_install() {
218
+ local agent_list
219
+ agent_list="$(detected_agents)"
220
+ [ -z "$agent_list" ] && { echo "No supported agents found."; exit 0; }
221
+
222
+ while IFS=: read -r name _root skills_dir; do
223
+ mkdir -p "$skills_dir"
224
+ local linked=0 skipped=0
225
+ while IFS= read -r skill; do
226
+ local target="$skills_dir/$skill"
227
+ local stype
228
+ stype="$(stub_type "$SKILLS_SRC/$skill")"
229
+ if [ "$stype" = "skill" ] || [ "$stype" = "navigator" ]; then
230
+ if ! is_allowed_tier "$SKILLS_SRC/$skill"; then
231
+ skipped=$((skipped + 1))
232
+ elif [ -L "$target" ] || [ -d "$target" ]; then
233
+ skipped=$((skipped + 1))
234
+ else
235
+ ln -s "$SKILLS_SRC/$skill" "$target"
236
+ linked=$((linked + 1))
237
+ fi
238
+ else
239
+ skipped=$((skipped + 1))
240
+ fi
241
+ done < <(skill_names)
242
+ printf " %-12s +%d linked %d skipped\n" "$name" "$linked" "$skipped"
243
+ done <<< "$agent_list"
244
+
245
+ echo
246
+ if [ "$INCLUDE_EXPERIMENTAL" -eq 0 ]; then
247
+ printf "scope: %s | experimental skills skipped (add --include-experimental to install all)\n" "$SCOPE"
248
+ else
249
+ printf "scope: %s | run './install.sh status' to inspect states.\n" "$SCOPE"
250
+ fi
251
+
252
+ # Warn about user-scope-only agents when running project scope
253
+ if [ "$SCOPE" = "project" ]; then
254
+ local skipped_agents=""
255
+ for _entry in "codex:$HOME/.codex" "droid:$HOME/.factory"; do
256
+ local _aname _aroot
257
+ IFS=: read -r _aname _aroot <<< "$_entry"
258
+ [ -d "$_aroot" ] && skipped_agents="${skipped_agents:+$skipped_agents, }$_aname"
259
+ done
260
+ if [ -n "$skipped_agents" ]; then
261
+ printf "note: %s detected but not linked (user-scope only) — omit --scope=project to include.\n" "$skipped_agents"
262
+ fi
263
+ fi
264
+ }
265
+
266
+ cmd_status() {
267
+ local agent_list
268
+ agent_list="$(detected_agents)"
269
+ [ -z "$agent_list" ] && { echo "No supported agents found."; exit 0; }
270
+
271
+ local names=() dirs=()
272
+ while IFS=: read -r name _root skills_dir; do
273
+ names+=("$name")
274
+ dirs+=("$skills_dir")
275
+ done <<< "$agent_list"
276
+
277
+ local ncols=${#names[@]}
278
+
279
+ printf "\n%-22s %-4s" "skill" "tier"
280
+ for name in "${names[@]}"; do printf " %-10s" "$name"; done
281
+ echo
282
+
283
+ printf "%-22s %-4s" "──────────────────────" "────"
284
+ for _ in "${names[@]}"; do printf " %-10s" "──────────"; done
285
+ echo
286
+
287
+ while IFS= read -r skill; do
288
+ local src="$SKILLS_SRC/$skill"
289
+ local tier_char
290
+ case "$(stub_tier "$src")" in
291
+ official) tier_char="O" ;;
292
+ community) tier_char="C" ;;
293
+ experimental) tier_char="E" ;;
294
+ *) tier_char="?" ;;
295
+ esac
296
+ printf "%-22s %-4s" "$skill" "$tier_char"
297
+ local i=0
298
+ while [ $i -lt $ncols ]; do
299
+ local target="${dirs[$i]}/$skill"
300
+ printf " %-10s" "$(skill_state "$target" "$src")"
301
+ i=$((i + 1))
302
+ done
303
+ echo
304
+ done < <(skill_names)
305
+
306
+ echo
307
+ printf "scope: %s\n" "$SCOPE"
308
+ echo "tier: O=official C=community E=experimental"
309
+ echo "stub=pending upgraded=full installed=package installed package=not installed BROKEN=run fix"
310
+ echo
311
+ }
312
+
313
+ cmd_update() {
314
+ local dry_run=0 frozen=0
315
+ for arg in "$@"; do
316
+ case "$arg" in
317
+ --dry-run) dry_run=1 ;;
318
+ --frozen) frozen=1 ;;
319
+ esac
320
+ done
321
+
322
+ if [ "$frozen" -eq 1 ] && [ ! -f "$LOCKFILE" ]; then
323
+ echo "Error: --frozen requires a lockfile. Run './install.sh lock' first."
324
+ exit 1
325
+ fi
326
+
327
+ local agent_list
328
+ agent_list="$(detected_agents)"
329
+ local refreshed=0 linked=0 shown=0
330
+
331
+ [ "$dry_run" -eq 1 ] && echo "(dry run — no changes will be made)"
332
+ echo
333
+
334
+ while IFS= read -r skill; do
335
+ local src="$SKILLS_SRC/$skill"
336
+ local yaml="$src/stub.yaml"
337
+
338
+ # Package/platform types — print install command instead of symlinking
339
+ local stype
340
+ stype="$(stub_type "$src")"
341
+ if [ "$stype" = "package" ] || [ "$stype" = "platform" ]; then
342
+ local install_cmd
343
+ install_cmd="$(stub_yaml_value install_default "$yaml" 2>/dev/null || true)"
344
+ if [ -n "$install_cmd" ]; then
345
+ printf " package %-18s run: %s\n" "$skill" "$install_cmd"
346
+ shown=$((shown + 1))
347
+ fi
348
+ continue
349
+ fi
350
+
351
+ # Upgraded stub with manifest → re-fetch from upstream
352
+ if has_stub_manifest "$src" && ! is_stub "$src"; then
353
+ local url
354
+ url="$(raw_url_from_stub "$yaml")"
355
+ if [ "$dry_run" -eq 1 ]; then
356
+ printf " would refresh %s ← %s\n" "$skill" "$url"
357
+ refreshed=$((refreshed + 1))
358
+ elif [ "$frozen" -eq 1 ]; then
359
+ local locked_sha current_sha
360
+ locked_sha="$(lockfile_sha "$skill")"
361
+ current_sha="$(sha256_file "$src/SKILL.md" 2>/dev/null || true)"
362
+ if [ -n "$locked_sha" ] && [ "$current_sha" != "$locked_sha" ]; then
363
+ printf " DRIFT %s — content changed since lockfile was written\n" "$skill"
364
+ fi
365
+ # Skip re-fetch; keep current content
366
+ else
367
+ # Backup before overwrite
368
+ cp "$src/SKILL.md" "$src/SKILL.md.bak" 2>/dev/null || true
369
+ printf " updating %s ... " "$skill"
370
+ local upstream_url
371
+ upstream_url="$(stub_yaml_value upstream "$yaml" 2>/dev/null || true)"
372
+ if curl -fsSL "$url" -o "$src/SKILL.md" 2>/dev/null; then
373
+ echo "ok"
374
+ refreshed=$((refreshed + 1))
375
+ # Record in lockfile
376
+ local new_sha
377
+ new_sha="$(sha256_file "$src/SKILL.md" 2>/dev/null || true)"
378
+ [ -n "$new_sha" ] && lockfile_upsert "$skill" "$new_sha" "$upstream_url"
379
+ else
380
+ # Restore backup on failure
381
+ mv "$src/SKILL.md.bak" "$src/SKILL.md" 2>/dev/null || true
382
+ echo "failed (upstream unreachable — backup restored)"
383
+ fi
384
+ fi
385
+ continue
386
+ fi
387
+
388
+ # New stub not yet linked to all agents → add missing links (respects tier filter)
389
+ [ "$stype" = "skill" ] || [ "$stype" = "navigator" ] || continue
390
+ is_allowed_tier "$src" || continue
391
+ while IFS=: read -r name _root skills_dir; do
392
+ local target="$skills_dir/$skill"
393
+ if [ ! -L "$target" ] && [ ! -d "$target" ]; then
394
+ if [ "$dry_run" -eq 1 ]; then
395
+ printf " would link %-18s → %s\n" "$skill" "$name"
396
+ else
397
+ mkdir -p "$skills_dir"
398
+ ln -s "$src" "$target"
399
+ printf " added %-18s %s\n" "$skill" "$name"
400
+ fi
401
+ linked=$((linked + 1))
402
+ fi
403
+ done <<< "$agent_list"
404
+
405
+ done < <(skill_names)
406
+
407
+ if [ "$refreshed" -eq 0 ] && [ "$linked" -eq 0 ] && [ "$shown" -eq 0 ]; then
408
+ echo "Nothing to update."
409
+ else
410
+ if [ "$dry_run" -eq 1 ]; then
411
+ [ "$refreshed" -gt 0 ] && echo "$refreshed skill(s) would be refreshed from upstream."
412
+ [ "$linked" -gt 0 ] && echo "$linked new link(s) would be added."
413
+ [ "$shown" -gt 0 ] && echo "$shown package install command(s) shown."
414
+ else
415
+ [ "$refreshed" -gt 0 ] && echo "$refreshed skill(s) refreshed from upstream."
416
+ [ "$linked" -gt 0 ] && echo "$linked new link(s) added."
417
+ [ "$shown" -gt 0 ] && echo "$shown package install command(s) shown."
418
+ fi
419
+ fi
420
+ }
421
+
422
+ cmd_fix() {
423
+ local agent_list
424
+ agent_list="$(detected_agents)"
425
+ local fixed=0
426
+
427
+ while IFS=: read -r _name _root skills_dir; do
428
+ [ -d "$skills_dir" ] || continue
429
+ for target in "$skills_dir"/*/; do
430
+ target="${target%/}"
431
+ [ -L "$target" ] || continue
432
+ if [ ! -e "$target" ]; then
433
+ rm "$target"
434
+ printf " removed broken link: %s\n" "$target"
435
+ fixed=$((fixed + 1))
436
+ fi
437
+ done
438
+ done <<< "$agent_list"
439
+
440
+ [ "$fixed" -eq 0 ] && echo "No broken links found." || echo "Fixed $fixed broken link(s)."
441
+ }
442
+
443
+ cmd_lock() {
444
+ echo "Generating lockfile: $LOCKFILE"
445
+ local tmp
446
+ tmp="$(mktemp)"
447
+ printf '# design-agent-skills.lock — generated by install.sh\n' > "$tmp"
448
+ printf '# skill\tsha256\tupstream\tlocked_at\n' >> "$tmp"
449
+
450
+ local ts locked=0
451
+ ts="$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u)"
452
+
453
+ while IFS= read -r skill; do
454
+ local src="$SKILLS_SRC/$skill"
455
+ local md="$src/SKILL.md"
456
+ local yaml="$src/stub.yaml"
457
+ [ -f "$md" ] || continue
458
+ is_stub "$src" && continue # only lock upgraded (non-stub) skills
459
+ local sha upstream
460
+ sha="$(sha256_file "$md")"
461
+ upstream="$(stub_yaml_value upstream "$yaml" 2>/dev/null || true)"
462
+ printf '%s\t%s\t%s\t%s\n' "$skill" "$sha" "$upstream" "$ts" >> "$tmp"
463
+ echo " locked $skill"
464
+ locked=$((locked + 1))
465
+ done < <(skill_names)
466
+
467
+ mv "$tmp" "$LOCKFILE"
468
+ if [ "$locked" -eq 0 ]; then
469
+ echo "No upgraded skills found — lockfile written (empty)."
470
+ else
471
+ printf "%d skill(s) locked.\n" "$locked"
472
+ fi
473
+ }
474
+
475
+ cmd_doctor() {
476
+ local strict=0 show_substr=0
477
+ for arg in "$@"; do
478
+ case "$arg" in
479
+ --strict) strict=1 ;;
480
+ --substr) show_substr=1 ;;
481
+ esac
482
+ done
483
+
484
+ local tmp
485
+ tmp="$(mktemp)"
486
+
487
+ local skill_count
488
+ skill_count=$(skill_names | wc -l | tr -d ' ')
489
+ printf "Scanning %d skills for trigger collisions...\n\n" "$skill_count"
490
+
491
+ # Collect (trigger TAB skill) pairs into temp file
492
+ while IFS= read -r skill; do
493
+ local md="$SKILLS_SRC/$skill/SKILL.md"
494
+ [ -f "$md" ] || continue
495
+ awk -v skill="$skill" '
496
+ BEGIN { in_front=0; in_trig=0 }
497
+ /^---$/ { if(in_front==0){in_front=1}else{exit}; next }
498
+ in_front && /^triggers:/ { in_trig=1; next }
499
+ in_front && in_trig && /^[[:space:]]*-[[:space:]]/ {
500
+ line=$0; sub(/^[[:space:]]*-[[:space:]]+/,"",line); gsub(/"/,"",line)
501
+ print line "\t" skill; next
502
+ }
503
+ in_front && in_trig && /^[^[:space:]]/ { in_trig=0 }
504
+ ' "$md"
505
+ done < <(skill_names) > "$tmp"
506
+
507
+ local issues=0
508
+
509
+ # ── Exact collisions ─────────────────────────────────────────────────────────
510
+ local exact_out
511
+ exact_out=$(sort "$tmp" | awk -F'\t' '
512
+ {
513
+ key=$1; skill=$2
514
+ if (key != prev_key) {
515
+ if (cnt > 1) print prev_key "\t" list
516
+ prev_key=key; list=skill; cnt=1
517
+ } else { list=list ", " skill; cnt++ }
518
+ }
519
+ END { if (cnt > 1) print prev_key "\t" list }
520
+ ')
521
+
522
+ if [ -n "$exact_out" ]; then
523
+ local exact_count
524
+ exact_count=$(printf '%s\n' "$exact_out" | grep -c . || true)
525
+ printf "Exact trigger collisions (%d):\n" "$exact_count"
526
+ printf '%s\n' "$exact_out" | awk -F'\t' '{ printf " %-34s → %s\n", "\"" $1 "\"", $2 }'
527
+ echo
528
+ issues=$((issues + exact_count))
529
+ fi
530
+
531
+ # ── Substring overlaps (opt-in via --substr) ──────────────────────────────────
532
+ if [ "$show_substr" -eq 1 ]; then
533
+ local substr_out
534
+ substr_out=$(cut -f1 "$tmp" | sort -u | awk '
535
+ { t[NR]=$0 }
536
+ END {
537
+ n=NR
538
+ for(i=1;i<=n;i++) for(j=1;j<=n;j++) {
539
+ if(i!=j && index(t[i],t[j])>0 && length(t[j])<length(t[i]))
540
+ printf "%s\t%s\n", t[j], t[i]
541
+ }
542
+ }
543
+ ' | sort -u)
544
+
545
+ if [ -n "$substr_out" ]; then
546
+ local substr_count
547
+ substr_count=$(printf '%s\n' "$substr_out" | grep -c . || true)
548
+ printf "Substring overlaps — shorter trigger subsumed by longer (%d):\n" "$substr_count"
549
+ printf '%s\n' "$substr_out" | awk -F'\t' '{ printf " %-20s ⊇ %s\n", "\"" $1 "\"", "\"" $2 "\"" }'
550
+ echo
551
+ issues=$((issues + substr_count))
552
+ fi
553
+ fi
554
+
555
+ rm -f "$tmp"
556
+
557
+ # ── Symlink fragility scan ──────────────────────────────────────────────────
558
+ local orphaned=0 relocated=0
559
+ while IFS=: read -r _name _root skills_dir; do
560
+ [ -d "$skills_dir" ] || continue
561
+ while IFS= read -r link; do
562
+ [ -L "$link" ] || continue
563
+ local target
564
+ target="$(readlink "$link")"
565
+ if [ ! -e "$link" ]; then
566
+ orphaned=$((orphaned + 1))
567
+ elif [ "${target#"$SKILLS_SRC"}" = "$target" ]; then
568
+ relocated=$((relocated + 1))
569
+ fi
570
+ done < <(find "$skills_dir" -maxdepth 1 -type l 2>/dev/null)
571
+ done < <(detected_agents)
572
+
573
+ if [ "$orphaned" -gt 0 ]; then
574
+ printf "BROKEN %d orphaned symlink(s) — target missing (repo moved?).\n" "$orphaned"
575
+ printf " Run: ./install.sh fix && ./install.sh install\n\n"
576
+ issues=$((issues + orphaned))
577
+ fi
578
+ if [ "$relocated" -gt 0 ]; then
579
+ printf "RELOCATED %d symlink(s) point outside current install dir.\n" "$relocated"
580
+ printf " Likely caused by moving the repo. Run: ./install.sh fix && ./install.sh install\n\n"
581
+ issues=$((issues + relocated))
582
+ fi
583
+ if [ "$orphaned" -eq 0 ] && [ "$relocated" -eq 0 ]; then
584
+ echo "Symlinks OK — all links resolve inside current install dir."
585
+ fi
586
+
587
+ echo
588
+ if [ "$issues" -eq 0 ]; then
589
+ echo "All checks OK — no issues found."
590
+ else
591
+ printf "%d issue(s) found.\n" "$issues"
592
+ if [ "$strict" -eq 1 ]; then
593
+ echo "Exiting 1 (--strict)."
594
+ exit 1
595
+ fi
596
+ fi
597
+ }
598
+
599
+ cmd_remove() {
600
+ local skill="${1:-}"
601
+ if [ -z "$skill" ]; then
602
+ echo "Usage: ./install.sh remove <skill-name>"
603
+ echo " ./install.sh remove --all"
604
+ exit 1
605
+ fi
606
+
607
+ local agent_list
608
+ agent_list="$(detected_agents)"
609
+ local removed=0
610
+
611
+ if [ "$skill" = "--all" ]; then
612
+ while IFS=: read -r _name _root skills_dir; do
613
+ [ -d "$skills_dir" ] || continue
614
+ while IFS= read -r sk; do
615
+ local target="$skills_dir/$sk"
616
+ [ -L "$target" ] || continue
617
+ rm "$target"
618
+ printf " removed: %s\n" "$target"
619
+ removed=$((removed + 1))
620
+ done < <(skill_names)
621
+ done <<< "$agent_list"
622
+ printf "%d link(s) removed.\n" "$removed"
623
+ return
624
+ fi
625
+
626
+ if [ ! -d "$SKILLS_SRC/$skill" ]; then
627
+ echo "Unknown skill: $skill"
628
+ echo "Run './install.sh status' to see available skills."
629
+ exit 1
630
+ fi
631
+
632
+ while IFS=: read -r name _root skills_dir; do
633
+ local target="$skills_dir/$skill"
634
+ if [ -L "$target" ] || [ -d "$target" ]; then
635
+ rm -rf "$target"
636
+ printf " removed from %s\n" "$name"
637
+ removed=$((removed + 1))
638
+ fi
639
+ done <<< "$agent_list"
640
+
641
+ [ "$removed" -eq 0 ] \
642
+ && echo "No links found for: $skill" \
643
+ || printf "%d link(s) removed.\n" "$removed"
644
+ }
645
+
646
+ cmd_help() {
647
+ cat <<HELP
648
+ Usage: ./install.sh [flags] [command]
649
+
650
+ Global flags:
651
+ --scope=user Link to agent user-level dirs (default): ~/.claude/skills/
652
+ --scope=project Link to project-level dirs: ./.claude/skills/
653
+ --include-experimental Also install experimental-tier skills (default: official+community only)
654
+
655
+ Commands:
656
+ install Symlink all stubs to detected agents (default)
657
+ status Show stub / upgraded / installed / BROKEN state per agent
658
+ update Re-fetch upgraded skills from upstream; add links for new stubs
659
+ --dry-run Show what would change without making any changes
660
+ --frozen Skip re-fetching; warn if content has drifted from lockfile
661
+ lock Generate design-agent-skills.lock from current upgraded skill state
662
+ fix Remove broken symlinks
663
+ remove <skill> Remove a specific skill's links from all agents
664
+ remove --all Remove all skill links (uninstall)
665
+ doctor Scan for trigger collisions and orphaned/relocated symlinks
666
+ --strict Exit 1 if any issues found (useful for CI)
667
+ --substr Also report substring overlaps (broad triggers subsuming narrow ones)
668
+ help Show this message
669
+
670
+ Skill tiers: official (28) community (35) experimental (60)
671
+ User-scope agents: claude cursor codex opencode droid
672
+ Project-scope agents: claude cursor opencode
673
+ HELP
674
+ }
675
+
676
+ # ── Entry ─────────────────────────────────────────────────────────────────────
677
+ CMD="${1:-install}"
678
+ shift 2>/dev/null || true
679
+ case "$CMD" in
680
+ install) cmd_install ;;
681
+ status) cmd_status ;;
682
+ update) cmd_update "$@" ;;
683
+ fix) cmd_fix ;;
684
+ remove) cmd_remove "$@" ;;
685
+ lock) cmd_lock ;;
686
+ doctor) cmd_doctor "$@" ;;
687
+ help|-h) cmd_help ;;
688
+ *) echo "Unknown command: $CMD"; cmd_help; exit 1 ;;
689
+ esac