docs(readme): Update README to include new skills and add GitHub Actions workflow for PR validation
This commit is contained in:
parent
cef29d3db4
commit
3bf63cdff2
2 changed files with 161 additions and 2 deletions
159
.github/workflows/label-ready-skill.yml
vendored
Normal file
159
.github/workflows/label-ready-skill.yml
vendored
Normal file
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue