This repository was archived by the owner on May 18, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
428 lines (382 loc) · 19.2 KB
/
Copy pathsdk-update-check.yml
File metadata and controls
428 lines (382 loc) · 19.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
name: SDK Update Check
on:
schedule:
- cron: "0 8 * * *" # Daily at 08:00 UTC
workflow_dispatch:
permissions:
contents: write
env:
MAX_MEND_RETRIES: 2
PIPELINE_LOG: /tmp/pipeline-log.json
jobs:
daily-run:
if: github.repository == 'xiaolai/claude-agent-sdk-skill-autoupdated'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: Initialize pipeline log
run: |
echo '{"startedAt":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","steps":[]}' > "$PIPELINE_LOG"
# ---------------------------------------------------------------
# 1. Monitor — zero API cost
# ---------------------------------------------------------------
- name: Run change monitor
id: monitor
working-directory: agent
run: |
START=$(date +%s)
bash monitor.sh && echo "changes=false" >> "$GITHUB_OUTPUT" || {
exit_code=$?
if [ "$exit_code" -eq 1 ]; then
echo "changes=true" >> "$GITHUB_OUTPUT"
else
ELAPSED=$(( $(date +%s) - START ))
jq --arg s "monitor" --arg r "error" --arg d "${ELAPSED}s" \
--arg e "Monitor script failed with exit code $exit_code" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"error":$e}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit $exit_code
fi
}
ELAPSED=$(( $(date +%s) - START ))
CHANGES="${{ steps.monitor.outputs.changes }}"
# Output may not be set yet in this run block, detect from exit code
if [ -f /tmp/change-report.json ]; then
CHANGES="true"
else
CHANGES="false"
fi
jq --arg s "monitor" --arg r "success" --arg d "${ELAPSED}s" \
--arg c "$CHANGES" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"changesDetected":($c == "true")}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
# ---------------------------------------------------------------
# 2. Setup — install + authenticate (once)
# ---------------------------------------------------------------
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Authenticate Claude Code
id: auth
run: |
if [ -n "${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}" ]; then
echo "Using OAuth token authentication"
echo "CLAUDE_CODE_OAUTH_TOKEN=${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}" >> "$GITHUB_ENV"
# Skip onboarding in non-interactive mode
mkdir -p ~/.claude
echo '{"hasCompletedOnboarding":true}' > ~/.claude.json
echo "method=oauth" >> "$GITHUB_OUTPUT"
elif [ -n "${{ secrets.ANTHROPIC_API_KEY }}" ]; then
echo "Using API key authentication"
echo "ANTHROPIC_API_KEY=${{ secrets.ANTHROPIC_API_KEY }}" >> "$GITHUB_ENV"
echo "method=api_key" >> "$GITHUB_OUTPUT"
else
echo "ERROR: No authentication configured."
echo "Set either CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY secret."
jq --arg s "auth" --arg r "error" \
--arg e "No authentication configured" \
'.steps += [{"step":$s,"result":$r,"error":$e}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit 1
fi
jq --arg s "auth" --arg r "success" --arg m "${{ steps.auth.outputs.method || 'unknown' }}" \
'.steps += [{"step":$s,"result":$r,"method":$m}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
- name: Install agent dependencies
working-directory: agent
run: npm install
- name: Install Python SDK for research
run: pip install claude-agent-sdk
# ---------------------------------------------------------------
# 3. Update agent — only when version changes detected
# ---------------------------------------------------------------
- name: Run update agent
id: update
if: steps.monitor.outputs.changes == 'true'
continue-on-error: true
working-directory: agent
run: |
START=$(date +%s)
npx tsx update-agent.ts 2>&1 | tee /tmp/update-agent.log
EXIT_CODE=${PIPESTATUS[0]}
ELAPSED=$(( $(date +%s) - START ))
if [ "$EXIT_CODE" -eq 0 ]; then
jq --arg s "update" --arg r "success" --arg d "${ELAPSED}s" \
'.steps += [{"step":$s,"result":$r,"duration":$d}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
else
LAST_LINES=$(tail -20 /tmp/update-agent.log | jq -Rs '.')
jq --arg s "update" --arg r "failed" --arg d "${ELAPSED}s" \
--arg c "$EXIT_CODE" --argjson e "$LAST_LINES" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"exitCode":($c|tonumber),"lastOutput":$e}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit $EXIT_CODE
fi
# ---------------------------------------------------------------
# 4. Research agent — runs daily
# ---------------------------------------------------------------
- name: Run TypeScript research agent
id: research_ts
continue-on-error: true
working-directory: agent
run: |
START=$(date +%s)
npx tsx research-agent-ts.ts 2>&1 | tee /tmp/research-ts.log
EXIT_CODE=${PIPESTATUS[0]}
ELAPSED=$(( $(date +%s) - START ))
if [ "$EXIT_CODE" -eq 0 ]; then
jq --arg s "research_ts" --arg r "success" --arg d "${ELAPSED}s" \
'.steps += [{"step":$s,"result":$r,"duration":$d}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
else
LAST_LINES=$(tail -20 /tmp/research-ts.log | jq -Rs '.')
jq --arg s "research_ts" --arg r "failed" --arg d "${ELAPSED}s" \
--arg c "$EXIT_CODE" --argjson e "$LAST_LINES" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"exitCode":($c|tonumber),"lastOutput":$e}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit $EXIT_CODE
fi
- name: Run Python research agent
id: research_py
continue-on-error: true
working-directory: agent
run: |
START=$(date +%s)
npx tsx research-agent-py.ts 2>&1 | tee /tmp/research-py.log
EXIT_CODE=${PIPESTATUS[0]}
ELAPSED=$(( $(date +%s) - START ))
if [ "$EXIT_CODE" -eq 0 ]; then
jq --arg s "research_py" --arg r "success" --arg d "${ELAPSED}s" \
'.steps += [{"step":$s,"result":$r,"duration":$d}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
else
LAST_LINES=$(tail -20 /tmp/research-py.log | jq -Rs '.')
jq --arg s "research_py" --arg r "failed" --arg d "${ELAPSED}s" \
--arg c "$EXIT_CODE" --argjson e "$LAST_LINES" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"exitCode":($c|tonumber),"lastOutput":$e}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit $EXIT_CODE
fi
# ---------------------------------------------------------------
# 4b. Template type-check — always runs (catches API drift)
# ---------------------------------------------------------------
- name: Type-check templates
id: typecheck
continue-on-error: true
run: |
START=$(date +%s)
bash scripts/typecheck-templates.sh 2>&1 | tee /tmp/typecheck.log
EXIT_CODE=${PIPESTATUS[0]}
ELAPSED=$(( $(date +%s) - START ))
if [ "$EXIT_CODE" -eq 0 ]; then
jq --arg s "typecheck" --arg r "success" --arg d "${ELAPSED}s" \
'.steps += [{"step":$s,"result":$r,"duration":$d}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
else
LAST_LINES=$(tail -20 /tmp/typecheck.log | jq -Rs '.')
jq --arg s "typecheck" --arg r "failed" --arg d "${ELAPSED}s" \
--arg c "$EXIT_CODE" --argjson e "$LAST_LINES" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"exitCode":($c|tonumber),"lastOutput":$e}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
echo "Template type-check failed — see log above"
fi
# ---------------------------------------------------------------
# 5. Verify → Mend loop (only when version changed)
# ---------------------------------------------------------------
- name: Verify and mend loop
id: verify
if: steps.monitor.outputs.changes == 'true'
continue-on-error: true
working-directory: agent
run: |
START=$(date +%s)
VERIFY_RESULT="unknown"
MEND_ATTEMPTS=0
for attempt in $(seq 0 $MAX_MEND_RETRIES); do
echo ""
echo "=== Verification attempt $((attempt + 1)) of $((MAX_MEND_RETRIES + 1)) ==="
echo ""
if bash verify.sh; then
ELAPSED=$(( $(date +%s) - START ))
jq --arg s "verify" --arg r "success" --arg d "${ELAPSED}s" \
--arg a "$((attempt + 1))" --arg m "$MEND_ATTEMPTS" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"verifyAttempt":($a|tonumber),"mendRuns":($m|tonumber)}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit 0
fi
if [ "$attempt" -eq "$MAX_MEND_RETRIES" ]; then
ELAPSED=$(( $(date +%s) - START ))
# Capture verify failures for the report
FAILURES=""
if [ -f /tmp/verify-report.json ]; then
FAILURES=$(jq -c '.failures' /tmp/verify-report.json)
fi
jq --arg s "verify" --arg r "failed" --arg d "${ELAPSED}s" \
--arg a "$((attempt + 1))" --arg m "$MEND_ATTEMPTS" \
--argjson f "${FAILURES:-[]}" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"verifyAttempt":($a|tonumber),"mendRuns":($m|tonumber),"failures":$f}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
exit 1
fi
echo ""
echo "--- Running mending agent (attempt $((attempt + 1))) ---"
echo ""
MEND_ATTEMPTS=$((MEND_ATTEMPTS + 1))
npx tsx mending-agent.ts 2>&1 | tee /tmp/mending-agent-$((attempt + 1)).log
done
# ---------------------------------------------------------------
# 6. Report agent — always runs, even after failures
# ---------------------------------------------------------------
- name: Update state.json
if: always() && steps.monitor.outputs.changes == 'true'
working-directory: agent
run: |
if [ -f /tmp/fresh-state.json ]; then
cp /tmp/fresh-state.json state.json
fi
- name: Finalize pipeline log
if: always()
run: |
# Record final status of each step using GitHub context
jq \
--arg update_outcome "${{ steps.update.outcome || 'skipped' }}" \
--arg research_ts_outcome "${{ steps.research_ts.outcome || 'skipped' }}" \
--arg research_py_outcome "${{ steps.research_py.outcome || 'skipped' }}" \
--arg typecheck_outcome "${{ steps.typecheck.outcome || 'skipped' }}" \
--arg verify_outcome "${{ steps.verify.outcome || 'skipped' }}" \
--arg finished "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'. + {
"finishedAt": $finished,
"outcomes": {
"update": $update_outcome,
"research_ts": $research_ts_outcome,
"research_py": $research_py_outcome,
"typecheck": $typecheck_outcome,
"verify": $verify_outcome
}
}' "$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
echo "Pipeline log:"
cat "$PIPELINE_LOG" | jq .
- name: Run report agent
if: always()
continue-on-error: true
working-directory: agent
run: |
START=$(date +%s)
npx tsx report-agent.ts 2>&1 | tee /tmp/report-agent.log
EXIT_CODE=${PIPESTATUS[0]}
ELAPSED=$(( $(date +%s) - START ))
if [ "$EXIT_CODE" -eq 0 ]; then
jq --arg s "report" --arg r "success" --arg d "${ELAPSED}s" \
'.steps += [{"step":$s,"result":$r,"duration":$d}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
else
jq --arg s "report" --arg r "failed" --arg d "${ELAPSED}s" \
--arg c "$EXIT_CODE" \
'.steps += [{"step":$s,"result":$r,"duration":$d,"exitCode":($c|tonumber)}]' \
"$PIPELINE_LOG" > /tmp/pl.tmp && mv /tmp/pl.tmp "$PIPELINE_LOG"
fi
# ---------------------------------------------------------------
# 7. Stamp README with today's date
# ---------------------------------------------------------------
- name: Update README auto-updated date
if: always()
run: |
NOW=$(date -u +%Y-%m-%d)
sed -i "s/auto-updated\*\*: [0-9T:Z-]*/auto-updated**: $NOW/" README.md
# ---------------------------------------------------------------
# 8. Single commit — always runs to save report + partial work
# ---------------------------------------------------------------
- name: Commit and push
if: always()
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A .
if git diff --cached --quiet; then
echo "No changes to commit."
exit 0
fi
TODAY=$(date -u +%Y-%m-%d)
REPORT="/tmp/change-report.json"
# Check if any agent failed
HAS_FAILURES="false"
if jq -e '.outcomes | to_entries[] | select(.value == "failure")' "$PIPELINE_LOG" > /dev/null 2>&1; then
HAS_FAILURES="true"
fi
{
# Title
if [ "$HAS_FAILURES" == "true" ]; then
FAILED_STEPS=$(jq -r '[.outcomes | to_entries[] | select(.value == "failure") | .key] | join(", ")' "$PIPELINE_LOG")
if [ -f "$REPORT" ] && jq -e '.changes[] | select(.type == "npm_version")' "$REPORT" > /dev/null 2>&1; then
OLD_VER=$(jq -r '.oldVersion' "$REPORT")
NEW_VER=$(jq -r '.newVersion // "update"' "$REPORT")
echo "daily: partial run (${TODAY}) — ${FAILED_STEPS} failed [SDK v${OLD_VER} → v${NEW_VER}]"
else
echo "daily: partial run (${TODAY}) — ${FAILED_STEPS} failed"
fi
elif [ -f "$REPORT" ] && jq -e '.changes[] | select(.type == "npm_version")' "$REPORT" > /dev/null 2>&1; then
OLD_VER=$(jq -r '.oldVersion' "$REPORT")
NEW_VER=$(jq -r '.newVersion // "update"' "$REPORT")
echo "update: SDK v${OLD_VER} → v${NEW_VER} (${TODAY})"
else
echo "daily: research + report (${TODAY})"
fi
echo ""
# Version update details (if applicable)
if [ -f "$REPORT" ] && jq -e '.changes[] | select(.type == "npm_version")' "$REPORT" > /dev/null 2>&1; then
OLD_VER=$(jq -r '.oldVersion' "$REPORT")
NEW_VER=$(jq -r '.newVersion // "update"' "$REPORT")
echo "## Version Update"
echo "- Bump @anthropic-ai/claude-agent-sdk ${OLD_VER} → ${NEW_VER}"
RELEASE_NOTES=$(jq -r '.changes[] | select(.type == "github_release") | .releaseNotes // empty' "$REPORT")
[ -n "$RELEASE_NOTES" ] && echo "- Release notes: $(echo "$RELEASE_NOTES" | head -c 200)"
jq -e '.changes[] | select(.type == "peer_deps")' "$REPORT" > /dev/null 2>&1 && \
echo "- Peer deps: $(jq -c '.changes[] | select(.type == "peer_deps") | .old' "$REPORT") → $(jq -c '.changes[] | select(.type == "peer_deps") | .new' "$REPORT")"
jq -e '.changes[] | select(.type == "engines")' "$REPORT" > /dev/null 2>&1 && \
echo "- Engines: $(jq -c '.changes[] | select(.type == "engines") | .old' "$REPORT") → $(jq -c '.changes[] | select(.type == "engines") | .new' "$REPORT")"
for row in $(jq -c '.issueStateChanges[]?' "$REPORT"); do
echo "- Issue $(echo "$row" | jq -r '.repo')#$(echo "$row" | jq -r '.issue'): $(echo "$row" | jq -r '.oldState') → $(echo "$row" | jq -r '.newState')"
done
for row in $(jq -c '.newBugIssues[]?' "$REPORT"); do
echo "- New bug: #$(echo "$row" | jq -r '.issue') — $(echo "$row" | jq -r '.title')"
done
fi
# Research section
if git diff HEAD -- agent/state.json 2>/dev/null | grep -q '"verdict"'; then
echo ""
echo "## Research"
NEW_RESEARCHED=$(git diff HEAD -- agent/state.json | grep '^\+.*"verdict"' | wc -l | tr -d ' ')
ADDED=$(git diff HEAD -- agent/state.json | grep '^\+.*"added_known_issue\|added_rule"' | wc -l | tr -d ' ')
SKIPPED=$(git diff HEAD -- agent/state.json | grep '^\+.*"skipped"' | wc -l | tr -d ' ')
echo "Evaluated ${NEW_RESEARCHED} issue(s)."
[ "$ADDED" -gt 0 ] && echo "- Added ${ADDED} Known Issue(s) or rule(s)"
[ "$SKIPPED" -gt 0 ] && echo "- Skipped ${SKIPPED} issue(s)"
fi
# Failures section
if [ "$HAS_FAILURES" == "true" ]; then
echo ""
echo "## Failures"
jq -r '.steps[] | select(.result == "failed") | "- \(.step): exit \(.exitCode // "?") (\(.duration // "?"))"' "$PIPELINE_LOG"
fi
} > /tmp/commit-message.txt
git commit -F /tmp/commit-message.txt
git push
# ---------------------------------------------------------------
# 9. Fail the workflow if any critical step failed
# ---------------------------------------------------------------
- name: Check for failures
if: always()
run: |
UPDATE="${{ steps.update.outcome || 'skipped' }}"
RESEARCH_TS="${{ steps.research_ts.outcome || 'skipped' }}"
RESEARCH_PY="${{ steps.research_py.outcome || 'skipped' }}"
TYPECHECK="${{ steps.typecheck.outcome || 'skipped' }}"
VERIFY="${{ steps.verify.outcome || 'skipped' }}"
if [ "$UPDATE" == "failure" ] || [ "$RESEARCH_TS" == "failure" ] || [ "$RESEARCH_PY" == "failure" ] || [ "$TYPECHECK" == "failure" ] || [ "$VERIFY" == "failure" ]; then
echo "Pipeline had failures: update=$UPDATE research_ts=$RESEARCH_TS research_py=$RESEARCH_PY typecheck=$TYPECHECK verify=$VERIFY"
echo "Report and partial changes have been committed."
exit 1
fi