5151 steps :
5252 - uses : SocketDev/socket-registry/.github/actions/setup-and-install@6096b06b1790f411714c89c40f72aade2eeaab7c # main
5353
54- # claude-code is now a devDependency, installed via setup-and-install
55-
5654 - name : Create update branch
5755 id : branch
5856 env :
@@ -67,25 +65,58 @@ jobs:
6765 with :
6866 gpg-private-key : ${{ secrets.BOT_GPG_PRIVATE_KEY }}
6967
70- - name : Run updating skill with Claude Code
71- id : claude
72- timeout-minutes : 30
68+ - name : Update dependencies (haiku — fast, cheap)
69+ id : update
70+ timeout-minutes : 10
7371 shell : bash
7472 env :
7573 ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
7674 GITHUB_ACTIONS : ' true'
7775 run : |
78- alias pnpm="$SFW_BIN pnpm"
76+ # Wrap pnpm through Socket firewall for all subprocesses (not just this shell).
77+ if [ -n "$SFW_BIN" ]; then
78+ mkdir -p /tmp/sfw-bin
79+ printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm
80+ chmod +x /tmp/sfw-bin/pnpm
81+ export PATH="/tmp/sfw-bin:$PATH"
82+ fi
83+
7984 if [ -z "$ANTHROPIC_API_KEY" ]; then
8085 echo "ANTHROPIC_API_KEY not set - skipping automated update"
8186 echo "success=false" >> $GITHUB_OUTPUT
8287 exit 0
8388 fi
8489
8590 set +e
86- claude --print --dangerously-skip-permissions \
87- --model sonnet \
88- "/updating" \
91+ claude --print \
92+ --model haiku \
93+ --max-turns 15 \
94+ --allowedTools \
95+ "Bash(pnpm:*)" \
96+ "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" \
97+ "Read" "Write" "Edit" "Glob" "Grep" \
98+ "$(cat <<'PROMPT'
99+ /updating
100+
101+ <context>
102+ You are an automated CI agent in a weekly dependency update workflow.
103+ Git is configured with GPG signing. A branch has been created for you.
104+ </context>
105+
106+ <instructions>
107+ Update all dependencies to their latest versions.
108+ Create one atomic commit per dependency update with a conventional commit message.
109+ Leave all changes local — the workflow handles pushing and PR creation.
110+ Do not run builds or tests — the next step handles that.
111+ </instructions>
112+
113+ <success_criteria>
114+ Each updated dependency has its own commit.
115+ The lockfile is consistent with package.json changes.
116+ No uncommitted changes remain in the working tree.
117+ </success_criteria>
118+ PROMPT
119+ )" \
89120 2>&1 | tee claude-output.log
90121 CLAUDE_EXIT=${PIPESTATUS[0]}
91122 set -e
@@ -96,6 +127,130 @@ jobs:
96127 echo "success=false" >> $GITHUB_OUTPUT
97128 fi
98129
130+ - name : Run tests
131+ id : tests
132+ if : steps.update.outputs.success == 'true'
133+ shell : bash
134+ run : |
135+ if [ -n "$SFW_BIN" ]; then
136+ mkdir -p /tmp/sfw-bin
137+ printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm
138+ chmod +x /tmp/sfw-bin/pnpm
139+ export PATH="/tmp/sfw-bin:$PATH"
140+ fi
141+
142+ set +e
143+ pnpm run build 2>&1 | tee build-output.log
144+ BUILD_EXIT=$?
145+ if [ "$BUILD_EXIT" -ne 0 ]; then
146+ echo "tests-passed=false" >> $GITHUB_OUTPUT
147+ exit 0
148+ fi
149+
150+ pnpm test 2>&1 | tee test-output.log
151+ TEST_EXIT=$?
152+ set -e
153+
154+ if [ "$TEST_EXIT" -eq 0 ]; then
155+ echo "tests-passed=true" >> $GITHUB_OUTPUT
156+ else
157+ echo "tests-passed=false" >> $GITHUB_OUTPUT
158+ fi
159+
160+ - name : Fix test failures (sonnet — smarter, escalated)
161+ id : claude
162+ if : steps.update.outputs.success == 'true' && steps.tests.outputs.tests-passed == 'false'
163+ timeout-minutes : 15
164+ shell : bash
165+ env :
166+ ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
167+ GITHUB_ACTIONS : ' true'
168+ run : |
169+ if [ -n "$SFW_BIN" ]; then
170+ mkdir -p /tmp/sfw-bin
171+ printf '#!/bin/bash\nexec "%s" pnpm "$@"\n' "$SFW_BIN" > /tmp/sfw-bin/pnpm
172+ chmod +x /tmp/sfw-bin/pnpm
173+ export PATH="/tmp/sfw-bin:$PATH"
174+ fi
175+
176+ # Collect failure context for the agent.
177+ FAILURE_LOG=""
178+ if [ -f build-output.log ]; then
179+ FAILURE_LOG+="Build output (last 50 lines):"$'\n'
180+ FAILURE_LOG+="$(tail -50 build-output.log)"$'\n\n'
181+ fi
182+ if [ -f test-output.log ]; then
183+ FAILURE_LOG+="Test output (last 100 lines):"$'\n'
184+ FAILURE_LOG+="$(tail -100 test-output.log)"$'\n'
185+ fi
186+
187+ set +e
188+ claude --print \
189+ --model sonnet \
190+ --max-turns 25 \
191+ --allowedTools \
192+ "Bash(pnpm:*)" \
193+ "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" \
194+ "Read" "Write" "Edit" "Glob" "Grep" \
195+ "$(cat <<PROMPT
196+ Build or tests failed after dependency updates. Fix them.
197+
198+ <failure_output>
199+ $FAILURE_LOG
200+ </failure_output>
201+
202+ <instructions>
203+ Diagnose the failures from the output above.
204+ Fix the code — do not revert the dependency updates.
205+ Run the tests again to verify your fix works.
206+ Create a commit for each fix with a conventional commit message.
207+ </instructions>
208+ PROMPT
209+ )" \
210+ 2>&1 | tee -a claude-output.log
211+ CLAUDE_EXIT=${PIPESTATUS[0]}
212+ set -e
213+
214+ if [ "$CLAUDE_EXIT" -eq 0 ]; then
215+ echo "success=true" >> $GITHUB_OUTPUT
216+ else
217+ echo "success=false" >> $GITHUB_OUTPUT
218+ fi
219+
220+ - name : Set final status
221+ id : final
222+ if : always()
223+ run : |
224+ # Success if: update succeeded AND (tests passed OR fix succeeded)
225+ if [ "${{ steps.update.outputs.success }}" = "true" ]; then
226+ if [ "${{ steps.tests.outputs.tests-passed }}" = "true" ] || [ "${{ steps.claude.outputs.success }}" = "true" ]; then
227+ echo "success=true" >> $GITHUB_OUTPUT
228+ exit 0
229+ fi
230+ fi
231+ echo "success=false" >> $GITHUB_OUTPUT
232+
233+ - name : Validate changes
234+ id : validate
235+ if : steps.final.outputs.success == 'true'
236+ run : |
237+ # Allow dependency files + source/test fixes from the fix step.
238+ UNEXPECTED=""
239+ for file in $(git diff --name-only origin/main..HEAD); do
240+ case "$file" in
241+ package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml) ;;
242+ .npmrc|pnpm-workspace.yaml) ;;
243+ src/*|test/*|*.ts|*.mts|*.js|*.mjs) ;;
244+ *) UNEXPECTED="$UNEXPECTED $file" ;;
245+ esac
246+ done
247+ if [ -n "$UNEXPECTED" ]; then
248+ echo "::error::Unexpected files modified:$UNEXPECTED"
249+ echo "valid=false" >> $GITHUB_OUTPUT
250+ else
251+ echo "valid=true" >> $GITHUB_OUTPUT
252+ fi
253+
99254 - name : Check for changes
100255 id : changes
101256 run : |
@@ -106,13 +261,13 @@ jobs:
106261 fi
107262
108263 - name : Push branch
109- if : steps.claude .outputs.success == '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'
110265 env :
111266 BRANCH_NAME : ${{ steps.branch.outputs.branch }}
112267 run : git push origin "$BRANCH_NAME"
113268
114269 - name : Create Pull Request
115- if : steps.claude .outputs.success == 'true' && steps.changes.outputs.has-changes == 'true'
270+ if : steps.final .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
116271 env :
117272 GH_TOKEN : ${{ github.token }}
118273 BRANCH_NAME : ${{ steps.branch.outputs.branch }}
@@ -141,7 +296,7 @@ jobs:
141296 --base main
142297
143298 - name : Add job summary
144- if : steps.claude .outputs.success == 'true' && steps.changes.outputs.has-changes == 'true'
299+ if : steps.final .outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
145300 env :
146301 BRANCH_NAME : ${{ steps.branch.outputs.branch }}
147302 run : |
@@ -151,12 +306,15 @@ jobs:
151306 echo "**Branch:** \`${BRANCH_NAME}\`" >> $GITHUB_STEP_SUMMARY
152307 echo "**Commits:** ${COMMIT_COUNT}" >> $GITHUB_STEP_SUMMARY
153308
154- - name : Upload Claude output
309+ - name : Upload logs
155310 if : always()
156311 uses : actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
157312 with :
158- name : claude-output-${{ github.run_id }}
159- path : claude-output.log
313+ name : weekly-update-logs-${{ github.run_id }}
314+ path : |
315+ claude-output.log
316+ build-output.log
317+ test-output.log
160318 retention-days : 7
161319
162320 - uses : SocketDev/socket-registry/.github/actions/cleanup-git-signing@6096b06b1790f411714c89c40f72aade2eeaab7c # main
0 commit comments