6565 with :
6666 gpg-private-key : ${{ secrets.BOT_GPG_PRIVATE_KEY }}
6767
68- - name : Run updating skill with Claude Code
69- id : claude
70- timeout-minutes : 15
68+ - name : Update dependencies (haiku — fast, cheap)
69+ id : update
70+ timeout-minutes : 10
7171 shell : bash
7272 env :
7373 ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
8989
9090 set +e
9191 claude --print \
92- --model sonnet \
93- --max-turns 25 \
92+ --model haiku \
93+ --max-turns 15 \
9494 --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \
9595 "$(cat <<'PROMPT'
9696 /updating
@@ -104,7 +104,7 @@ jobs:
104104 Update all dependencies to their latest versions.
105105 Create one atomic commit per dependency update with a conventional commit message.
106106 Leave all changes local — the workflow handles pushing and PR creation.
107- Skip running builds, tests, and type checks — CI runs those separately .
107+ Do not run builds or tests — the next step handles that .
108108 </instructions>
109109
110110 <success_criteria>
@@ -124,20 +124,122 @@ jobs:
124124 echo "success=false" >> $GITHUB_OUTPUT
125125 fi
126126
127+ - name : Run tests
128+ id : tests
129+ if : steps.update.outputs.success == 'true'
130+ shell : bash
131+ run : |
132+ if [ -n "$SFW_BIN" ]; then
133+ mkdir -p /tmp/sfw-bin
134+ printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm
135+ chmod +x /tmp/sfw-bin/pnpm
136+ export PATH="/tmp/sfw-bin:$PATH"
137+ fi
138+
139+ set +e
140+ pnpm run build 2>&1 | tee build-output.log
141+ BUILD_EXIT=$?
142+ if [ "$BUILD_EXIT" -ne 0 ]; then
143+ echo "tests-passed=false" >> $GITHUB_OUTPUT
144+ exit 0
145+ fi
146+
147+ pnpm test 2>&1 | tee test-output.log
148+ TEST_EXIT=$?
149+ set -e
150+
151+ if [ "$TEST_EXIT" -eq 0 ]; then
152+ echo "tests-passed=true" >> $GITHUB_OUTPUT
153+ else
154+ echo "tests-passed=false" >> $GITHUB_OUTPUT
155+ fi
156+
157+ - name : Fix test failures (sonnet — smarter, escalated)
158+ id : claude
159+ if : steps.update.outputs.success == 'true' && steps.tests.outputs.tests-passed == 'false'
160+ timeout-minutes : 15
161+ shell : bash
162+ env :
163+ ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
164+ GITHUB_ACTIONS : ' true'
165+ run : |
166+ if [ -n "$SFW_BIN" ]; then
167+ mkdir -p /tmp/sfw-bin
168+ printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm
169+ chmod +x /tmp/sfw-bin/pnpm
170+ export PATH="/tmp/sfw-bin:$PATH"
171+ fi
172+
173+ # Collect failure context for the agent.
174+ FAILURE_LOG=""
175+ if [ -f build-output.log ]; then
176+ FAILURE_LOG+="Build output (last 50 lines):"$'\n'
177+ FAILURE_LOG+="$(tail -50 build-output.log)"$'\n\n'
178+ fi
179+ if [ -f test-output.log ]; then
180+ FAILURE_LOG+="Test output (last 100 lines):"$'\n'
181+ FAILURE_LOG+="$(tail -100 test-output.log)"$'\n'
182+ fi
183+
184+ set +e
185+ claude --print \
186+ --model sonnet \
187+ --max-turns 25 \
188+ --allowedTools "Bash(pnpm:*)" "Bash(git:*)" "Read" "Write" "Edit" "Glob" "Grep" \
189+ "$(cat <<PROMPT
190+ Build or tests failed after dependency updates. Fix them.
191+
192+ <failure_output>
193+ $FAILURE_LOG
194+ </failure_output>
195+
196+ <instructions>
197+ Diagnose the failures from the output above.
198+ Fix the code — do not revert the dependency updates.
199+ Run the tests again to verify your fix works.
200+ Create a commit for each fix with a conventional commit message.
201+ </instructions>
202+ PROMPT
203+ )" \
204+ 2>&1 | tee -a claude-output.log
205+ CLAUDE_EXIT=${PIPESTATUS[0]}
206+ set -e
207+
208+ if [ "$CLAUDE_EXIT" -eq 0 ]; then
209+ echo "success=true" >> $GITHUB_OUTPUT
210+ else
211+ echo "success=false" >> $GITHUB_OUTPUT
212+ fi
213+
214+ - name : Set final status
215+ id : final
216+ if : always()
217+ run : |
218+ # Success if: update succeeded AND (tests passed OR fix succeeded)
219+ if [ "${{ steps.update.outputs.success }}" = "true" ]; then
220+ if [ "${{ steps.tests.outputs.tests-passed }}" = "true" ] || [ "${{ steps.claude.outputs.success }}" = "true" ]; then
221+ echo "success=true" >> $GITHUB_OUTPUT
222+ exit 0
223+ fi
224+ fi
225+ echo "success=false" >> $GITHUB_OUTPUT
226+
127227 - name : Validate changes
128228 id : validate
129- if : steps.claude .outputs.success == 'true'
229+ if : steps.final .outputs.success == 'true'
130230 run : |
131- # Only allow changes to dependency-related files .
231+ # Allow dependency files + source/test fixes from the fix step .
132232 UNEXPECTED=""
133233 for file in $(git diff --name-only origin/main..HEAD); do
134234 case "$file" in
135- package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml|.npmrc|pnpm-workspace.yaml) ;;
235+ package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml) ;;
236+ .npmrc|pnpm-workspace.yaml) ;;
237+ src/*|test/*|*.ts|*.mts|*.js|*.mjs) ;;
136238 *) UNEXPECTED="$UNEXPECTED $file" ;;
137239 esac
138240 done
139241 if [ -n "$UNEXPECTED" ]; then
140- echo "::error::Unexpected files modified by Claude :$UNEXPECTED"
242+ echo "::error::Unexpected files modified:$UNEXPECTED"
141243 echo "valid=false" >> $GITHUB_OUTPUT
142244 else
143245 echo "valid=true" >> $GITHUB_OUTPUT
@@ -153,13 +255,13 @@ jobs:
153255 fi
154256
155257 - name : Push branch
156- if : steps.claude .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
258+ if : steps.final .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
157259 env :
158260 BRANCH_NAME : ${{ steps.branch.outputs.branch }}
159261 run : git push origin "$BRANCH_NAME"
160262
161263 - name : Create Pull Request
162- if : steps.claude .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
264+ if : steps.final .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
163265 env :
164266 GH_TOKEN : ${{ github.token }}
165267 BRANCH_NAME : ${{ steps.branch.outputs.branch }}
@@ -188,7 +290,7 @@ jobs:
188290 --base main
189291
190292 - name : Add job summary
191- if : steps.claude .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
293+ if : steps.final .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
192294 env :
193295 BRANCH_NAME : ${{ steps.branch.outputs.branch }}
194296 run : |
@@ -198,12 +300,15 @@ jobs:
198300 echo "**Branch:** \`${BRANCH_NAME}\`" >> $GITHUB_STEP_SUMMARY
199301 echo "**Commits:** ${COMMIT_COUNT}" >> $GITHUB_STEP_SUMMARY
200302
201- - name : Upload Claude output
303+ - name : Upload logs
202304 if : always()
203305 uses : actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
204306 with :
205- name : claude-output-${{ github.run_id }}
206- path : claude-output.log
307+ name : weekly-update-logs-${{ github.run_id }}
308+ path : |
309+ claude-output.log
310+ build-output.log
311+ test-output.log
207312 retention-days : 7
208313
209314 - uses : SocketDev/socket-registry/.github/actions/cleanup-git-signing@6096b06b1790f411714c89c40f72aade2eeaab7c # main
0 commit comments