cc-pr-review-ci
GitHub用于对TypeScript/React代码进行PR审查的CI安全技能。按10个领域顺序分析变更,生成结构化review.json供脚本发布GitHub评论。支持加载历史驳回以避免重复反馈,并具备代码变更时的重新评估机制。
触发场景
安装
npx skills add NeverSight/learn-skills.dev --skill cc-pr-review-ci -g -y
SKILL.md
Frontmatter
{
"name": "cc-pr-review-ci",
"description": "Comprehensive TypeScript\/React PR review. Outputs structured review.json consumed by a posting script that creates a GitHub Review with inline comments. Agent runs read-only; the workflow script holds write permissions."
}
PR Review (single-agent, CI-safe)
Review a PR across 10 domains sequentially, then write review.json. A separate posting script turns the JSON into GitHub inline review comments.
If no PR number provided, diff against origin/main and print JSON to stdout.
Step 0 — Load prior dismissals (PR runs only)
Skip if no PR number provided.
Fetch all existing bot reviews on this PR:
gh api repos/{owner}/{repo}/pulls/$PR_NUMBER/reviews \
--jq '[.[] | select(.body | test("<!-- cc-pr-review -->"; "i")) | {id: .id, submitted_at: .submitted_at}]'
For each bot review found, fetch its inline comments:
gh api repos/{owner}/{repo}/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments \
--jq '[.[] | {id: .id, body: .body, path: .path, line: .line, reactions: .reactions}]'
Also fetch any reply threads on those inline comments:
gh api repos/{owner}/{repo}/pulls/$PR_NUMBER/comments \
--jq '[.[] | select(.in_reply_to_id != null) | {id: .id, in_reply_to_id: .in_reply_to_id, body: .body}]'
Build SUPPRESSED_FINDINGS: a list of finding id values to skip this run.
A finding is suppressed if its prior inline comment has:
- A 👎 reaction (
.reactions["-1"] > 0), or - A human reply containing dismissal language: "intentional", "by design", "won't fix", "false positive", "ignore", "not applicable", "expected"
Extract the finding id from the prior comment body — each inline comment posted by the script contains an HTML comment <!-- id: {finding-id} --> in the first line.
Escape hatch: if the file + surrounding lines for a suppressed finding appear in the current diff (i.e. the code actually changed), remove it from SUPPRESSED_FINDINGS — the finding must be re-evaluated.
If no prior reviews or no dismissals: SUPPRESSED_FINDINGS is empty.
Step 1 — Get the diff
- PR number given →
gh pr diff $PR_NUMBER - No PR number →
git diff origin/main
Step 2 — Run 10 domain reviews sequentially
Read the reference file for each domain, then analyze the diff. Record findings with their exact file path and line number.
Before recording any finding: check if its computed id ({domain}-{kebab-title}) is in SUPPRESSED_FINDINGS AND the relevant code lines have not changed in the current diff. If both conditions hold → skip silently.
- Security —
Read .claude/skills/cc-pr-review-ci/references/security.md - Performance —
Read .claude/skills/cc-pr-review-ci/references/performance.md - React/TypeScript —
Read .claude/skills/cc-pr-review-ci/references/react-ts.md - Testing —
Read .claude/skills/cc-pr-review-ci/references/testing.md - DevOps/CI —
Read .claude/skills/cc-pr-review-ci/references/devops.md - Holistic —
Read .claude/skills/cc-pr-review-ci/references/holistic.md - Duplication —
Read .claude/skills/cc-pr-review-ci/references/duplication.md - Bug Hunting —
Read .claude/skills/cc-pr-review-ci/references/bug.md - Scope/Hygiene —
Read .claude/skills/cc-pr-review-ci/references/scope.md - Maintainability —
Read .claude/skills/cc-pr-review-ci/references/thermo.md
Step 3 — Write review.json
-
Read
Read .claude/skills/cc-pr-review-ci/references/format.mdfor the exact schema. -
Merge all domain findings into a single
findingsarray. Assign each finding a stableidfollowing the{domain}-{kebab-title}convention. -
Determine verdict:
- Any
critical→CHANGES_REQUESTED highonly →APPROVED_WITH_SUGGESTIONSobservationsonly or none →APPROVED
- Any
-
Write the JSON:
- PR run: write to
$REVIEW_OUTPUT_PATH(default/tmp/review.json) - Local run (no PR number): print to stdout
- PR run: write to
Do not call gh to post anything. The workflow's post-review.js step handles all GitHub writes.
版本历史
- c3c0a1e 当前 2026-07-23 11:01


