66 pull_request :
77 branches : [main]
88
9+ concurrency :
10+ group : ci-${{ github.ref }}
11+ cancel-in-progress : true
12+
913jobs :
14+ # ── Lightweight structural validation (no Node required) ──────────────
1015 validate :
11- name : Validate Framework
16+ name : Validate Structure
1217 runs-on : ubuntu-latest
18+ timeout-minutes : 2
1319 steps :
1420 - uses : actions/checkout@v4
1521
16- - name : Check shell scripts syntax
22+ - name : Check shell script syntax
1723 run : |
1824 errors=0
1925 for f in scripts/*.sh; do
2026 if [ -f "$f" ]; then
21- echo "Checking $f..."
22- bash -n "$f" || errors=$((errors + 1))
27+ bash -n "$f" || { echo "FAIL: $f"; errors=$((errors + 1)); }
2328 fi
2429 done
30+ echo "Checked $(ls scripts/*.sh 2>/dev/null | wc -l) scripts, $errors failed"
2531 exit $errors
2632
2733 - name : Validate JSON configs
2834 run : |
2935 errors=0
30- for f in .claude/pipeline.config.json package.json templates/**/*.json ; do
36+ for f in .claude/pipeline.config.json package.json; do
3137 if [ -f "$f" ]; then
32- echo "Checking $f..."
33- python3 -m json.tool "$f" > /dev/null || errors=$((errors + 1))
38+ python3 -m json.tool "$f" > /dev/null || { echo "FAIL: $f"; errors=$((errors + 1)); }
3439 fi
3540 done
41+ for f in templates/**/*.json; do
42+ if [ -f "$f" ]; then
43+ python3 -m json.tool "$f" > /dev/null || { echo "FAIL: $f"; errors=$((errors + 1)); }
44+ fi
45+ done
46+ echo "$errors JSON validation failures"
3647 exit $errors
3748
49+ - name : Validate pipeline.config.json structure
50+ run : |
51+ # Verify required top-level keys exist
52+ required_keys='["visualDiff","iterationLoop","tdd","e2e","qualityGate","appTypes","orchestration","caching"]'
53+ python3 -c "
54+ import json, sys
55+ with open('.claude/pipeline.config.json') as f:
56+ config = json.load(f)
57+ required = json.loads('$required_keys')
58+ missing = [k for k in required if k not in config]
59+ if missing:
60+ print(f'Missing required keys: {missing}')
61+ sys.exit(1)
62+ print(f'All {len(required)} required keys present')
63+ "
64+
3865 - name : Check required files exist
3966 run : |
4067 exit_code=0
4673 "scripts/run-tests.sh"
4774 "scripts/check-types.sh"
4875 "scripts/visual-diff.js"
76+ "scripts/verify-tokens.sh"
77+ "scripts/check-security.sh"
4978 )
5079 for f in "${required_files[@]}"; do
5180 if [ -f "$f" ]; then
@@ -57,21 +86,152 @@ jobs:
5786 done
5887 exit $exit_code
5988
60- - name : Check scripts are executable
89+ - name : Validate agent frontmatter
6190 run : |
62- for f in scripts/*.sh; do
63- if [ -f "$f" ]; then
64- if [ ! -x "$f" ]; then
65- echo "WARNING: $f is not executable"
66- else
67- echo " $f: OK"
91+ errors=0
92+ count=0
93+ for f in .claude/agents/*.md; do
94+ [ -f "$f" ] || continue
95+ count=$((count + 1))
96+
97+ # Extract YAML frontmatter between --- delimiters
98+ frontmatter=$(sed -n '/^---$/,/^---$/p' "$f" | sed '1d;$d')
99+
100+ if [ -z "$frontmatter" ]; then
101+ echo "FAIL: $f — no YAML frontmatter found"
102+ errors=$((errors + 1))
103+ continue
104+ fi
105+
106+ # Check required fields (tools is optional — omitted means "all tools")
107+ for field in name description; do
108+ if ! echo "$frontmatter" | grep -qE "^${field}:"; then
109+ echo "FAIL: $f — missing required field: $field"
110+ errors=$((errors + 1))
68111 fi
112+ done
113+ done
114+ echo "Checked $count agents, $errors failures"
115+ exit $errors
116+
117+ - name : Validate skill structure
118+ run : |
119+ errors=0
120+ count=0
121+ for f in .claude/skills/*.md; do
122+ [ -f "$f" ] || continue
123+ [ "$(basename "$f")" = "README.md" ] && continue
124+ count=$((count + 1))
125+
126+ frontmatter=$(sed -n '/^---$/,/^---$/p' "$f" | sed '1d;$d')
127+
128+ if [ -z "$frontmatter" ]; then
129+ echo "FAIL: $f — no frontmatter found"
130+ errors=$((errors + 1))
131+ continue
132+ fi
133+
134+ for field in name description; do
135+ if ! echo "$frontmatter" | grep -qE "^${field}:"; then
136+ echo "FAIL: $f — missing required field: $field"
137+ errors=$((errors + 1))
138+ fi
139+ done
140+ done
141+ echo "Checked $count skills, $errors failures"
142+ [ $count -eq 0 ] && echo "Note: no skill .md files found in .claude/skills/"
143+ exit $errors
144+
145+ - name : Validate templates
146+ run : |
147+ errors=0
148+
149+ # Check template JSON files parse correctly
150+ for f in templates/**/*.json; do
151+ if [ -f "$f" ]; then
152+ python3 -m json.tool "$f" > /dev/null 2>&1 || {
153+ echo "FAIL: $f — invalid JSON"
154+ errors=$((errors + 1))
155+ }
69156 fi
70157 done
71158
159+ # Check key template directories exist
160+ for dir in templates/shared templates/nextjs templates/vite; do
161+ if [ -d "$dir" ]; then
162+ echo " $dir: OK"
163+ else
164+ echo " $dir: MISSING"
165+ errors=$((errors + 1))
166+ fi
167+ done
168+
169+ # Check shared configs exist
170+ for f in templates/shared/eslint.config.js templates/shared/prettier.config.js templates/shared/tsconfig.json templates/shared/tailwind.config.ts; do
171+ if [ -f "$f" ]; then
172+ echo " $f: OK"
173+ else
174+ echo " $f: MISSING"
175+ errors=$((errors + 1))
176+ fi
177+ done
178+
179+ echo "$errors template validation failures"
180+ exit $errors
181+
182+ # ── Script test suite (needs Node + dependencies) ─────────────────────
183+ script-tests :
184+ name : Script Tests
185+ runs-on : ubuntu-latest
186+ timeout-minutes : 3
187+ steps :
188+ - uses : actions/checkout@v4
189+
190+ - name : Setup Node.js
191+ uses : actions/setup-node@v4
192+ with :
193+ node-version : " 20"
194+
195+ - name : Install pnpm
196+ uses : pnpm/action-setup@v4
197+ with :
198+ version : 9
199+
200+ - name : Install dependencies
201+ run : pnpm install --frozen-lockfile
202+
203+ - name : Run script tests
204+ run : pnpm vitest run scripts/__tests__/ --reporter=verbose
205+
206+ # ── Lint & format check (needs Node + project with eslint/prettier) ───
207+ lint :
208+ name : Lint & Format
209+ runs-on : ubuntu-latest
210+ timeout-minutes : 3
211+ steps :
212+ - uses : actions/checkout@v4
213+
214+ - name : Setup Node.js
215+ uses : actions/setup-node@v4
216+ with :
217+ node-version : " 20"
218+
219+ - name : Install pnpm
220+ uses : pnpm/action-setup@v4
221+ with :
222+ version : 9
223+
224+ - name : Install dependencies
225+ run : pnpm install --frozen-lockfile
226+
227+ - name : Run lint and format check
228+ run : bash scripts/lint-and-format.sh --check
229+
230+ # ── Token verification ────────────────────────────────────────────────
72231 token-verification :
73232 name : Verify Design Tokens
74233 runs-on : ubuntu-latest
234+ timeout-minutes : 2
75235 steps :
76236 - uses : actions/checkout@v4
77237
@@ -83,16 +243,18 @@ jobs:
83243 echo "No app source found — skipping token check"
84244 fi
85245
246+ # ── Security scanning ─────────────────────────────────────────────────
86247 security-scan :
87- name : Security Scanning
248+ name : Security Scan
88249 runs-on : ubuntu-latest
250+ timeout-minutes : 3
89251 steps :
90252 - uses : actions/checkout@v4
91253
92254 - name : Setup Node.js
93255 uses : actions/setup-node@v4
94256 with :
95- node-version : ' 20 '
257+ node-version : " 20 "
96258
97259 - name : Install pnpm
98260 uses : pnpm/action-setup@v4
@@ -129,9 +291,11 @@ jobs:
129291 if-no-files-found : ignore
130292 retention-days : 30
131293
294+ # ── Visual regression (PR only) ───────────────────────────────────────
132295 visual-regression :
133- name : Visual Regression Test
296+ name : Visual Regression
134297 runs-on : ubuntu-latest
298+ timeout-minutes : 5
135299 if : github.event_name == 'pull_request'
136300 steps :
137301 - uses : actions/checkout@v4
@@ -141,7 +305,7 @@ jobs:
141305 - name : Setup Node.js
142306 uses : actions/setup-node@v4
143307 with :
144- node-version : ' 20 '
308+ node-version : " 20 "
145309
146310 - name : Install pnpm
147311 uses : pnpm/action-setup@v4
0 commit comments