diff --git a/.github/workflows/jules-push.yml b/.github/workflows/jules-push.yml new file mode 100644 index 0000000..41c8b4c --- /dev/null +++ b/.github/workflows/jules-push.yml @@ -0,0 +1,122 @@ +name: Jules Push Monitor + +on: + push: + branches: + - '**' + +jobs: + # ── Detect whether any commit in this push is from JulesWyrm ────────────── + detect-jules: + runs-on: ubuntu-latest + outputs: + jules_pushed: ${{ steps.check.outputs.jules_pushed }} + commit_range: ${{ steps.check.outputs.commit_range }} + steps: + - name: Check commit authors + id: check + env: + COMMITS: ${{ toJson(github.event.commits) }} + BEFORE: ${{ github.event.before }} + AFTER: ${{ github.event.after }} + run: | + JULES_FOUND=$(echo "$COMMITS" | python3 -c " + import json, sys + commits = json.load(sys.stdin) + found = any(c.get('author', {}).get('username') == 'JulesWyrm' for c in commits) + print('true' if found else 'false') + ") + echo "jules_pushed=$JULES_FOUND" >> "$GITHUB_OUTPUT" + echo "commit_range=${BEFORE}..${AFTER}" >> "$GITHUB_OUTPUT" + + # ── Notify via Beeper ───────────────────────────────────────────────────── + notify: + needs: detect-jules + if: needs.detect-jules.outputs.jules_pushed == 'true' + runs-on: ubuntu-latest + steps: + - name: Send Beeper notification + # TODO: Confirm the following before enabling: + # 1. Base URL — if this is the Beeper Desktop API (localhost), it is not + # reachable from GitHub Actions. Confirm whether a cloud endpoint exists, + # or set up a proxy (e.g. a Vercel edge function that forwards to desktop). + # 2. Auth header — replace "Bearer" with the correct scheme if different. + # 3. accountID — add as a repo secret (BEEPER_ACCOUNT_ID). + # 4. user.id — your own Beeper user ID to start a self-DM (BEEPER_SELF_USER_ID). + # + # API shape (from https://developers.beeper.com/desktop-api-reference/resources/chats/methods/create): + # POST /v1/chats + # { + # "accountID": "", + # "mode": "start", + # "user": { "id": "" }, + # "messageText": "" + # } + env: + BEEPER_API_KEY: ${{ secrets.BEEPER_API_KEY }} + BEEPER_BASE_URL: ${{ vars.BEEPER_BASE_URL }} + BEEPER_ACCOUNT_ID: ${{ secrets.BEEPER_ACCOUNT_ID }} + BEEPER_SELF_USER_ID: ${{ secrets.BEEPER_SELF_USER_ID }} + BRANCH: ${{ github.ref_name }} + SHA: ${{ github.event.after }} + run: | + MESSAGE="JulesWyrm pushed to ${BRANCH} (${SHA:0:7}). A wiring-review issue has been opened." + curl -sf -X POST "${BEEPER_BASE_URL}/v1/chats" \ + -H "Authorization: Bearer ${BEEPER_API_KEY}" \ + -H "Content-Type: application/json" \ + -d "{ + \"accountID\": \"${BEEPER_ACCOUNT_ID}\", + \"mode\": \"start\", + \"user\": { \"id\": \"${BEEPER_SELF_USER_ID}\" }, + \"messageText\": \"${MESSAGE}\" + }" + + # ── Analyse diff and open issue assigned to Copilot ─────────────────────── + create-issue: + needs: detect-jules + if: needs.detect-jules.outputs.jules_pushed == 'true' + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + steps: + - name: Checkout full history + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Compute diff of Jules' commits + env: + BEFORE: ${{ github.event.before }} + AFTER: ${{ github.event.after }} + run: | + # If BEFORE is all-zeros the branch is new; diff against the first commit's parent. + if [[ "$BEFORE" == "0000000000000000000000000000000000000000" ]]; then + git diff "${AFTER}^..${AFTER}" > /tmp/jules-diff.patch || \ + git show "$AFTER" > /tmp/jules-diff.patch + else + git diff "${BEFORE}..${AFTER}" > /tmp/jules-diff.patch + fi + echo "Diff size: $(wc -c < /tmp/jules-diff.patch) bytes" + + - name: Analyse diff and build issue body + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: node scripts/analyze-diff.mjs < /tmp/jules-diff.patch > /tmp/issue-body.md + + - name: Open GitHub issue assigned to Copilot + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: ${{ github.ref_name }} + SHA: ${{ github.event.after }} + run: | + SHORT_SHA="${SHA:0:7}" + gh issue create \ + --title "Jules push on ${BRANCH} (${SHORT_SHA}): wiring review needed" \ + --body-file /tmp/issue-body.md \ + --assignee "@copilot" diff --git a/dev.md b/dev.md index 66c81d5..a5aa9f3 100644 --- a/dev.md +++ b/dev.md @@ -152,3 +152,41 @@ Run with `npm test`. 20 tests across 3 suites, all passing. | B001 | Fixed | Circuit suite iframe state loss on tab switch | Fixed by rendering both iframes simultaneously, toggling with CSS display:none | | B002 | Fixed | Electromagnet coil flat rendering (no depth) | Fixed draw order: back arches → rod (white fill) → front arches | | B003 | Reverted | Electromagnet integration removed from circuit tools | Symbol style did not match required exam format (hatched steel rod + stacked cell symbols). To be redesigned before re-integrating. | + +--- + +## Planned: Co-contributor Push Automation + +### Problem +JulesWyrm (co-contributor) pushes raw HTML tool additions/enhancements directly. These changes need Next.js wiring (new page, `tool-id`, tracker meta, tests) before they are production-ready. Currently this wiring is done manually after noticing her push. + +### Goal +Automate detection, notification, and issue creation whenever JulesWyrm pushes, so nothing falls through the cracks. + +### Design + +**Trigger:** GitHub Actions workflow on `push` to any branch. + +**Job 1 — Notify** +- Check if any commit author in the push is `JulesWyrm` +- If yes, call Beeper API to send a push notification to Kahhow + +**Job 2 — Auto-issue (runs only on JulesWyrm pushes)** +- Generate a diff of her changes using the full push range (`${before}..${after}`), not just the last commit; if `before` is all zeros (new branch), handle that case separately so the diff still covers everything introduced by the push +- Send the diff to Claude API (Anthropic) with a structured prompt that checks for: + - New HTML files in `public/tools/` → needs a Next.js page + `tool-id` added to `VALID_TOOLS` + - Missing `` or `\` tag before \`\` +- Every new tool also needs: + 3. A new route at \`app/tools//page.tsx\` that renders a full-viewport iframe + 4. A new tool-id string added to the VALID_TOOLS Set in \`app/api/event/route.ts\` + 5. A Jest test suite in \`__tests__/canvas/.test.js\` using + \`loadCircuitScript\` (non-IIFE) or \`loadIifeScript\` (IIFE scripts) + from \`__tests__/canvas/helpers.js\` +- When canvas logic functions change (snap, gcd, componentSize, getComponentNodes, + rotatePoint, getLocalNodes), the corresponding __tests__/canvas/ suite likely + needs updating. +- GRID=28, COMPONENT_SCALE=0.8 for circuit_diagram_creatorv2.html +- GRID=22.4 for circuit_diagram_secjc.html; includes transistor (3-node) and transformer (2-node) +- object_circuitv2.html: COMPONENT_SCALE=0.8 for battery/switch, BULB_SCALE=1 (bulb nodes unscaled) +` + +// Truncate at 48 000 chars to avoid runaway costs on huge diffs +const diffSnippet = diff.length > 48_000 + ? diff.slice(0, 48_000) + '\n\n[... diff truncated at 48 000 chars ...]' + : diff + +const USER_PROMPT = `\ +Below is a git diff from a push by JulesWyrm. Analyse it and produce a GitHub +issue body in Markdown describing the Next.js wiring work needed. + +Structure your response as: +1. A short (2-3 sentence) **Summary** of what changed. +2. A **Checklist** of actionable tasks (GitHub task-list syntax: \`- [ ] ...\`), + covering where relevant: + - New \`public/tools/\` HTML files that need a Next.js page + - Missing or incorrect \`\` tags + - Missing \`