diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 26a1f2b..975c2ac 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,6 +8,12 @@ "version": "1.0.0" }, "plugins": [ + { + "name": "openclaw-github-dedupe", + "source": "./skills/openclaw-github-dedupe", + "skills": "./", + "description": "Use this skill when a cluster of GitHub issues and pull requests has been reported for a common failure mode (Slack, iMessage, support threads, or manual list), and you need an evidence-based dedupe recommendation or execution." + }, { "name": "technical-deslop", "source": "./skills/technical-deslop", diff --git a/README.md b/README.md index 462bc0f..974eca3 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ This is my personal **.skills** repository for Codex, Cursor, OpenClaw and agent | `technical-documentation` | Produce dev‑ready docs: clear, structured build/review for brownfield + evergreen. | `npx skills add vincentkoc/dotskills --skill technical-documentation -y` | | `technical-integrations` | Design integrations that land: vendor‑agnostic API/RFC/SDK plans with rollout safety. | `npx skills add vincentkoc/dotskills --skill technical-integrations -y` | | `technical-skill-finder` | Turn real agent pain into new skills: mine logs, rank wins, draft next steps. | `npx skills add vincentkoc/dotskills --skill technical-skill-finder -y` | +| `openclaw-github-dedupe` | Triage GitHub issue/PR clusters, preserve contributor credit, and manage canonical duplicates safely. | `npx skills add vincentkoc/dotskills --skill openclaw-github-dedupe -y` | Internal/private workflow skills can live in this repo and are marked in the metadata as `internal: true` and excluded from public marketplace/release artifacts. @@ -47,6 +48,7 @@ npx skills add vincentkoc/dotskills --skill technical-deslop -y npx skills add vincentkoc/dotskills --skill technical-documentation -y npx skills add vincentkoc/dotskills --skill technical-integrations -y npx skills add vincentkoc/dotskills --skill technical-skill-finder -y +npx skills add vincentkoc/dotskills --skill openclaw-github-dedupe -y ``` List available public skills: diff --git a/catalog.yaml b/catalog.yaml index d6e2734..565e5f4 100644 --- a/catalog.yaml +++ b/catalog.yaml @@ -88,3 +88,10 @@ skills: source: local tags: [opik, integrations, audit, internal] version: 0.1.0 + + - id: openclaw-github-dedupe + name: Issue/PR Cluster Deduper + path: skills/openclaw-github-dedupe + source: local + tags: [github, triage, dedupe, issue-pr] + version: 0.1.0 diff --git a/releases/skills.json b/releases/skills.json index 26786e0..28ddbd3 100644 --- a/releases/skills.json +++ b/releases/skills.json @@ -1,6 +1,12 @@ { "repo": "vincentkoc/dotskills", "skills": [ + { + "name": "openclaw-github-dedupe", + "source": "./skills/openclaw-github-dedupe", + "description": "Use this skill when a cluster of GitHub issues and pull requests has been reported for a common failure mode (Slack, iMessage, support threads, or manual list), and you need an evidence-based dedupe recommendation or execution.", + "install": "npx skills add https://github.com/vincentkoc/dotskills --skill openclaw-github-dedupe -y" + }, { "name": "technical-deslop", "source": "./skills/technical-deslop", diff --git a/skills/openclaw-github-dedupe/SKILL.md b/skills/openclaw-github-dedupe/SKILL.md new file mode 100644 index 0000000..926e379 --- /dev/null +++ b/skills/openclaw-github-dedupe/SKILL.md @@ -0,0 +1,200 @@ +--- +name: openclaw-github-dedupe +description: Investigate a cluster of GitHub issues and PRs, determine canonical candidates, post duplicate/related status, preserve contributor credit, and execute cleanup actions (comments, closes, labels, changelog touchpoints). +license: AGPL-3.0-only +metadata: + short-description: GitHub triage for issue/PR dedupe clusters + source: "https://github.com/vincentkoc/dotskills" +--- + +# Issue/PR Cluster Deduper + +Use this skill when a cluster of GitHub issues and pull requests has been reported for a common failure mode (Slack, iMessage, support threads, or manual list), and you need an evidence-based dedupe recommendation or execution. + +## Purpose + +Provide a consistent, evidence-driven triage pass for issue and PR clusters so duplicate work is folded, contributor credit is preserved, and cleanup actions stay auditable. + +## When to use + +- You have a cluster of suspected duplicates to classify as canonical/related/independent. +- You need a concise dedupe plan with explicit credit and rationale before taking action. +- The user asked to execute safe closure/label/comment steps (or return a vetted plan only). +- You need to avoid duplicate PR churn by identifying which change should stay canonical. + +## Inputs + +- `cluster_refs` (required): list of issue/PR references as IDs or URLs. +- `mode` (optional): `plan` (default) or `execute`. +- `channel` (optional): source context like `slack`, `discord`, `support`, etc. +- `repo` (optional): explicit `owner/repo` when not using current checkout. +- `canonical_hint` (optional): explicit preference when ambiguity exists. +- `merge_guard` (optional): `high|medium` mergeability strictness; default `high`. +- `max_changed_files_for_canonical` (optional): default `30`. +- `max_delta_lines_for_canonical` (optional): default `2500`. +- `min_greptile_score` (optional): default `65` when available. +- `body_noise_mode` (optional): `strict|medium` for junk body tolerance; default `medium`. +- `reuse_copy_detection` (optional): `off|on` with default `on` for bot/copied-work checks. +- `bot_author_pattern` (optional): list of substrings for suspicious authors. +- `merge_tool_pref` (optional): `auto`, `gh`, `merge-skill`, or `land-skill`; default `auto`. + +## Workflow + +1. Fetch cluster evidence. + - For PRs: `gh pr view --json number,title,body,state,author,labels,createdAt,updatedAt,mergedAt,closedAt,mergeable,mergeStateStatus,isDraft,changedFiles,additions,deletions,statusCheckRollup,commits,url` + - For issues: `gh issue view --json number,title,body,state,labels,author,createdAt,updatedAt,url,comments` + - Pull quick file scope context if needed: `gh pr diff --name-only` + - Pull status checks: `gh pr checks ` + - Pull review/AI-tool comments for score hints: `gh issue view --json comments` + - Record common bot/copied-work signals: + - `author.login` ending with `[bot]` or matching `bot_author_pattern`. + - PR body that advertises generated/copied content (`generated by`, `copy/pasted`, `cherry-picked from`, etc.). + - Commit messages that indicate lifted or mechanical work without problem-specific reasoning. + +2. Normalize signals into a guardrail matrix. + - Mergeability signal: mergeable state, draft status, merge-state blockers, and check conclusions. + - Churn signal: `changedFiles`, `additions`, and `deletions`. + - Body hygiene signal: body length, meaningful root-cause description, and presence of placeholder/junk patterns (e.g. `WIP`, `TODO`, blank text, automation template only, no concrete impact). + - AI review signal: Greptile or equivalent score-like comments. If score is present and below threshold, downgrade confidence. + - Source integrity signal: bot/copied-work risk and commit provenance. + - Any PR matched by bot/copied-work signals is marked `review-heavy` and cannot become canonical without explicit manual confirmation. + +3. Run full review-on-candidate for likely canonical PR(s). + - For the top canonical candidate(s), perform a complete pass: + - `gh pr view --json files` and `gh pr diff `. + - `gh pr checks ` and ensure required checks are passing or have explicit acceptable exceptions. + - Quick duplicate/conflict scan against canonical cluster references via file overlap and root-cause text. + - If mergeability and hygiene are clean, treat this as the "winning PR" candidate and move to merge-prep. + +4. Choose canonical outputs. + - Prefer merged + validated PRs with mergeability and a strong scope match. + - If a newer item is a strict superset and still merge-safe, prefer the newer item. + - If two items have equivalent scope, keep the most stable/least conflicting anchor. + - If uncertainty is high, do not close anything; return a report of open questions. + +5. Apply hard guardrails before assigning `canonical` or `duplicate`. + - Mergeability hard-stop: + - Reject as canonical if `isDraft` is true. + - Reject as canonical if `mergeable` is false or `mergeStateStatus` indicates blocking. + - If checks are failing, mark as `manual-review-required` unless user explicitly wants forced action. + - Churn hard-stop: + - If `changedFiles > max_changed_files_for_canonical` or `additions + deletions > max_delta_lines_for_canonical`, do not auto-close other PRs as duplicate. + - Treat as related/review-needed even if overlap appears strong. + - Body hygiene hard-stop: + - For empty/junk bodies or no concrete root cause, classify confidence as low and require explicit manual confirmation before duplicate actions. + - AI review hard-stop: + - If a recognized score (for example Greptile) is below `min_greptile_score`, require manual confirmation before duplicates and avoid auto-canonicalization. + - Bot/copy hard-stop: + - If author appears as bot/auto-generated and work appears copied with low evidence of original validation, classify as `manual-review-required`. + - Do not suppress original human credit; keep attribution to originator and include a provenance note. + +6. Map outcomes. + - Canonical issue/PR: keep open. + - Duplicate PRs/issues: close with explicit duplicate rationale and credit. + - Winning PR that passes all guardrails: perform final review and help merge. + - Related but not duplicate: keep open and add explicit relationship note. + - Unrelated: split into separate routing plan. + - For any hard-stop failures, return `manual-review-required` with blockers listed. + +7. Merge and OpenClaw follow-up. + - If user asked `mode=execute` and the winning PR is green: + - Use `merge_tool_pref`: + - `merge-skill`/`land-skill`: invoke local merge/land workflow/skill if available. + - `gh`: run `gh pr merge --auto --merge` (or `--squash`, `--rebase` based on repo policy). + - `auto`: prefer merge/land skill first if detected; otherwise fallback to `gh` merge. + - Re-check checks after merge and report final state. + - If canonical PR is merge-ready but not yet merged, add/verify OpenClaw changelog entry in that PR: + - Check presence of `CHANGELOG.md`. + - If entry exists, do not duplicate; otherwise add a concise bullet under current unreleased `Fixes` section with PR number + credits. + - Prefer including this within the canonical PR before merge. + - If not possible, create follow-up squash commit after merge to add changelog. + +8. Run boundary check. + - If `mode=plan`, return a precise command plan and message drafts with confidence and blocker list. + - If `mode=execute`, run GH commands only for items with no blockers; otherwise stop and report. + +9. Emit results with explicit evidence and attribution. + +## Outputs + +- A canonicality assessment for the cluster with evidence bullets. +- A `plan` table: item, role (canonical/duplicate/related/unrelated), rationale, and confidence. +- A `risk register` per item for: `mergeability`, `churn`, `body_hygiene`, `ai_review_score`. +- A merge-readiness checklist for each candidate (checks, approvals, conflicts, branch state, policy alignment). +- For chosen canonical PR: explicit merge command used, merge result, and OpenClaw changelog action status. +- Draft close/keep messages containing contributor credits. +- Command list for labels/comments/close steps (and execution status when run). +- Explicit escalation notes for manual review and uncertainty. + +## Message templates + +### Canonical PR credit line +`This final fix is in #{canonical_pr} by @{canonical_author}. Earlier related work is credited to #{prior_pr} by @{prior_author}; thanks for that groundwork.` + +### Close duplicate PR +`Thanks for the earlier contribution. Closing as a duplicate of #{canonical_pr}. Your PR covered part of the same root cause and is credited in the canonical fix. If this is a mistake, please tell me and we'll reopen a review path.` + +### Keep canonical issue open +`Keeping this open as canonical for this {channel}-specific failure cluster.` + +### Close duplicate issue +`Closing as duplicate of #{canonical}. This matches the same root-cause path and behavior. Credit is tracked in #{canonical_pr} with foundational work from #{prior_pr}. If this is a mistake, please tell me and we'll reopen a review path.` + +### Related (not duplicate) +`This appears related but not a duplicate: symptom path diverges at {reason}. Keeping it open separately.` + +### Winning PR full-review summary +`I reviewed the winning PR for scope, checks, and mergeability. Conflicts: {status}. Check status: {status}. Final action: {merged|ready|blocked}.` + +### Unrelated (routing only) +`This appears separate from this cluster and should be tracked independently.` + +## Action commands + +> Run commands from repo checkout unless explicitly using full `owner/repo` URLs. + +### Add labels for closed duplicates +- PR/issue duplicate: `gh issue edit --add-label dedupe:child --add-label close:duplicate` (repo labels vary; use `duplicate` fallback as needed). +- Canonical issue: `gh issue edit --add-label dedupe:parent`. + +### Close with comment (issues) +- Comment first, then close: +`gh issue comment --body "..."` +`gh issue close --reason not planned` + +### Close PR +- For duplicate PR: `gh pr close --comment "..."`. + +### Guardrail helper checks +- Mergeability snapshot: +`gh pr view --json mergeable,mergeStateStatus,isDraft,statusCheckRollup` +- Churn snapshot: +`gh pr view --json changedFiles,additions,deletions` +- Greptile/AI review scan (optional): +`gh issue view --json comments` + +### Changelog policy +- If changelog already has an entry, do not duplicate it. +- If adding new entry, place under current Unreleased `### Fixes` section with PR number and contributor credits. + +### Suggested merge helpers +- Prefer local merge/land skill (`merge_tool_pref=merge-skill` or `land-skill`) when available and configured. +- Otherwise use: +`gh pr merge --merge --auto` +`gh pr merge --squash --auto` +`gh pr merge --rebase --auto` + +Select merge mode based on repo policy and branch protection requirements. + +## Git cleanup option +- To remove stale branch: +`git branch -D ` +`git push origin --delete ` + +## Safety / anti-patterns + +- Do not assume duplicate status from metadata alone; always inspect body + diff for scope overlap. +- Do not use failed closure defaults when hard-stop guardrails fail. +- Do not invent non-existent GH close reasons (for example, `--reason duplicate` in `gh issue close` is invalid; use `not planned` plus label/comments). +- Preserve evidence in each comment text for auditability. +- Do not merge or close items while mergeability/churn/AI-review warnings are unresolved. diff --git a/skills/openclaw-github-dedupe/agents/openai.yaml b/skills/openclaw-github-dedupe/agents/openai.yaml new file mode 100644 index 0000000..f8c77fa --- /dev/null +++ b/skills/openclaw-github-dedupe/agents/openai.yaml @@ -0,0 +1,10 @@ +interface: + display_name: "Issue/PR Cluster Deduper" + short_description: "Triages issue/PR clusters for duplicates, canonicalization, and audit-ready closure actions." + icon_small: "./assets/icon.jpg" + icon_large: "./assets/icon.jpg" + brand_color: "#111827" + default_prompt: "Run an evidence-based issue/PR cluster dedupe triage and propose safe closure actions with full contributor credit." + +policy: + allow_implicit_invocation: true diff --git a/skills/openclaw-github-dedupe/assets/icon.jpg b/skills/openclaw-github-dedupe/assets/icon.jpg new file mode 100644 index 0000000..8c8b22a Binary files /dev/null and b/skills/openclaw-github-dedupe/assets/icon.jpg differ