diff --git a/.github/workflows/label-ready-skill.yml b/.github/workflows/label-ready-skill.yml new file mode 100644 index 0000000..ce7320e --- /dev/null +++ b/.github/workflows/label-ready-skill.yml @@ -0,0 +1,159 @@ +name: Label ready-to-merge skill listings + +on: + pull_request_target: + types: [opened, synchronize, reopened, edited] + +permissions: + contents: read + pull-requests: write + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Fetch base README + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BASE_REPO: ${{ github.event.pull_request.base.repo.full_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} + run: | + gh api "repos/$BASE_REPO/contents/README.md?ref=$BASE_SHA" \ + -H "Accept: application/vnd.github.raw" > base.md + + - name: Fetch head README + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + gh api "repos/$HEAD_REPO/contents/README.md?ref=$HEAD_SHA" \ + -H "Accept: application/vnd.github.raw" > head.md + + - name: List changed files + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR: ${{ github.event.pull_request.number }} + run: | + gh api "repos/$REPO/pulls/$PR/files" --paginate -q '.[].filename' > changed.txt + cat changed.txt + + - name: Validate PR + id: validate + run: | + node <<'EOF' + const fs = require('fs'); + const base = fs.readFileSync('base.md', 'utf8'); + const head = fs.readFileSync('head.md', 'utf8'); + const changed = fs.readFileSync('changed.txt', 'utf8') + .split('\n').map(s => s.trim()).filter(Boolean); + + const fail = (msg) => { console.error('FAIL:', msg); process.exit(1); }; + + // 1. Only README.md changed + if (changed.length === 0) fail('no changed files reported'); + for (const f of changed) { + if (f !== 'README.md') fail(`disallowed file changed: ${f}`); + } + + // 2. Locate Skills <-> Getting Started bounds in both base and head + const bounds = (text) => { + const lines = text.split('\n'); + let start = -1, end = -1; + for (let i = 0; i < lines.length; i++) { + if (start === -1 && /^##\s+Skills\s*$/.test(lines[i])) start = i; + else if (start !== -1 && /^##\s+Getting Started\s*$/.test(lines[i])) { end = i; break; } + } + if (start === -1 || end === -1) fail('could not locate Skills / Getting Started markers'); + return { lines, start, end }; + }; + const b = bounds(base); + const h = bounds(head); + + // 3. All edits must be within the Skills..Getting Started window. + // Compare lines outside the window — they must be identical. + const outside = (o) => [ + o.lines.slice(0, o.start).join('\n'), + o.lines.slice(o.end).join('\n'), + ]; + const [bPre, bPost] = outside(b); + const [hPre, hPost] = outside(h); + if (bPre !== hPre) fail('changes detected before the Skills section'); + if (bPost !== hPost) fail('changes detected after the Getting Started section'); + + // 4. Diff inside the window — find added bullet lines. + const bInside = b.lines.slice(b.start, b.end); + const hInside = h.lines.slice(h.start, h.end); + const bSet = new Set(bInside); + const addedLines = hInside.filter(l => !bSet.has(l)); + + const bulletRe = /^\s*-\s+\[([^\]]+)\]\(([^)]+)\)/; + const addedBullets = addedLines + .map(l => ({ line: l, m: l.match(bulletRe) })) + .filter(x => x.m) + .map(x => ({ line: x.line, name: x.m[1], url: x.m[2] })); + + if (addedBullets.length === 0) fail('no new skill bullet detected in PR'); + + // 5. Every added bullet must link to an external repo (https, not our own host). + for (const b of addedBullets) { + if (!/^https?:\/\//i.test(b.url)) { + fail(`bullet "${b.name}" does not link to an external URL: ${b.url}`); + } + try { + const u = new URL(b.url); + const host = u.hostname.toLowerCase(); + if (host.endsWith('composio.dev') || host.endsWith('anthropic.com')) { + fail(`bullet "${b.name}" links to internal host ${host}`); + } + } catch { fail(`bullet "${b.name}" has invalid URL`); } + } + + // 6. No crypto/web3/blockchain/nft keywords anywhere in added lines. + const blocked = /\b(crypto|cryptocurrency|web3|blockchain|nft|defi|token(?:omics)?|wallet\b|solana|ethereum|bitcoin)\b/i; + for (const line of addedLines) { + if (blocked.test(line)) fail(`blocked keyword in added line: ${line.trim()}`); + } + + // 7. Each added bullet must sit alphabetically between its immediate + // neighbors in its category (case-insensitive). Existing disorder + // elsewhere in the category is grandfathered. + const addedSet = new Set(addedBullets.map(b => b.line)); + let category = null; + const groups = new Map(); // category -> [{name, added}] + for (const line of hInside) { + const hMatch = line.match(/^###\s+(.+?)\s*$/); + if (hMatch) { category = hMatch[1]; continue; } + const m = line.match(bulletRe); + if (m && category) { + if (!groups.has(category)) groups.set(category, []); + groups.get(category).push({ name: m[1], added: addedSet.has(line) }); + } + } + const ci = (s) => s.toLowerCase(); + for (const [cat, items] of groups) { + for (let i = 0; i < items.length; i++) { + if (!items[i].added) continue; + const prev = items[i - 1]; + const next = items[i + 1]; + if (prev && ci(prev.name).localeCompare(ci(items[i].name)) > 0) { + fail(`"${items[i].name}" placed after "${prev.name}" in category "${cat}" (out of alphabetical order)`); + } + if (next && ci(items[i].name).localeCompare(ci(next.name)) > 0) { + fail(`"${items[i].name}" placed before "${next.name}" in category "${cat}" (out of alphabetical order)`); + } + } + } + + console.log('OK: PR meets all criteria'); + EOF + + - name: Add ready-to-merge label + if: success() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR: ${{ github.event.pull_request.number }} + run: | + gh pr edit "$PR" --repo "$REPO" --add-label "ready-to-merge" diff --git a/README.md b/README.md index c3dd33c..116ef58 100644 --- a/README.md +++ b/README.md @@ -115,10 +115,12 @@ Claude Skills are customizable workflows that teach Claude how to perform specif - [Changelog Generator](./changelog-generator/) - Automatically creates user-facing changelogs from git commits by analyzing history and transforming technical commits into customer-friendly release notes. - [Chrome Relay](https://chrome-relay.kushalsm.com/) - Drives the user's already-open Chrome session — cookies, SSO, extensions, localhost — through a local CLI bridge. Real-Chrome counterpart to Playwright Browser Automation; install via `npx skills add chrome-relay` + a [Chrome Web Store extension](https://chromewebstore.google.com/detail/chrome-relay/cpdiapbifblhlcpnmlmfpgfjlacebokb). No remote relay, no Playwright fixtures, no MCP server needed. - [Claude Code Terminal Title](https://github.com/bluzername/claude-code-terminal-title) - Gives each Claud-Code terminal window a dynamic title that describes the work being done so you don't lose track of what window is doing what. +- [Connect](./connect/) - Connect Claude to any app. Send emails, create issues, post messages, update databases - take real actions across Gmail, Slack, GitHub, Notion, and 1000+ services. - [D3.js Visualization](https://github.com/chrisvoncsefalvay/claude-d3js-skill) - Teaches Claude to produce D3 charts and interactive data visualizations. *By [@chrisvoncsefalvay](https://github.com/chrisvoncsefalvay)* - [FFUF Web Fuzzing](https://github.com/jthack/ffuf_claude_skill) - Integrates the ffuf web fuzzer so Claude can run fuzzing tasks and analyze results for vulnerabilities. *By [@jthack](https://github.com/jthack)* - [finishing-a-development-branch](https://github.com/obra/superpowers/tree/main/skills/finishing-a-development-branch) - Guides completion of development work by presenting clear options and handling chosen workflow. - [Full-Page Screenshot](https://github.com/LewisLiu007/full-page-screenshot) - Captures full-page screenshots of web pages via Chrome DevTools Protocol with zero dependencies. *By [@LewisLiu007](https://github.com/LewisLiu007)* +- [great_cto](https://github.com/avelikiy/great_cto) - Claude Code plugin: 7 specialised subagents (tech-lead, senior-dev, qa-engineer, security-officer, devops, l3-support, project-auditor) orchestrating a full SDLC pipeline — architecture, TDD, 12-angle code review, QA, security audit, deploy. 11 project archetypes auto-detected, 13 compliance frameworks (GDPR/PCI-DSS/HIPAA/SOC2/ISO 27001), self-improving knowledge layer that learns from every incident. *By [@avelikiy](https://github.com/avelikiy)* - [iOS Simulator](https://github.com/conorluddy/ios-simulator-skill) - Enables Claude to interact with iOS Simulator for testing and debugging iOS applications. *By [@conorluddy](https://github.com/conorluddy)* - [jules](https://github.com/sanjay3290/ai-skills/tree/main/skills/jules) - Delegate coding tasks to Google Jules AI agent for async bug fixes, documentation, tests, and feature implementation on GitHub repos. *By [@sanjay3290](https://github.com/sanjay3290)* - [LangSmith Fetch](./langsmith-fetch/) - Debug LangChain and LangGraph agents by automatically fetching and analyzing execution traces from LangSmith Studio. First AI observability skill for Claude Code. *By [@OthmanAdi](https://github.com/OthmanAdi)* @@ -137,8 +139,6 @@ Claude Skills are customizable workflows that teach Claude how to perform specif - [subagent-driven-development](https://github.com/NeoLabHQ/context-engineering-kit/tree/master/plugins/sadd/skills/subagent-driven-development) - Dispatches independent subagents for individual tasks with code review checkpoints between iterations for rapid, controlled development. - [test-driven-development](https://github.com/obra/superpowers/tree/main/skills/test-driven-development) - Use when implementing any feature or bugfix, before writing implementation code. - [using-git-worktrees](https://github.com/obra/superpowers/blob/main/skills/using-git-worktrees/) - Creates isolated git worktrees with smart directory selection and safety verification. -- [Connect](./connect/) - Connect Claude to any app. Send emails, create issues, post messages, update databases - take real actions across Gmail, Slack, GitHub, Notion, and 1000+ services. -- [great_cto](https://github.com/avelikiy/great_cto) - Claude Code plugin: 7 specialised subagents (tech-lead, senior-dev, qa-engineer, security-officer, devops, l3-support, project-auditor) orchestrating a full SDLC pipeline — architecture, TDD, 12-angle code review, QA, security audit, deploy. 11 project archetypes auto-detected, 13 compliance frameworks (GDPR/PCI-DSS/HIPAA/SOC2/ISO 27001), self-improving knowledge layer that learns from every incident. *By [@avelikiy](https://github.com/avelikiy)* - [Webapp Testing](./webapp-testing/) - Tests local web applications using Playwright for verifying frontend functionality, debugging UI behavior, and capturing screenshots. ### Data & Analysis