1350
--body "$BODY"
1351
fi
1352
1353
- reskill-check:
1354
- needs: [crawl]
1355
- runs-on: ubuntu-latest
1356
- outputs:
1357
- should_reskill: ${{ steps.check.outputs.reskill }}
1358
-
1359
- steps:
1360
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
1361
- with:
1362
- fetch-depth: 0
1363
- ref: publish
1364
- persist-credentials: false
1365
- continue-on-error: true
1366
-
1367
- - name: Fallback to default branch for counter
1368
- env:
1369
- DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
1370
- run: |
1371
- if [ ! -f .squad/run-counter.txt ]; then
1372
- git fetch origin "$DEFAULT_BRANCH" 2>/dev/null || true
1373
- git checkout "origin/$DEFAULT_BRANCH" -- .squad/run-counter.txt 2>/dev/null || true
1374
- fi
1375
-
1376
- - name: Check reskill trigger
1377
- id: check
1378
- run: |
1379
- COUNTER=$(cat .squad/run-counter.txt 2>/dev/null || echo 0)
1380
- if [ $((COUNTER % 5)) -eq 0 ] && [ "$COUNTER" -gt 0 ]; then
1381
- echo "reskill=true" >> $GITHUB_OUTPUT
1382
- echo "🔄 Reskill triggered at run #$COUNTER"
1383
- else
1384
- echo "reskill=false" >> $GITHUB_OUTPUT
1385
- echo "📊 Run #$COUNTER — next reskill at run #$(( (COUNTER/5 + 1) * 5 ))"
1386
- fi
1387
-
1388
- reskill:
1389
- needs: [reskill-check]
1390
- if: needs.reskill-check.outputs.should_reskill == 'true'
1391
- runs-on: ubuntu-latest
1392
- permissions:
1393
- contents: write
1394
-
1395
- steps:
1396
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # zizmor: ignore[artipacked] reskill job pushes to the publish branch; checkout token is reused by a later git push
1397
- with:
1398
- fetch-depth: 0
1399
- ref: publish
1400
- continue-on-error: true
1401
-
1402
- - name: Fallback to default branch
1403
- env:
1404
- DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
1405
- run: |
1406
- if [ ! -d .squad ]; then
1407
- git fetch origin "$DEFAULT_BRANCH"
1408
- git checkout "origin/$DEFAULT_BRANCH" -- . 2>/dev/null || true
1409
- fi
1410
-
1411
- - name: Set up Node
1412
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
1413
- with:
1414
- node-version: '24'
1415
-
1416
- - name: Set up Python
1417
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
1418
- with:
1419
- python-version: '3.12'
1420
-
1421
- - name: Install Copilot CLI
1422
- run: npm install -g @github/copilot
1423
-
1424
- - name: Run reskill
1425
- env:
1426
- DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
1427
- COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GH_TOKEN }}
1428
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1429
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1430
- run: |
1431
- set -euo pipefail
1432
- git config user.name "github-actions[bot]"
1433
- git config user.email "github-actions[bot]@users.noreply.github.com"
1434
- COUNTER=$(cat .squad/run-counter.txt 2>/dev/null || echo 0)
1435
- CURRENT_DATETIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
1436
- WEEK=$(date -u +%G-W%V)
1437
- RESKILL_OUTPUT=".squad/reskill/${WEEK}.md"
1438
- RESKILL_PROMPT=".squad/reskill/current-prompt.md"
1439
- mkdir -p .squad/skills .squad/reskill data/metrics
1440
-
1441
- sanitize_agent_output() {
1442
- python3 scripts/sanitize_agent_output.py --path "$1"
1443
- }
1444
-
1445
- # Primary path: Copilot CLI with agent identity
1446
- RESKILL_SOURCE="copilot-cli"
1447
- RESKILL_MODEL="copilot-default"
1448
- python3 scripts/reskill.py --current-datetime "$CURRENT_DATETIME" --output "$RESKILL_OUTPUT" --prompt-output "$RESKILL_PROMPT" --print-prompt > "$RESKILL_PROMPT" || true
1449
-
1450
- # Intentionally rely on Copilot CLI's default model so CI follows the platform-supported default.
1451
- RESKILL_FAILURE_CLASS=""
1452
- if command -v copilot >/dev/null 2>&1; then
1453
- set +e
1454
- copilot \
1455
- --agent weekly-analysis \
1456
- -p "Read the file at ${RESKILL_PROMPT}. Write the complete reskill markdown to ${RESKILL_OUTPUT}. The run is incomplete until ${RESKILL_OUTPUT} exists and is non-empty. Do not delegate. Do not spawn sub-agents. Do not emit commentary." \
1457
- -s \
1458
- --no-ask-user \
1459
- --allow-tool=read \
1460
- --allow-tool=write \
1461
- > /dev/null
1462
- COPILOT_STATUS=$?
1463
- set -e
1464
- if [ "$COPILOT_STATUS" -eq 0 ] && test -s "$RESKILL_OUTPUT"; then
1465
- echo "✅ Reskill via focused analysis agent"
1466
- else
1467
- if [ "$COPILOT_STATUS" -eq 0 ]; then
1468
- RESKILL_FAILURE_CLASS="writer_contract_failure"
1469
- echo "::warning::Reskill writer contract failed: ${RESKILL_OUTPUT} missing or empty after Copilot completed."
1470
- else
1471
- RESKILL_FAILURE_CLASS="copilot_cli_failure"
1472
- echo "::warning::Reskill Copilot CLI invocation failed with exit code ${COPILOT_STATUS}."
1473
- fi
1474
- RESKILL_SOURCE="none"
1475
- RESKILL_MODEL="none"
1476
- rm -f "$RESKILL_PROMPT"
1477
- echo "Copilot CLI reskill failed; no GitHub Models/OpenAI reskill fallback is configured. Writing placeholder trigger log."
1478
- {
1479
- echo "Reskill triggered at run #$COUNTER ($CURRENT_DATETIME)"
1480
- echo "Failure class: ${RESKILL_FAILURE_CLASS}"
1481
- } >> .squad/reskill/trigger-log.txt
1482
- fi
1483
- else
1484
- RESKILL_FAILURE_CLASS="copilot_inaccessible"
1485
- RESKILL_SOURCE="none"
1486
- RESKILL_MODEL="none"
1487
- rm -f "$RESKILL_PROMPT"
1488
- echo "Copilot CLI reskill failed; no GitHub Models/OpenAI reskill fallback is configured. Writing placeholder trigger log."
1489
- {
1490
- echo "Reskill triggered at run #$COUNTER ($CURRENT_DATETIME)"
1491
- echo "Failure class: ${RESKILL_FAILURE_CLASS}"
1492
- } >> .squad/reskill/trigger-log.txt
1493
- fi
1494
-
1495
- if [ "$RESKILL_SOURCE" != "none" ]; then
1496
- sanitize_agent_output "$RESKILL_OUTPUT"
1497
- fi
1498
-
1499
- if [ "$RESKILL_SOURCE" != "none" ]; then
1500
- API_RESPONSE_ARGS=""
1501
- if [ -f "data/metrics/reskill-api-response.json" ]; then
1502
- API_RESPONSE_ARGS="--api-response data/metrics/reskill-api-response.json"
1503
- fi
1504
- python3 scripts/track_token_usage.py \
1505
- --stage reskill \
1506
- --source "$RESKILL_SOURCE" \
1507
- --model "$RESKILL_MODEL" \
1508
- --current-datetime "$CURRENT_DATETIME" \
1509
- --week "$WEEK" \
1510
- --prompt-file "$RESKILL_PROMPT" \
1511
- --output-file "$RESKILL_OUTPUT" \
1512
- $API_RESPONSE_ARGS
1513
- rm -f "$RESKILL_PROMPT"
1514
- echo "🔄 Reskill report generated for run #$COUNTER"
1515
- fi
1516
-
1517
- if ! git status --short -- .squad data/metrics | grep -q .; then
1518
- echo "No .squad or token usage changes to commit."
1519
- exit 0
1520
- fi
1521
-
1522
- cp -r .squad squad-state-backup
1523
- cp -r data/metrics reskill-metrics-backup
1524
- DATA_BRANCH="publish"
1525
- if git fetch origin "$DATA_BRANCH" 2>/dev/null; then
1526
- git checkout -f -B "$DATA_BRANCH" "origin/$DATA_BRANCH"
1527
- else
1528
- git fetch origin "$DEFAULT_BRANCH"
1529
- git checkout -f -B "$DATA_BRANCH" "origin/$DEFAULT_BRANCH"
1530
- fi
1531
- cp -r squad-state-backup/* .squad/ 2>/dev/null || true
1532
- mkdir -p data/metrics
1533
- cp -r reskill-metrics-backup/* data/metrics/ 2>/dev/null || true
1534
- rm -rf squad-state-backup reskill-metrics-backup
1535
- git add .squad/ data/metrics/
1536
- git diff --cached --quiet && exit 0
1537
- git commit -m "chore: reskill state update [run #${GITHUB_RUN_ID}]"
1538
- git push origin "$DATA_BRANCH"