feat(github,commit): remove terminal-ui-design, add batch ops and PR templates#20
Conversation
…templates - Remove terminal-ui-design plugin (consolidated with frontend-design) - Add GitHub batch commands: bulk-close-issues, bulk-merge-prs, bulk-label - Add PR templates to commit plugin (default, bugfix, feature) - Add PR automation GitHub Action for auto-labeling and reviewer assignment - Enhance GitHub documentation with examples, troubleshooting, and gotchas - Add github/examples/ directory with automation scripts - Update plugin versions: github@1.2.0, commit@1.3.0 Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>
Reviewer's GuideRemoves the deprecated terminal-ui-design plugin, adds GitHub batch operation commands and documentation, enhances the commit plugin with PR templates and improved /commit:and-create-pr behavior, and introduces a PR automation GitHub Action plus marketplace/readme metadata updates. Sequence diagram for enhanced /commit:and-create-pr with PR templates and draft optionsequenceDiagram
actor Developer
participant CommitCommand as Commit_and_create_pr
participant Git
participant TemplateSelector
participant PRTemplates as PR_template_files
participant GitHubCLI as gh
Developer->>CommitCommand: invoke /commit:and-create-pr [options]
CommitCommand->>Git: git status, git diff, git branch
Git-->>CommitCommand: repo state
CommitCommand->>Git: git commit -m "semantic message"
Git-->>CommitCommand: commit created
CommitCommand->>TemplateSelector: determine template(commit_type, cli_template_option)
TemplateSelector-->>CommitCommand: template_name (default | bugfix | feature)
CommitCommand->>PRTemplates: read template_file(template_name)
alt template file exists
PRTemplates-->>CommitCommand: template_body
CommitCommand->>CommitCommand: substitute placeholders (description, changes, etc.)
CommitCommand-->>CommitCommand: PR_BODY
else template missing or read error
PRTemplates-->>CommitCommand: read error
CommitCommand->>CommitCommand: build fallback PR_BODY
end
alt --draft flag provided
CommitCommand->>GitHubCLI: gh pr create --title COMMIT_MSG --body PR_BODY --draft
else
CommitCommand->>GitHubCLI: gh pr create --title COMMIT_MSG --body PR_BODY
end
GitHubCLI-->>Developer: PR URL
Class diagram for GitHub and commit plugin structures with batch commands and PR templatesclassDiagram
class GitHubPlugin {
+string name
+string version
+GitHubSkill github
+BulkCloseIssuesCommand bulk_close_issues
+BulkMergePrsCommand bulk_merge_prs
+BulkLabelCommand bulk_label
}
class GitHubSkill {
+string description
+string documentation_file
}
class BulkCloseIssuesCommand {
+string description
+execute(label, search, comment, state, dry_run)
}
class BulkMergePrsCommand {
+string description
+execute(label, reviewer_approved, search, method, delete_branch, dry_run)
}
class BulkLabelCommand {
+string description
+execute(add_labels, remove_labels, label, search, type, dry_run)
}
GitHubPlugin --> GitHubSkill
GitHubPlugin --> BulkCloseIssuesCommand
GitHubPlugin --> BulkMergePrsCommand
GitHubPlugin --> BulkLabelCommand
class CommitPlugin {
+string name
+string version
+CommitAndCreatePrCommand commit_and_create_pr
+PrTemplate default_template
+PrTemplate bugfix_template
+PrTemplate feature_template
}
class CommitAndCreatePrCommand {
+string description
+run(template_name, draft, title, body)
+select_template(commit_type, template_name)
+build_pr_body(template)
}
class PrTemplate {
+string name
+string file_path
+string content
}
CommitPlugin --> CommitAndCreatePrCommand
CommitPlugin --> PrTemplate : uses
CommitAndCreatePrCommand --> PrTemplate : selects
class PrAutomationWorkflow {
+string name
+auto_label(files, commits)
+auto_assign(files)
+welcome_first_time(author)
}
class LabelRules {
+apply_area_labels(files)
+apply_breaking_label(commits)
+apply_documentation_label(files)
}
class ReviewerRules {
+assign_frontend(files)
+assign_backend(files)
+assign_api(files)
+assign_devops(files)
}
PrAutomationWorkflow --> LabelRules
PrAutomationWorkflow --> ReviewerRules
Flow diagram for GitHub bulk operations commands (close issues, merge PRs, label)flowchart TD
Start([Start])
ChooseCmd{Select command}
CmdClose["/github:bulk-close-issues"]
CmdMerge["/github:bulk-merge-prs"]
CmdLabel["/github:bulk-label"]
GatherOpts["Parse CLI options\n(label, search, type, method, add/remove, delete-branch)"]
ListItems["Query matching items via gh\n(issues or PRs)"]
AnyItems{Any items found?}
ShowPreview["Show items and planned changes"]
DryRun{--dry-run?}
Confirm["Ask for confirmation"]
ApplyClose["gh issue close\n(+ optional comment)"]
ApplyMerge["gh pr merge\n(+ optional delete branch)"]
ApplyLabel["gh issue/pr edit\n(add/remove labels)"]
End([End])
Start --> ChooseCmd
ChooseCmd -->|bulk-close-issues| CmdClose
ChooseCmd -->|bulk-merge-prs| CmdMerge
ChooseCmd -->|bulk-label| CmdLabel
CmdClose --> GatherOpts
CmdMerge --> GatherOpts
CmdLabel --> GatherOpts
GatherOpts --> ListItems
ListItems --> AnyItems
AnyItems -->|No| End
AnyItems -->|Yes| ShowPreview
ShowPreview --> DryRun
DryRun -->|Yes| End
DryRun -->|No| Confirm
Confirm -->|No| End
Confirm -->|Yes and bulk-close-issues| ApplyClose
Confirm -->|Yes and bulk-merge-prs| ApplyMerge
Confirm -->|Yes and bulk-label| ApplyLabel
ApplyClose --> End
ApplyMerge --> End
ApplyLabel --> End
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
📝 WalkthroughWalkthroughRemoved the terminal-ui-design plugin and its docs; added GitHub PR automation workflow, scripts, and docs for auto-labeling/assigning/welcome; introduced commit PR templates and template-driven PR creation docs; added GitHub batch operation commands, examples, and plugin version/marketplace metadata updates. Changes
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub
participant WF as Workflow Runner
participant API as GitHub API
participant Script as pr-automation.sh
participant PR as Pull Request
GH->>WF: PR opened/reopened event
WF->>Script: Run automation (passes PR number)
Script->>API: gh pr diff --name-only (fetch changed files)
API-->>Script: File list
Script->>Script: Map files -> labels & reviewers rules
Script->>API: Apply labels to PR
Script->>API: Assign reviewers to PR
Script->>API: Query author PR count
alt First-time contributor (PR count = 1)
Script->>API: Add first-time-contributor label
Script->>API: Post welcome comment
end
Script-->>WF: Exit status
WF-->>GH: Workflow completed (labels/reviewers/comments applied)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the GitHub and commit plugins by introducing powerful batch operations and flexible PR templating, alongside a new GitHub Actions workflow for PR automation. These changes aim to streamline development workflows, improve efficiency in managing GitHub resources, and provide a more robust and user-friendly experience for contributors. The plugin ecosystem has also been refined through the consolidation of the Highlights
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
commit/commands/and-create-pr.md, the "Default branch" context line now has an unmatched backtick (the closing backtick after the command is missing), which will break the markdown formatting for that section. - The
github/examples/pr-automation.shscript attempts to detect breaking changes by greppingFILESfor"BREAKING CHANGE", butFILESonly contains file paths fromgh pr diff, so this check will never succeed; consider inspecting commit messages instead (e.g., viagh apiorgh pr view --json commits). - Label names related to breaking changes are inconsistent across the repo (
type:breakingin the workflow,breakingin the example script, and textual references elsewhere); aligning on a single canonical label name will avoid confusion for users and automation.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `commit/commands/and-create-pr.md`, the "Default branch" context line now has an unmatched backtick (the closing backtick after the command is missing), which will break the markdown formatting for that section.
- The `github/examples/pr-automation.sh` script attempts to detect breaking changes by grepping `FILES` for `"BREAKING CHANGE"`, but `FILES` only contains file paths from `gh pr diff`, so this check will never succeed; consider inspecting commit messages instead (e.g., via `gh api` or `gh pr view --json commits`).
- Label names related to breaking changes are inconsistent across the repo (`type:breaking` in the workflow, `breaking` in the example script, and textual references elsewhere); aligning on a single canonical label name will avoid confusion for users and automation.
## Individual Comments
### Comment 1
<location path=".github/workflows/pr-automation.yml" line_range="101-103" />
<code_context>
+ AUTHOR=${{ github.event.pull_request.user.login }}
+
+ # Check if this is the author's first PR
+ PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 1 --json number --jq 'length')
+
+ if [ "$PR_COUNT" -eq 1 ]; then
+ gh pr edit "$PR_NUMBER" --add-label "first-time-contributor"
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The first-time contributor detection will evaluate to true for any author with at least one PR in this repo, not just their first.
With `--limit 1`, `jq 'length'` will only ever return `0` or `1`, so any author with at least one prior PR will still produce `PR_COUNT=1` and trigger the welcome logic on every PR. To detect a true first PR, you’ll need to count all PRs for the author (e.g., drop `--limit` or use an API that exposes `totalCount`) and only treat it as first-time when the count is exactly 1. Another option is to query closed/merged PRs and gate on those instead.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 1 --json number --jq 'length') | ||
|
|
||
| if [ "$PR_COUNT" -eq 1 ]; then |
There was a problem hiding this comment.
issue (bug_risk): The first-time contributor detection will evaluate to true for any author with at least one PR in this repo, not just their first.
With --limit 1, jq 'length' will only ever return 0 or 1, so any author with at least one prior PR will still produce PR_COUNT=1 and trigger the welcome logic on every PR. To detect a true first PR, you’ll need to count all PRs for the author (e.g., drop --limit or use an API that exposes totalCount) and only treat it as first-time when the count is exactly 1. Another option is to query closed/merged PRs and gate on those instead.
There was a problem hiding this comment.
Code Review
This pull request introduces significant enhancements, including batch operations for the GitHub plugin and pull request templates for the commit plugin, while also removing the terminal-ui-design plugin. However, a critical security vulnerability was identified in the bulk-merge-prs.sh example script, where a maliciously crafted PR title containing a newline could lead to unauthorized merging of other pull requests. Additionally, the review highlights areas for improving script robustness, clarifying documentation, and correcting examples, including a logic bug in the PR template selection and platform-specific commands in the documentation that could cause confusion.
| PRS=$(gh pr list --search "review:approved status:success" --limit 50 --json number,title --jq '.[] | "\(.number)|\(.title)"') | ||
|
|
||
| if [ -z "$PRS" ]; then | ||
| echo "No approved PRs with passing CI found" | ||
| exit 0 | ||
| fi | ||
|
|
||
| PR_COUNT=$(echo "$PRS" | wc -l) | ||
| echo "Found $PR_COUNT PRs:" | ||
| echo "$PRS" | ||
|
|
||
| if [ "$1" = "--dry-run" ]; then | ||
| echo "DRY RUN - Would merge the PRs listed above" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Confirm | ||
| read -p "Merge $PR_COUNT PRs with squash? (y/N) " -n 1 -r | ||
| echo | ||
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| echo "Aborted" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Merge each PR | ||
| echo "$PRS" | while IFS='|' read -r number title; do | ||
| echo "Merging PR #$number: $title" | ||
| gh pr merge "$number" --squash --delete-branch | ||
| done |
There was a problem hiding this comment.
The script is vulnerable to a newline injection attack. The output of gh pr list is parsed using a while read loop with | as a delimiter. Since PR titles can contain newlines, an attacker can craft a PR title that introduces a new line into the output. This new line will be processed as a separate PR by the loop, allowing the attacker to specify an arbitrary PR number to be merged. If the user approves the attacker's PR, the script will also merge the injected PR number, which might not have been approved.
PRS=$(gh pr list --search "review:approved status:success" --limit 50 --json number --jq '.[].number')
if [ -z "$PRS" ]; then
echo "No approved PRs with passing CI found"
exit 0
fi
PR_COUNT=$(echo "$PRS" | wc -l)
echo "Found $PR_COUNT PRs:"
echo "$PRS"
if [ "$1" = "--dry-run" ]; then
echo "DRY RUN - Would merge the PRs listed above"
exit 0
fi
# Confirm
read -p "Merge $PR_COUNT PRs with squash? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted"
exit 1
fi
# Merge each PR
for number in $PRS; do
echo "Merging PR #$number"
gh pr merge "$number" --squash --delete-branch
done| if PR_BODY=$(cat "$TEMPLATE" 2>/dev/null); then | ||
| # Replace placeholders with actual values | ||
| PR_BODY="${PR_BODY//\{\{ brief description of what this PR does \}\}/Brief description based on commit}" | ||
| else | ||
| # Fallback to simple body with proper newlines | ||
| PR_BODY=$'## Summary\n'"${COMMIT_MSG#*:}"$'\n\n## Changes\n- Key changes here' | ||
| fi |
There was a problem hiding this comment.
The logic for populating the PR body from a template only replaces the placeholder {{ brief description of what this PR does }}, which is specific to default.md. The other templates (bugfix.md, feature.md) use different placeholders (e.g., {{ issue description }}, {{ feature description }}) that will not be replaced. This will result in PRs created from these templates containing unfilled placeholders. Consider implementing a more robust replacement mechanism that can handle the different placeholders in each template.
| if echo "$FILES" | grep -q "BREAKING CHANGE"; then | ||
| gh pr edit "$pr_number" --add-label "breaking" | ||
| fi |
There was a problem hiding this comment.
The check for "BREAKING CHANGE" incorrectly searches within the list of changed file paths ($FILES) instead of the commit messages where this information is conventionally located. This will likely cause the check to always fail. You should inspect the PR's commit messages to correctly identify breaking changes.
| if echo "$FILES" | grep -q "BREAKING CHANGE"; then | |
| gh pr edit "$pr_number" --add-label "breaking" | |
| fi | |
| if gh pr view "$pr_number" --json commits --jq '.commits[].messageBody' | grep -q "BREAKING CHANGE"; then | |
| gh pr edit "$pr_number" --add-label "breaking" | |
| fi |
| - Current Git diff (staged and unstaged changes): !`git diff HEAD` | ||
| - Current branch: !`git branch --show-current` | ||
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5` | ||
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5' |
There was a problem hiding this comment.
There appears to be a typo in this command. The trailing single quote ' will cause a syntax error. It should be removed for the command to execute correctly.
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5' | |
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5` |
| ### Repository Cleanup | ||
| ```bash | ||
| # Close stale draft PRs | ||
| gh pr list --search "draft:yes updated:<30 days ago" --json number --jq '.[].number' | \ |
There was a problem hiding this comment.
The date format updated:<30 days ago in the search query is not a valid format for the GitHub CLI, which expects dates in YYYY-MM-DD format. This example will fail as written. It should be updated to use a dynamic, correctly formatted date. For example, on macOS/BSD, you could use updated:<$(date -v-30d +%Y-%m-%d). On Linux, the equivalent is updated:<$(date --date='30 days ago' +%Y-%m-%d).
| gh pr list --search "draft:yes updated:<30 days ago" --json number --jq '.[].number' | \ | |
| gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \ |
| /github:bulk-close-issues --label "duplicate" --comment "Closing as duplicate of #123" | ||
|
|
||
| # Close issues older than 90 days | ||
| /github:bulk-close-issues --search "updated:<2025-12-01" |
There was a problem hiding this comment.
The example for closing issues by date uses a hardcoded future date (2025-12-01). This makes the example not immediately runnable and it will eventually become outdated. Please consider using a placeholder like YYYY-MM-DD or demonstrating how to generate a dynamic date to make the documentation more helpful and timeless.
| /github:bulk-close-issues --search "updated:<2025-12-01" | |
| /github:bulk-close-issues --search "updated:<YYYY-MM-DD" |
| /github:bulk-label --add "priority:urgent" --add "needs-review" --label "bug" | ||
|
|
||
| # Preview changes | ||
| /github:bulk-label --dry-run --add "quarter-1" --search "created:>=2025-01-01" |
There was a problem hiding this comment.
This example uses a hardcoded future date (2025-01-01), which is not ideal for documentation. To improve clarity and usability, please consider replacing it with a placeholder like YYYY-MM-DD or an example of how to generate a dynamic date.
| /github:bulk-label --dry-run --add "quarter-1" --search "created:>=2025-01-01" | |
| /github:bulk-label --dry-run --add "quarter-1" --search "created:>=YYYY-MM-DD" |
| LABEL="${1:-stale}" | ||
| DRY_RUN="${2:-}" |
There was a problem hiding this comment.
The argument parsing in this script is fragile. If a user runs ./bulk-close-issues.sh --dry-run, the script will incorrectly assign LABEL="--dry-run" and DRY_RUN="", leading to unexpected behavior. Consider using a more robust argument parsing method, such as a while loop with getopts or a case statement, to handle flags and positional arguments correctly.
| ### Repository Cleanup | ||
| ```bash | ||
| # Close all stale draft PRs older than 30 days | ||
| gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \ |
There was a problem hiding this comment.
The date -v-30d command is specific to macOS/BSD systems. On Linux systems, which are common in CI/CD environments, the equivalent command is date --date='30 days ago'. For better portability and to avoid confusion, please consider adding a note about this platform difference or providing both versions of the command in the documentation.
- Add /github:watch-and-fix command that watches PR, fixes issues from AI reviews, and auto-merges when ready - Add options: --auto-merge, --max-iterations, --dry-run, --pr - Add watch-and-fix.sh example script with full implementation - Update github plugin to v1.3.0 - Update documentation with watch-and-fix usage examples Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 18
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/pr-automation.md:
- Around line 93-95: The example in the PR automation doc is incorrect: for a PR
changing "src/api/users.ts" it should not apply "area:backend" unless backend
paths are changed; update the example under the diff block that currently shows
"Labels applied: `area:api`, `area:backend`" so it only shows the correct
label(s) (e.g., remove `area:backend` and leave `area:api`) or adjust the
example text to state that `area:backend` is only added when backend paths are
also modified; edit the snippet that references "src/api/users.ts" to reflect
this corrected labeling behavior.
In @.github/workflows/pr-automation.yml:
- Line 5: The workflow currently triggers only on pull_request types
["opened","reopened"]; add "synchronize" to the pull_request event types so the
job also runs on new commits to existing PRs (update the pull_request.types
array to include "synchronize") to ensure labels/reviewer assignment and other
automation update after pushes.
- Around line 101-104: The PR-count check is wrong: change the gh pr list
invocation used to set PR_COUNT (currently using --limit 1) to request up to 2
PRs so you can detect "exactly one PR" (the current one); update the command
that sets PR_COUNT (the gh pr list call referencing AUTHOR) to use --limit 2 and
keep the existing equality check on PR_COUNT == 1 before calling gh pr edit with
PR_NUMBER to add the "first-time-contributor" label.
In `@commit/commands/and-create-pr.md`:
- Around line 99-100: The current PR_BODY replacement only substitutes a single
placeholder token and leaves other {{ ... }} tokens intact; update the PR_BODY
population logic (the PR_BODY variable handling/replacement block) to iterate
over all template tokens or apply a global regex replace to substitute every
{{...}} placeholder with the appropriate value (or a sensible default) rather
than only replacing the single literal string; ensure the replacement step runs
after all placeholder values are computed and verify no leftover {{...}} tokens
remain in PR_BODY before using it.
- Line 22: The inline shell command on the "Default branch" line is missing its
closing backtick causing broken interpolation; update the inline command so the
backticks properly wrap the shell invocation (the text starting with !`git
remote show origin | grep 'HEAD branch' | cut -d' ' -f5`) by replacing the
trailing single quote with a closing backtick so the line becomes !`...` and
renders correctly.
- Around line 90-95: The current extraction sets COMMIT_TYPE to the full token
before the colon (e.g., "feat(auth)"), so the case on "fix" and "feat" never
matches; change the extraction so COMMIT_TYPE is the bare type without scope (or
adapt the case to accept scoped forms). Specifically, after
COMMIT_TYPE="${COMMIT_MSG%%:*}", strip any scope suffix (e.g., remove "(...)"
using parameter expansion on COMMIT_TYPE) so it becomes "feat" or "fix", then
keep the existing case that references TEMPLATE_DIR/TPL_FEATURE,
TEMPLATE_DIR/TPL_BUGFIX and TEMPLATE_DIR/TPL_DEFAULT to select the template.
In `@github/commands/bulk-label.md`:
- Line 38: Replace the unsupported `file:` search qualifier in the example
invocation of the /github:bulk-label command; locate the example string
`/github:bulk-label --add "area:backend" --type pr --search "file:src/api/*"`
and either remove the `--search` argument or swap `"file:src/api/*"` for a
supported PR search qualifier such as `"base:main"`, `"label:backend"`,
`"author:USERNAME"`, or `"review-requested:TEAM"` so the example uses valid gh
pr list search syntax.
In `@github/examples/bulk-close-issues.sh`:
- Around line 5-7: The script currently only reads positional args into LABEL
and DRY_RUN (variables LABEL="${1:-stale}" and DRY_RUN="${2:-}") which conflicts
with the documented flag-based interface; update the argument parsing to accept
the documented flags (--label, --search, --comment, --state, --dry-run) (while
preserving backward-compatible positional fallbacks), set corresponding
variables (e.g., LABEL, SEARCH, COMMENT, STATE, DRY_RUN) accordingly, and
implement a simple getopt/getopts loop to parse flags and set defaults so flag
usage in github/commands/bulk-close-issues.md works as advertised.
- Around line 36-41: The script currently iterates over $ISSUES calling gh issue
close but always prints "Closed $ISSUE_COUNT issues" even when individual closes
fail; update the loop in bulk-close-issues.sh to track failures by checking each
gh invocation's exit status (or using set -e and trap) and increment a failure
counter (e.g., FAILED_COUNT) when a close fails, optionally printing per-issue
error output; after the loop, print a summary that uses ISSUE_COUNT and
FAILED_COUNT to report successes (ISSUE_COUNT - FAILED_COUNT) and failures
(FAILED_COUNT) and exit with non-zero status if any failures occurred.
In `@github/examples/bulk-merge-prs.sh`:
- Around line 33-38: The script currently prints "Merged $PR_COUNT PRs"
regardless of individual merge failures; modify the loop that reads from PRS and
calls gh pr merge to detect when gh pr merge fails (non-zero exit status) and
increment a failure counter (e.g., MERGE_FAILS) while still attempting remaining
merges, and also increment a success counter if desired; after the loop, update
the final reporting to show successes and failures (use PR_COUNT and MERGE_FAILS
to compute succeeded = PR_COUNT - MERGE_FAILS) and return a non-zero exit code
(exit 1) if MERGE_FAILS > 0 so the script accurately reflects merge failures
rather than always reporting full success.
In `@github/examples/pr-automation.sh`:
- Around line 56-59: PR_COUNT is computed with gh pr list --limit 1 which forces
length to be 0 or 1 and breaks first-time contributor detection; update the gh
pr list invocation in the PR_COUNT assignment (the line using PR_COUNT and
--limit 1) to remove the --limit 1 (or set it to a sufficiently large number) so
the --json number --jq 'length' returns the total number of PRs by $AUTHOR, then
keep the existing if [ "$PR_COUNT" -eq 1 ] check to correctly detect first-time
contributors.
- Around line 25-28: The script currently checks the FILES variable for the
literal string "BREAKING CHANGE" and applies the "breaking" label; change this
to inspect commit messages and apply the workflow's label "type:breaking".
Replace the check that uses echo "$FILES" | grep -q "BREAKING CHANGE" with a
commit-message check (e.g., use git log --format=%B -n 1 "$pr_branch" or git
show --format=%B "$commit_sha" | grep -q "BREAKING CHANGE") and then call gh pr
edit "$pr_number" --add-label "type:breaking" instead of "breaking"; keep
references to the existing variables FILES, pr_number and the gh pr edit
invocation so it's easy to locate and update.
In `@github/README.md`:
- Around line 150-164: Two fenced code blocks in the README (the repository tree
block and the commit message list block) lack language identifiers; update the
opening fences from ``` to ```text so markdownlint rule MD040 is satisfied.
Locate the block containing "github/ ├── .claude-plugin/" (the directory tree)
and the block containing the commit lines starting with "feat(github): add new
batch command" and change their fence markers to use "text" as the language
identifier, leaving the contents unchanged.
- Around line 77-83: The script incorrectly uses the user's repo count to infer
first-time contributors; instead, determine if the author has prior PRs in THIS
repository. For each PR (variable pr), get the author via gh pr view $pr --json
author --jq '.author.login' and then count that author's prior PRs in the same
repo with gh pr list --author <author> --json number --jq 'length' (or an
equivalent gh api call filtering by repo/author), and only call gh pr edit $pr
--add-label "first-time-contributor" when that count is 1 (meaning the current
PR is their first) or 0 prior PRs; update the existing use of gh pr list/gh pr
view/gh pr edit in the loop accordingly.
In `@github/skills/github.md`:
- Around line 423-425: The gh CLI command in the docs uses an unsupported --page
2 flag; remove the --page 2 token from the second occurrence of the gh pr list
command (the line that currently reads "gh pr list --limit 100 --json
number,title --jq '.[]' --page 2") and leave the command using only supported
flags (e.g., --limit and --json); ensure the example shows "gh pr list --limit
100 --json number,title" (and the intended --jq usage) so the docs reflect valid
gh pr list usage.
- Around line 469-477: The current PR-labeling snippet uses a username regex
(test("^[a-z0-9_-]{4,}$")) which misidentifies first-time contributors; replace
that logic with a per-author PR count check by listing PRs (gh pr list --json
author) and counting PRs for each .author.login, then only call gh pr edit
--add-label "first-time-contributor" for authors whose PR count equals 1; locate
the pipeline that reads into "number" and "author" (the while IFS=' ' read -r
number author loop) and change the selection step to compute or filter by the PR
count before invoking gh pr edit so only true first-time contributors are
labeled.
- Around line 505-507: The script uses a macOS/BSD-specific date flag (`date
-v-30d`) in the command starting with `gh pr list --search "draft:yes
updated:<$(date -v-30d +%Y-%m-%d)"`; replace this with a portable solution by
detecting the date implementation and using `date -d '30 days ago'` on GNU/Linux
or `date -v-30d` on macOS (e.g., add a small helper that sets a variable like
RECENT_DATE="$(date -d '30 days ago' +%Y-%m-%d 2>/dev/null || date -v-30d
+%Y-%m-%d)" and then use `gh pr list --search "draft:yes
updated:<${RECENT_DATE}"`), so the `gh pr list` invocation works on both GNU and
BSD/macOS systems.
In `@marketplace.json`:
- Around line 81-82: The plugin "description" field is out of sync between
registries: update the other marketplace.json's "description" JSON value to
exactly match the new string "GitHub operations using gh CLI - PRs, issues,
workflows, batch operations, and smart branch detection" so both registry
manifests advertise the same capabilities; ensure you edit the "description" key
in the other manifest that still contains the previous text and leave the
version field unchanged unless an actual version bump is required.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: cf810ff1-83ea-45c2-9351-cfff746908ea
📒 Files selected for processing (25)
.claude-plugin/marketplace.json.github/ISSUE_TEMPLATE/feature_request.md.github/workflows/pr-automation.md.github/workflows/pr-automation.ymlCHANGELOG.mdREADME.mdcommit/.claude-plugin/plugin.jsoncommit/.pr-templates/bugfix.mdcommit/.pr-templates/default.mdcommit/.pr-templates/feature.mdcommit/commands/and-create-pr.mdgithub/.claude-plugin/plugin.jsongithub/README.mdgithub/commands/bulk-close-issues.mdgithub/commands/bulk-label.mdgithub/commands/bulk-merge-prs.mdgithub/examples/bulk-close-issues.shgithub/examples/bulk-merge-prs.shgithub/examples/pr-automation.shgithub/skills/github.mdmarketplace.jsonterminal-ui-design/.claude-plugin/plugin.jsonterminal-ui-design/CLAUDE.mdterminal-ui-design/README.mdterminal-ui-design/skills/terminal-ui-design/SKILL.md
💤 Files with no reviewable changes (7)
- terminal-ui-design/.claude-plugin/plugin.json
- .claude-plugin/marketplace.json
- terminal-ui-design/skills/terminal-ui-design/SKILL.md
- terminal-ui-design/README.md
- README.md
- .github/ISSUE_TEMPLATE/feature_request.md
- terminal-ui-design/CLAUDE.md
| For a PR changing `src/api/users.ts`: | ||
| - Labels applied: `area:api`, `area:backend` | ||
| - Reviewers assigned: `api-team` |
There was a problem hiding this comment.
Example output labels are inconsistent with the documented path rules.
For a PR changing src/api/users.ts, area:backend should not be listed unless backend paths are also changed.
Suggested fix
-For a PR changing `src/api/users.ts`:
-- Labels applied: `area:api`, `area:backend`
+For a PR changing `src/api/users.ts`:
+- Labels applied: `area:api`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| For a PR changing `src/api/users.ts`: | |
| - Labels applied: `area:api`, `area:backend` | |
| - Reviewers assigned: `api-team` | |
| For a PR changing `src/api/users.ts`: | |
| - Labels applied: `area:api` | |
| - Reviewers assigned: `api-team` |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/pr-automation.md around lines 93 - 95, The example in the
PR automation doc is incorrect: for a PR changing "src/api/users.ts" it should
not apply "area:backend" unless backend paths are changed; update the example
under the diff block that currently shows "Labels applied: `area:api`,
`area:backend`" so it only shows the correct label(s) (e.g., remove
`area:backend` and leave `area:api`) or adjust the example text to state that
`area:backend` is only added when backend paths are also modified; edit the
snippet that references "src/api/users.ts" to reflect this corrected labeling
behavior.
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, reopened] |
There was a problem hiding this comment.
Workflow should react to new commits on existing PRs.
Only opened and reopened are handled. Without synchronize, labels/reviewer assignment won't update after subsequent pushes.
Suggested fix
- types: [opened, reopened]
+ types: [opened, reopened, synchronize]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| types: [opened, reopened] | |
| types: [opened, reopened, synchronize] |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/pr-automation.yml at line 5, The workflow currently
triggers only on pull_request types ["opened","reopened"]; add "synchronize" to
the pull_request event types so the job also runs on new commits to existing PRs
(update the pull_request.types array to include "synchronize") to ensure
labels/reviewer assignment and other automation update after pushes.
| PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 1 --json number --jq 'length') | ||
|
|
||
| if [ "$PR_COUNT" -eq 1 ]; then | ||
| gh pr edit "$PR_NUMBER" --add-label "first-time-contributor" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/pr-automation.yml | sed -n '90,115p'Repository: duyet/claude-plugins
Length of output: 1290
🏁 Script executed:
# Verify the --limit 1 behavior and confirm the jq 'length' logic is the issue
# by checking if there are any other PR filtering mechanisms in the file
rg -n "gh pr list" .github/workflows/pr-automation.ymlRepository: duyet/claude-plugins
Length of output: 169
First-time contributor detection is logically incorrect and produces false positives.
At Line 101, using --limit 1 with jq 'length' returns at most 0 or 1. This means the condition on Line 103 triggers whenever the author has any existing PR, not just for first-time contributors. Any returning contributor opening a new PR will be incorrectly labeled.
The fix requires checking if the author has exactly one PR (the current one) by increasing the limit to 2:
Suggested fix
-PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 1 --json number --jq 'length')
+PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 2 --json number --jq 'length')
-if [ "$PR_COUNT" -eq 1 ]; then
+if [ "${{ github.event.action }}" = "opened" ] && [ "$PR_COUNT" -eq 1 ]; then📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 1 --json number --jq 'length') | |
| if [ "$PR_COUNT" -eq 1 ]; then | |
| gh pr edit "$PR_NUMBER" --add-label "first-time-contributor" | |
| PR_COUNT=$(gh pr list --author "$AUTHOR" --state all --limit 2 --json number --jq 'length') | |
| if [ "${{ github.event.action }}" = "opened" ] && [ "$PR_COUNT" -eq 1 ]; then | |
| gh pr edit "$PR_NUMBER" --add-label "first-time-contributor" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/pr-automation.yml around lines 101 - 104, The PR-count
check is wrong: change the gh pr list invocation used to set PR_COUNT (currently
using --limit 1) to request up to 2 PRs so you can detect "exactly one PR" (the
current one); update the command that sets PR_COUNT (the gh pr list call
referencing AUTHOR) to use --limit 2 and keep the existing equality check on
PR_COUNT == 1 before calling gh pr edit with PR_NUMBER to add the
"first-time-contributor" label.
| - Current Git diff (staged and unstaged changes): !`git diff HEAD` | ||
| - Current branch: !`git branch --show-current` | ||
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5` | ||
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5' |
There was a problem hiding this comment.
Fix the broken inline command delimiter on default-branch line.
Line 22 appears to miss the closing backtick for the ! command, which can break command interpolation in this command spec.
Suggested fix
-- Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5'
+- Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5' | |
| - Default branch: !`git remote show origin | grep 'HEAD branch' | cut -d' ' -f5` |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commit/commands/and-create-pr.md` at line 22, The inline shell command on the
"Default branch" line is missing its closing backtick causing broken
interpolation; update the inline command so the backticks properly wrap the
shell invocation (the text starting with !`git remote show origin | grep 'HEAD
branch' | cut -d' ' -f5`) by replacing the trailing single quote with a closing
backtick so the line becomes !`...` and renders correctly.
| COMMIT_TYPE="${COMMIT_MSG%%:*}" # Extract first word before colon | ||
| case "$COMMIT_TYPE" in | ||
| fix) TEMPLATE="${TEMPLATE_DIR}/${TPL_BUGFIX}.md" ;; | ||
| feat) TEMPLATE="${TEMPLATE_DIR}/${TPL_FEATURE}.md" ;; | ||
| *) TEMPLATE="${TEMPLATE_DIR}/${TPL_DEFAULT}.md" ;; | ||
| esac |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find the file and check if it exists
find . -name "and-create-pr.md" -o -name "and-create-pr.sh" | head -20Repository: duyet/claude-plugins
Length of output: 130
🏁 Script executed:
# List files in commit directory
ls -la commit/ 2>/dev/null || echo "commit directory not found in root"
find . -path "*/commit/*" -type f | head -20Repository: duyet/claude-plugins
Length of output: 752
🏁 Script executed:
# Search for COMMIT_TYPE extraction pattern
rg "COMMIT_TYPE.*COMMIT_MSG" --max-count 10Repository: duyet/claude-plugins
Length of output: 163
🏁 Script executed:
# Read the file to see the context around lines 90-95
wc -l commit/commands/and-create-pr.mdRepository: duyet/claude-plugins
Length of output: 100
🏁 Script executed:
# Read specific lines with context
sed -n '85,100p' commit/commands/and-create-pr.mdRepository: duyet/claude-plugins
Length of output: 682
🏁 Script executed:
# Test the extraction logic with scoped commits
cat > /tmp/test_commit.sh << 'EOF'
#!/bin/bash
# Test current extraction
COMMIT_MSG='feat(auth): add OAuth login'
COMMIT_TYPE="${COMMIT_MSG%%:*}"
echo "Input: $COMMIT_MSG"
echo "Current extraction (%%:*): $COMMIT_TYPE"
echo "Expected for case match: feat"
echo "Does 'feat' match '$COMMIT_TYPE'? $([ "$COMMIT_TYPE" = "feat" ] && echo 'NO - FAILS' || echo 'YES - WORKS')"
echo ""
# Test the suggested fix
COMMIT_PREFIX="${COMMIT_MSG%%:*}"
COMMIT_TYPE="${COMMIT_PREFIX%%(*}"
echo "Suggested fix:"
echo " COMMIT_PREFIX: $COMMIT_PREFIX"
echo " COMMIT_TYPE: $COMMIT_TYPE"
echo " Match test: $([ "$COMMIT_TYPE" = "feat" ] && echo 'YES - WORKS' || echo 'NO - FAILS')"
EOF
bash /tmp/test_commit.shRepository: duyet/claude-plugins
Length of output: 300
🏁 Script executed:
# Final validation: test actual bash case statement behavior
cat > /tmp/case_test.sh << 'EOF'
#!/bin/bash
test_case() {
local COMMIT_TYPE="$1"
echo "Testing COMMIT_TYPE='$COMMIT_TYPE':"
case "$COMMIT_TYPE" in
fix) echo " Result: BUGFIX template" ;;
feat) echo " Result: FEATURE template" ;;
*) echo " Result: DEFAULT template (BUG!)" ;;
esac
}
echo "=== CURRENT IMPLEMENTATION (BROKEN) ==="
COMMIT_MSG='feat(auth): add OAuth login'
COMMIT_TYPE="${COMMIT_MSG%%:*}"
test_case "$COMMIT_TYPE"
echo ""
echo "=== PROPOSED FIX (WORKING) ==="
COMMIT_PREFIX="${COMMIT_MSG%%:*}"
COMMIT_TYPE="${COMMIT_PREFIX%%(*}"
test_case "$COMMIT_TYPE"
echo ""
echo "=== TEST WITH fix SCOPE ==="
COMMIT_MSG='fix(bugfix): resolve issue'
COMMIT_PREFIX="${COMMIT_MSG%%:*}"
COMMIT_TYPE="${COMMIT_PREFIX%%(*}"
test_case "$COMMIT_TYPE"
EOF
bash /tmp/case_test.shRepository: duyet/claude-plugins
Length of output: 340
Template selection fails for all scoped conventional commits.
Line 90 extracts feat(auth) from feat(auth): ..., so the case statement at lines 91-95 won't match feat or fix and always falls back to default template. Since the project mandates scoped commits (feat(plugin), fix(plugin), docs(plugin)), this breaks template selection for all commits.
Suggested fix
-COMMIT_TYPE="${COMMIT_MSG%%:*}" # Extract first word before colon
+COMMIT_PREFIX="${COMMIT_MSG%%:*}" # e.g. feat(auth)
+COMMIT_TYPE="${COMMIT_PREFIX%%(*}" # e.g. feat
case "$COMMIT_TYPE" in
fix) TEMPLATE="${TEMPLATE_DIR}/${TPL_BUGFIX}.md" ;;
feat) TEMPLATE="${TEMPLATE_DIR}/${TPL_FEATURE}.md" ;;
*) TEMPLATE="${TEMPLATE_DIR}/${TPL_DEFAULT}.md" ;;
esac📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| COMMIT_TYPE="${COMMIT_MSG%%:*}" # Extract first word before colon | |
| case "$COMMIT_TYPE" in | |
| fix) TEMPLATE="${TEMPLATE_DIR}/${TPL_BUGFIX}.md" ;; | |
| feat) TEMPLATE="${TEMPLATE_DIR}/${TPL_FEATURE}.md" ;; | |
| *) TEMPLATE="${TEMPLATE_DIR}/${TPL_DEFAULT}.md" ;; | |
| esac | |
| COMMIT_PREFIX="${COMMIT_MSG%%:*}" # e.g. feat(auth) | |
| COMMIT_TYPE="${COMMIT_PREFIX%%(*}" # e.g. feat | |
| case "$COMMIT_TYPE" in | |
| fix) TEMPLATE="${TEMPLATE_DIR}/${TPL_BUGFIX}.md" ;; | |
| feat) TEMPLATE="${TEMPLATE_DIR}/${TPL_FEATURE}.md" ;; | |
| *) TEMPLATE="${TEMPLATE_DIR}/${TPL_DEFAULT}.md" ;; | |
| esac |
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 95-95: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@commit/commands/and-create-pr.md` around lines 90 - 95, The current
extraction sets COMMIT_TYPE to the full token before the colon (e.g.,
"feat(auth)"), so the case on "fix" and "feat" never matches; change the
extraction so COMMIT_TYPE is the bare type without scope (or adapt the case to
accept scoped forms). Specifically, after COMMIT_TYPE="${COMMIT_MSG%%:*}", strip
any scope suffix (e.g., remove "(...)" using parameter expansion on COMMIT_TYPE)
so it becomes "feat" or "fix", then keep the existing case that references
TEMPLATE_DIR/TPL_FEATURE, TEMPLATE_DIR/TPL_BUGFIX and TEMPLATE_DIR/TPL_DEFAULT
to select the template.
| ``` | ||
| github/ | ||
| ├── .claude-plugin/ | ||
| │ └── plugin.json # Manifest (version 1.2.0) | ||
| ├── commands/ # Slash commands | ||
| │ ├── bulk-close-issues.md | ||
| │ ├── bulk-merge-prs.md | ||
| │ └── bulk-label.md | ||
| ├── skills/ # Reusable knowledge | ||
| │ └── github.md | ||
| └── examples/ # Example scripts | ||
| ├── bulk-close-issues.sh | ||
| ├── bulk-merge-prs.sh | ||
| └── pr-automation.sh | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to fenced code blocks (MD040).
Two fenced blocks are missing language tags, which is currently flagged by markdownlint.
Suggested fix
-```
+```text
github/
├── .claude-plugin/
│ └── plugin.json # Manifest (version 1.2.0)
@@
-```
+```
-```
+```text
feat(github): add new batch command
fix(github): fix issue listing pagination
docs(github): update examples
-```
+```Also applies to: 188-192
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 150-150: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/README.md` around lines 150 - 164, Two fenced code blocks in the
README (the repository tree block and the commit message list block) lack
language identifiers; update the opening fences from ``` to ```text so
markdownlint rule MD040 is satisfied. Locate the block containing "github/ ├──
.claude-plugin/" (the directory tree) and the block containing the commit lines
starting with "feat(github): add new batch command" and change their fence
markers to use "text" as the language identifier, leaving the contents
unchanged.
| gh pr list --limit 100 --json number,title | jq '.[]' | ||
| gh pr list --limit 100 --json number,title --jq '.[]' --page 2 | ||
| ``` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find and read the file around lines 423-425
if [ -f "github/skills/github.md" ]; then
sed -n '420,430p' github/skills/github.md
else
echo "File not found, searching for it..."
find . -name "github.md" -path "*/github/skills/*" 2>/dev/null | head -5
fiRepository: duyet/claude-plugins
Length of output: 255
🌐 Web query:
GitHub CLI gh pr list --page flag pagination options
💡 Result:
gh pr list does not support a --page flag. The built-in pagination control is --limit (default 30), which tells gh how many PRs to fetch; gh will page internally as needed until it reaches that limit. [1]
What to use instead
- Fetch more PRs in one go:
gh pr list --limit 100(or any higher number you need) [1]
- If you truly need manual page/offset-style pagination, switch to the API:
gh api --paginate ...(REST auto-pagination) [2]- For GraphQL, you must implement cursor pagination (
pageInfo { hasNextPage endCursor }) and loop with--paginate. [2]
Docs
gh pr listoptions (shows--limitand no--page): [1]
Sources
[1] GitHub CLI manual: gh pr list — https://cli.github.com/manual/gh_pr_list
[2] GitHub CLI discussion on gh api --paginate — cli/cli#3257
🏁 Script executed:
# Read the actual file around the lines in question
sed -n '420,430p' "github/skills/github.md" | cat -nRepository: duyet/claude-plugins
Length of output: 332
🏁 Script executed:
# The line numbers don't match. Let me search for the file content containing the pr list commands
rg "gh pr list.*--limit 100.*--json number,title" "github/skills/github.md" -A 1 -B 1 -nRepository: duyet/claude-plugins
Length of output: 241
🏁 Script executed:
# Also search more broadly for the specific commands mentioned
rg "gh pr list" "github/skills/github.md" -nRepository: duyet/claude-plugins
Length of output: 959
Remove --page 2 flag from the gh pr list command — it is not supported.
Line 447 uses --page 2 which is invalid for gh pr list. The command lacks pagination support for fetching "pages" of results; --limit sets the total number of results fetched, not pages.
Suggested fix
-gh pr list --limit 100 --json number,title --jq '.[]' --page 2
+gh api --paginate "repos/{owner}/{repo}/pulls" --jq '.[] | {number, title}'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/skills/github.md` around lines 423 - 425, The gh CLI command in the
docs uses an unsupported --page 2 flag; remove the --page 2 token from the
second occurrence of the gh pr list command (the line that currently reads "gh
pr list --limit 100 --json number,title --jq '.[]' --page 2") and leave the
command using only supported flags (e.g., --limit and --json); ensure the
example shows "gh pr list --limit 100 --json number,title" (and the intended
--jq usage) so the docs reflect valid gh pr list usage.
| ```bash | ||
| # Label all PRs from first-time contributors (efficient batch approach) | ||
| gh pr list --author . --json number,author --jq '.[] | | ||
| select(.author.login | test("^[a-z0-9_-]{4,}$")) | | ||
| "\(.number) \(.author.login)"' | \ | ||
| while IFS=' ' read -r number author; do | ||
| # Quick check for first-timers (avoid API call for known contributors) | ||
| gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true | ||
| done |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd github/skills && wc -l github.mdRepository: duyet/claude-plugins
Length of output: 77
🏁 Script executed:
cd github/skills && sed -n '469,477p' github.mdRepository: duyet/claude-plugins
Length of output: 243
🏁 Script executed:
cd github/skills && sed -n '460,485p' github.mdRepository: duyet/claude-plugins
Length of output: 605
🏁 Script executed:
cd github/skills && grep -n "first-time-contributor\|first-time contributor" github.mdRepository: duyet/claude-plugins
Length of output: 322
🏁 Script executed:
cd github/skills && grep -n "gh pr list.*author.*json" github.mdRepository: duyet/claude-plugins
Length of output: 122
🏁 Script executed:
cd github/skills && grep -n "select.*author\.login.*test" github.mdRepository: duyet/claude-plugins
Length of output: 120
🏁 Script executed:
cd github/skills && sed -n '493,505p' github.mdRepository: duyet/claude-plugins
Length of output: 699
Incorrect line numbers; the issue is confirmed as valid.
The actual code is at lines 493-505, not 469-477. Your analysis is correct: the username pattern check (^[a-z0-9_-]{4,}$) is unrelated to contribution history and will incorrectly label many contributors as first-time contributors regardless of their actual PR count. The suggested fix properly detects first-time contributors by counting PRs from each author and labeling only those with exactly one PR.
Suggested fix
-gh pr list --author . --json number,author --jq '.[] |
- select(.author.login | test("^[a-z0-9_-]{4,}$")) |
- "\(.number) \(.author.login)"' | \
- while IFS=' ' read -r number author; do
- # Quick check for first-timers (avoid API call for known contributors)
- gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true
- done
+gh pr list --json number,author --jq '.[] | "\(.number) \(.author.login)"' | \
+ while IFS=' ' read -r number author; do
+ pr_count=$(gh pr list --author "$author" --state all --limit 2 --json number --jq 'length')
+ if [ "$pr_count" -eq 1 ]; then
+ gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true
+ fi
+ done📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```bash | |
| # Label all PRs from first-time contributors (efficient batch approach) | |
| gh pr list --author . --json number,author --jq '.[] | | |
| select(.author.login | test("^[a-z0-9_-]{4,}$")) | | |
| "\(.number) \(.author.login)"' | \ | |
| while IFS=' ' read -r number author; do | |
| # Quick check for first-timers (avoid API call for known contributors) | |
| gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true | |
| done |
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 469-469: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/skills/github.md` around lines 469 - 477, The current PR-labeling
snippet uses a username regex (test("^[a-z0-9_-]{4,}$")) which misidentifies
first-time contributors; replace that logic with a per-author PR count check by
listing PRs (gh pr list --json author) and counting PRs for each .author.login,
then only call gh pr edit --add-label "first-time-contributor" for authors whose
PR count equals 1; locate the pipeline that reads into "number" and "author"
(the while IFS=' ' read -r number author loop) and change the selection step to
compute or filter by the PR count before invoking gh pr edit so only true
first-time contributors are labeled.
| # Close all stale draft PRs older than 30 days | ||
| gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \ | ||
| while read pr; do |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find and examine the github.md file
find . -name "github.md" -type f | head -20Repository: duyet/claude-plugins
Length of output: 89
🏁 Script executed:
# Check if the file exists and read the relevant lines
if [ -f "github/skills/github.md" ]; then
echo "=== File found. Reading lines 500-510 ==="
sed -n '500,510p' "github/skills/github.md" | cat -n
else
echo "File not found at github/skills/github.md"
fiRepository: duyet/claude-plugins
Length of output: 490
🏁 Script executed:
# Search for the specific code pattern in the github.md file
grep -n "draft:yes" "github/skills/github.md" | cat -nRepository: duyet/claude-plugins
Length of output: 176
🏁 Script executed:
# Also search for "date -v-30d" to find the exact location
grep -n "date -v-30d" "github/skills/github.md" | cat -nRepository: duyet/claude-plugins
Length of output: 176
🏁 Script executed:
# Read the context around line 529
sed -n '525,535p' "github/skills/github.md" | cat -nRepository: duyet/claude-plugins
Length of output: 510
🌐 Web query:
date command -v flag BSD GNU Linux portability differences
💡 Result:
Key portability point
date -v ... is not POSIX, and it’s not supported by GNU date. On GNU/Linux (coreutils), relative/parsed dates are done with -d/--date, not -v. [1]
BSD/macOS/FreeBSD: -v = adjust components relative/absolute
On FreeBSD (and typically macOS’s BSD date), -v[+|-]val[y|m|w|d|H|M|S] adjusts the current (or specified) date by years/months/weeks/days/hours/minutes/seconds, and you can repeat -v multiple times (processed in order). Examples: -v+1d, -v-2H, -v1m (set month), etc. [2]
GNU/Linux (coreutils): use -d/--date instead
GNU date uses --date=STRING / -d STRING to parse expressions like "next friday", "yesterday", "2026-03-04 10:00", etc. [1]
Not all BSDs have -v
OpenBSD’s date(1) does not include -v (it has options like -f, -j, -r, -z, etc.), so even “BSD portability” is not guaranteed. [3]
Practical portable pattern
- If you control the platform:
- BSD/macOS/FreeBSD:
date -v+1d ...[2] - GNU/Linux:
date -d 'now + 1 day' ...[1]
- BSD/macOS/FreeBSD:
- If you need one script across systems: detect GNU vs BSD (
date --versionworks on GNU) and branch, or use a language runtime (Python/Perl) for date arithmetic.
Sources: GNU coreutils date options [1]; FreeBSD date(1) including -v [2]; OpenBSD date(1) (no -v) [3].
Correct line numbers: lines 529-530 (not 505-507). The portability concern is valid.
date -v-30d is BSD/macOS-specific and unsupported by GNU date on Linux systems. The -v flag does not exist in GNU coreutils; use -d for relative date expressions instead.
Suggested fix
-gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \
+cutoff=$(date -u -d '30 days ago' +%Y-%m-%d 2>/dev/null || date -u -v-30d +%Y-%m-%d)
+gh pr list --search "draft:yes updated:<$cutoff" --json number --jq '.[].number' | \📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Close all stale draft PRs older than 30 days | |
| gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \ | |
| while read pr; do | |
| # Close all stale draft PRs older than 30 days | |
| cutoff=$(date -u -d '30 days ago' +%Y-%m-%d 2>/dev/null || date -u -v-30d +%Y-%m-%d) | |
| gh pr list --search "draft:yes updated:<$cutoff" --json number --jq '.[].number' | \ | |
| while read pr; do |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/skills/github.md` around lines 505 - 507, The script uses a
macOS/BSD-specific date flag (`date -v-30d`) in the command starting with `gh pr
list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)"`; replace this with
a portable solution by detecting the date implementation and using `date -d '30
days ago'` on GNU/Linux or `date -v-30d` on macOS (e.g., add a small helper that
sets a variable like RECENT_DATE="$(date -d '30 days ago' +%Y-%m-%d 2>/dev/null
|| date -v-30d +%Y-%m-%d)" and then use `gh pr list --search "draft:yes
updated:<${RECENT_DATE}"`), so the `gh pr list` invocation works on both GNU and
BSD/macOS systems.
| "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, and smart branch detection", | ||
| "version": "1.2.0", |
There was a problem hiding this comment.
Synchronize GitHub plugin description across both marketplace registries.
Line 81 now advertises batch operations, but .claude-plugin/marketplace.json:48-51 still has the previous description. This can cause inconsistent plugin metadata depending on which registry is read.
Suggested alignment
--- a/.claude-plugin/marketplace.json
+++ b/.claude-plugin/marketplace.json
@@
- "description": "GitHub operations using gh CLI - PRs, workflows, issues, repositories, and smart branch detection for implementation workflows"
+ "description": "GitHub operations using gh CLI - PRs, issues, workflows, batch operations, and smart branch detection"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@marketplace.json` around lines 81 - 82, The plugin "description" field is out
of sync between registries: update the other marketplace.json's "description"
JSON value to exactly match the new string "GitHub operations using gh CLI -
PRs, issues, workflows, batch operations, and smart branch detection" so both
registry manifests advertise the same capabilities; ensure you edit the
"description" key in the other manifest that still contains the previous text
and leave the version field unchanged unless an actual version bump is required.
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (6)
marketplace.json (1)
81-82:⚠️ Potential issue | 🟡 MinorKeep GitHub plugin description synchronized across manifests.
marketplace.jsonandgithub/.claude-plugin/plugin.jsondescribe different capability sets for the same plugin version, which can produce inconsistent catalog metadata.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@marketplace.json` around lines 81 - 82, The marketplace.json "description" for version "1.3.0" is out of sync with github/.claude-plugin/plugin.json; update the plugin metadata so both manifests share the same capability description for the same "version" (e.g., align the "description" field in marketplace.json with the "description" in github/.claude-plugin/plugin.json or vice versa), or centralize the source of truth and propagate it to both files so catalog metadata remains consistent.github/skills/github.md (3)
446-448:⚠️ Potential issue | 🟠 MajorRemove unsupported
--pageusage fromgh pr listexamples.
gh pr listexamples currently include--page, which is not a valid flag for this command. This makes both the gotcha snippet and final note incorrect.Suggested doc fix
-gh pr list --limit 100 --json number,title --jq '.[]' --page 2 +gh pr list --limit 100 --json number,title --jq '.[]' -- Large operations may require pagination with `--limit` and `--page` +- Large operations may require higher `--limit`, or `gh api --paginate` for explicit paginationAlso applies to: 564-565
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@github/skills/github.md` around lines 446 - 448, The examples use an unsupported --page flag with the gh pr list command and also show a mistaken mixed usage of --json and --jq; remove the unsupported --page 2 token from the example(s) and update the surrounding gotcha/final note to no longer reference --page, leaving the valid invocation(s) such as gh pr list --limit 100 --json number,title (and gh pr list --limit 100 --json number,title --jq '.[]' if you intend to demonstrate jq-style filtering), and make the same removal/update for the duplicate occurrence that appears later in the file; ensure references to --page are deleted and examples show only supported flags for gh pr list.
493-500:⚠️ Potential issue | 🟠 MajorFirst-time contributor labeling logic is incorrect.
The regex-based username check does not represent contribution history and can mislabel contributors.
Suggested doc fix
-gh pr list --author . --json number,author --jq '.[] | - select(.author.login | test("^[a-z0-9_-]{4,}$")) | - "\(.number) \(.author.login)"' | \ +gh pr list --json number,author --jq '.[] | "\(.number) \(.author.login)"' | \ while IFS=' ' read -r number author; do - # Quick check for first-timers (avoid API call for known contributors) - gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true + pr_count=$(gh pr list --author "$author" --state all --limit 2 --json number --jq 'length') + if [ "$pr_count" -eq 1 ]; then + gh pr edit "$number" --add-label "first-time-contributor" 2>/dev/null || true + fi done🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@github/skills/github.md` around lines 493 - 500, The current approach uses a regex on the username in the gh pr list pipeline (the select(.author.login | test("^[a-z0-9_-]{4,}$")) step and subsequent while loop/gh pr edit) which misclassifies contributors; replace the regex check with a real contribution-history check by calling the GitHub API for each PR author (e.g., via gh api) to verify whether they have previous contributions/merged PRs or prior activity in the repo before adding the "first-time-contributor" label, and update the pipeline so gh pr edit is invoked only when the API response confirms zero prior contributions for that author.
529-530:⚠️ Potential issue | 🟠 MajorUse portable date arithmetic in shell examples.
date -v-30dis BSD/macOS-specific and fails on GNU/Linux.Suggested doc fix
-gh pr list --search "draft:yes updated:<$(date -v-30d +%Y-%m-%d)" --json number --jq '.[].number' | \ +cutoff=$(date -u -d '30 days ago' +%Y-%m-%d 2>/dev/null || date -u -v-30d +%Y-%m-%d) +gh pr list --search "draft:yes updated:<$cutoff" --json number --jq '.[].number' | \🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@github/skills/github.md` around lines 529 - 530, The example uses BSD-only date arithmetic ("date -v-30d") in the gh pr list command, which breaks on GNU/Linux; replace the inline date substitution used in the gh pr list example with a portable approach such as computing a 30-day-ago value with a fallback that supports both BSD and GNU (e.g., set a DATE_30_DAYS_AGO variable using date -v-30d ... 2>/dev/null || date -d '30 days ago' ... and then use that variable in the gh pr list --search string), and update the snippet referencing the substitution used with gh pr list to use that variable instead (refer to the gh pr list --search "draft:yes updated:<$(...)" usage in the diff).github/README.md (2)
170-186:⚠️ Potential issue | 🟡 MinorAdd language identifiers to fenced code blocks.
The repository tree and commit-convention fenced blocks are missing language tags.
Suggested fix
-``` +```text github/ @@ -``` +``` -``` +```text feat(github): add new batch command fix(github): fix issue listing pagination docs(github): update examples -``` +```Also applies to: 210-214
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@github/README.md` around lines 170 - 186, The README has fenced code blocks that lack language identifiers: update the repository tree block and the commit-convention example blocks in the README to use ```text (i.e., change the opening ``` to ```text for those blocks) so the tree and commit examples are rendered as plain text; leave the closing ``` unchanged and ensure all similar examples (the repository tree block and the commit message examples) receive the same change.
87-93:⚠️ Potential issue | 🟠 MajorFirst-time contributor detection is based on the wrong signal.
Using
users/{login}/reposcount does not determine whether a PR is a first contribution to this repository.Suggested fix
-for pr in $(gh pr list --author . --json number --jq '.[].number'); do - count=$(gh api users/$(gh pr view $pr --json author --jq '.author.login')/repos --jq 'length' 2>/dev/null || echo 0) - if [ "$count" -lt 5 ]; then - gh pr edit $pr --add-label "first-time-contributor" - fi +for pr in $(gh pr list --json number --jq '.[].number'); do + author=$(gh pr view "$pr" --json author --jq '.author.login') + pr_count=$(gh pr list --author "$author" --state all --limit 2 --json number --jq 'length') + if [ "$pr_count" -eq 1 ]; then + gh pr edit "$pr" --add-label "first-time-contributor" + fi done🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@github/README.md` around lines 87 - 93, The current script uses users/$(login)/repos to count a user's total repos, which doesn't indicate whether this is their first contribution to this repository; replace that check with a repository-scoped PR count: after extracting the author via gh pr view $pr --json author --jq '.author.login', call gh pr list --author "$author" --repo "$(gh repo view --json nameWithOwner --jq '.nameWithOwner')" --state all --json number --jq 'length' and treat the author as a first-time contributor only if that count is 1 (meaning only the current PR exists); update the script logic around the variables pr and count and the gh pr edit invocation accordingly so labeling is based on prior PRs in this repo rather than total user repos.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@github/commands/watch-and-fix.md`:
- Around line 39-41: The documentation in github/commands/watch-and-fix.md
claims the command applies fixes and commits/pushes and that it filters reviews
to “Bot-only”, but the implementation in github/examples/watch-and-fix.sh still
contains a fix placeholder and uses a `Bot or OWNER` filter; reconcile them by
either (A) implementing the automatic fix+commit+push flow in
github/examples/watch-and-fix.sh (replace the placeholder fix logic with the
real edit/apply/commit/push steps and ensure the script invokes git commit/push)
and update the review-source filter in the script to only accept `Bot` reviews,
or (B) revert the doc text to match the current script behavior (document that
fixes are placeholders and that the script filters `Bot` or `OWNER`), making
sure to update the review-source wording in github/commands/watch-and-fix.md and
remove any claim of Bot-only behavior. Ensure you update the unique files
github/examples/watch-and-fix.sh and github/commands/watch-and-fix.md
consistently so doc and implementation match.
In `@github/examples/watch-and-fix.sh`:
- Around line 125-134: The script currently only prints a warning where it
should run the automated fixer (the block with the "Applying fixes..." echo and
the "⚠️ Fix automation requires fix:and-update-pr skill integration" message);
replace that placeholder with a real invocation to the fix orchestration (e.g.
call the fix:and-update-pr skill/command or an apply_fixes helper), capture and
check its exit status, commit and push any updated files or update the PR if
fixes were applied, and only continue the loop (or retry with backoff) on
success—on failure emit an error and either abort the loop or retry according to
policy. Ensure you modify the section that currently contains the two echo
warnings and the comment about fix:and-update-pr so it runs the fixer, handles
errors, and updates the repo/PR when fixes are applied.
- Around line 17-20: The arg-parsing branches that assign MAX_ITERATIONS and
PR_NUMBER read "$2" without validating it, which under set -u can cause an
unbound-variable crash; update the --max-iterations and --pr cases to first
check that a next argument exists and is not another option (e.g., test that
"${2-}" is non-empty and does not start with "-"), emit a clear "missing value
for --max-iterations/--pr" error and exit if invalid, otherwise assign
MAX_ITERATIONS="$2" or PR_NUMBER="$2" and shift; also apply the same
presence-check pattern to any future flags that expect a value.
- Around line 37-41: The PR lookup assigns PR_NUMBER using gh and the jq
expression can return the literal string "null" when no PR matches; update the
check after retrieving PR_NUMBER (used with BRANCH) to treat both empty and the
string "null" as not found (e.g., test for -z OR equals "null") and exit with
the existing error path so subsequent GitHub CLI commands don't run with
PR_NUMBER="null".
- Around line 57-79: Initialize CI status vars and sanitize RUN_ID before the
merge check: set CONCLUSION="unknown" and STATUS="unknown" prior to the RUN_ID
logic so they are always defined under set -u, and change the RUN_ID assignment
to return an empty string when jq yields null (e.g. use --jq '.[0].databaseId //
""' or -r with '.[0].databaseId // ""') and/or ensure the merge check tests
RUN_ID for both empty and literal "null" (e.g. if [ -n "$RUN_ID" ] && [
"$RUN_ID" != "null" ]); keep REVIEW_STATE as-is but ensure the later if that
tests CONCLUSION uses the initialized CONCLUSION variable.
- Line 96: The current COMMENTS extraction uses a GH query filter allowing
`.authorAssociation == "OWNER"`, which lets human repo owners trigger fixes;
update the filter in the COMMENTS assignment (the gh pr view command that builds
COMMENTS) to restrict sources to bots only by removing or replacing the `or
.authorAssociation == "OWNER"` clause so the selector only checks `.author.type
== "Bot"`, ensuring only bot-authored comments are parsed as trusted AI review
sources.
In `@github/skills/github.md`:
- Around line 311-317: The docs currently claim the "watch-and-fix" command
fully automates parsing/applying fixes and pushing commits, but
github/examples/watch-and-fix.sh is only a placeholder; either update
github/skills/github.md to accurately describe the current manual workflow (call
out that github/examples/watch-and-fix.sh logs a placeholder and requires manual
edits) or implement the automation in github/examples/watch-and-fix.sh to
perform the listed steps: wait for CI, fetch review comments (e.g., via gh api
or gh pr review-comments), parse suggested fixes, apply patches (git apply or
patch), commit and push changes, and loop until CI/approval—choose one and make
the doc and the script consistent (reference: the "watch-and-fix" command and
github/examples/watch-and-fix.sh).
---
Duplicate comments:
In `@github/README.md`:
- Around line 170-186: The README has fenced code blocks that lack language
identifiers: update the repository tree block and the commit-convention example
blocks in the README to use ```text (i.e., change the opening ``` to ```text for
those blocks) so the tree and commit examples are rendered as plain text; leave
the closing ``` unchanged and ensure all similar examples (the repository tree
block and the commit message examples) receive the same change.
- Around line 87-93: The current script uses users/$(login)/repos to count a
user's total repos, which doesn't indicate whether this is their first
contribution to this repository; replace that check with a repository-scoped PR
count: after extracting the author via gh pr view $pr --json author --jq
'.author.login', call gh pr list --author "$author" --repo "$(gh repo view
--json nameWithOwner --jq '.nameWithOwner')" --state all --json number --jq
'length' and treat the author as a first-time contributor only if that count is
1 (meaning only the current PR exists); update the script logic around the
variables pr and count and the gh pr edit invocation accordingly so labeling is
based on prior PRs in this repo rather than total user repos.
In `@github/skills/github.md`:
- Around line 446-448: The examples use an unsupported --page flag with the gh
pr list command and also show a mistaken mixed usage of --json and --jq; remove
the unsupported --page 2 token from the example(s) and update the surrounding
gotcha/final note to no longer reference --page, leaving the valid invocation(s)
such as gh pr list --limit 100 --json number,title (and gh pr list --limit 100
--json number,title --jq '.[]' if you intend to demonstrate jq-style filtering),
and make the same removal/update for the duplicate occurrence that appears later
in the file; ensure references to --page are deleted and examples show only
supported flags for gh pr list.
- Around line 493-500: The current approach uses a regex on the username in the
gh pr list pipeline (the select(.author.login | test("^[a-z0-9_-]{4,}$")) step
and subsequent while loop/gh pr edit) which misclassifies contributors; replace
the regex check with a real contribution-history check by calling the GitHub API
for each PR author (e.g., via gh api) to verify whether they have previous
contributions/merged PRs or prior activity in the repo before adding the
"first-time-contributor" label, and update the pipeline so gh pr edit is invoked
only when the API response confirms zero prior contributions for that author.
- Around line 529-530: The example uses BSD-only date arithmetic ("date -v-30d")
in the gh pr list command, which breaks on GNU/Linux; replace the inline date
substitution used in the gh pr list example with a portable approach such as
computing a 30-day-ago value with a fallback that supports both BSD and GNU
(e.g., set a DATE_30_DAYS_AGO variable using date -v-30d ... 2>/dev/null || date
-d '30 days ago' ... and then use that variable in the gh pr list --search
string), and update the snippet referencing the substitution used with gh pr
list to use that variable instead (refer to the gh pr list --search "draft:yes
updated:<$(...)" usage in the diff).
In `@marketplace.json`:
- Around line 81-82: The marketplace.json "description" for version "1.3.0" is
out of sync with github/.claude-plugin/plugin.json; update the plugin metadata
so both manifests share the same capability description for the same "version"
(e.g., align the "description" field in marketplace.json with the "description"
in github/.claude-plugin/plugin.json or vice versa), or centralize the source of
truth and propagate it to both files so catalog metadata remains consistent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 74a20eaa-d90a-413e-995e-1ec1ce7daca8
📒 Files selected for processing (6)
github/.claude-plugin/plugin.jsongithub/README.mdgithub/commands/watch-and-fix.mdgithub/examples/watch-and-fix.shgithub/skills/github.mdmarketplace.json
| 4. **Fix issues**: Applies fixes based on review feedback | ||
| 5. **Commit and push**: Commits fixes with semantic message | ||
| 6. **Repeat**: Goes back to step 1 |
There was a problem hiding this comment.
Documented behavior is ahead of implementation and internally inconsistent.
The doc says the command applies fixes and commits/pushes, and defines a Bot-only review source, but current script (github/examples/watch-and-fix.sh) still has a fix placeholder and uses Bot or OWNER filtering.
Also applies to: 118-118, 121-125
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/commands/watch-and-fix.md` around lines 39 - 41, The documentation in
github/commands/watch-and-fix.md claims the command applies fixes and
commits/pushes and that it filters reviews to “Bot-only”, but the implementation
in github/examples/watch-and-fix.sh still contains a fix placeholder and uses a
`Bot or OWNER` filter; reconcile them by either (A) implementing the automatic
fix+commit+push flow in github/examples/watch-and-fix.sh (replace the
placeholder fix logic with the real edit/apply/commit/push steps and ensure the
script invokes git commit/push) and update the review-source filter in the
script to only accept `Bot` reviews, or (B) revert the doc text to match the
current script behavior (document that fixes are placeholders and that the
script filters `Bot` or `OWNER`), making sure to update the review-source
wording in github/commands/watch-and-fix.md and remove any claim of Bot-only
behavior. Ensure you update the unique files github/examples/watch-and-fix.sh
and github/commands/watch-and-fix.md consistently so doc and implementation
match.
| --max-iterations) MAX_ITERATIONS="$2"; shift ;; | ||
| --dry-run) DRY_RUN=true ;; | ||
| --pr) PR_NUMBER="$2"; shift ;; | ||
| *) echo "Unknown option: $1"; exit 1 ;; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n github/examples/watch-and-fix.shRepository: duyet/claude-plugins
Length of output: 5338
Validate required option values during arg parsing.
Lines 17 and 19 access $2 without checking if it exists. With set -u (enabled on line 5), missing values cause an "unbound variable" error instead of a user-friendly message.
Suggested fix
- --max-iterations) MAX_ITERATIONS="$2"; shift ;;
+ --max-iterations)
+ [[ $# -ge 2 ]] || { echo "Missing value for --max-iterations"; exit 1; }
+ MAX_ITERATIONS="$2"; shift ;;
@@
- --pr) PR_NUMBER="$2"; shift ;;
+ --pr)
+ [[ $# -ge 2 ]] || { echo "Missing value for --pr"; exit 1; }
+ PR_NUMBER="$2"; shift ;;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| --max-iterations) MAX_ITERATIONS="$2"; shift ;; | |
| --dry-run) DRY_RUN=true ;; | |
| --pr) PR_NUMBER="$2"; shift ;; | |
| *) echo "Unknown option: $1"; exit 1 ;; | |
| --max-iterations) | |
| [[ $# -ge 2 ]] || { echo "Missing value for --max-iterations"; exit 1; } | |
| MAX_ITERATIONS="$2"; shift ;; | |
| --dry-run) DRY_RUN=true ;; | |
| --pr) | |
| [[ $# -ge 2 ]] || { echo "Missing value for --pr"; exit 1; } | |
| PR_NUMBER="$2"; shift ;; | |
| *) echo "Unknown option: $1"; exit 1 ;; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/examples/watch-and-fix.sh` around lines 17 - 20, The arg-parsing
branches that assign MAX_ITERATIONS and PR_NUMBER read "$2" without validating
it, which under set -u can cause an unbound-variable crash; update the
--max-iterations and --pr cases to first check that a next argument exists and
is not another option (e.g., test that "${2-}" is non-empty and does not start
with "-"), emit a clear "missing value for --max-iterations/--pr" error and exit
if invalid, otherwise assign MAX_ITERATIONS="$2" or PR_NUMBER="$2" and shift;
also apply the same presence-check pattern to any future flags that expect a
value.
| PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number') | ||
| if [ -z "$PR_NUMBER" ]; then | ||
| echo "Error: No PR found for branch $BRANCH" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the actual file
cat -n github/examples/watch-and-fix.sh | sed -n '30,50p'Repository: duyet/claude-plugins
Length of output: 799
🏁 Script executed:
# Let's also check what jq outputs when accessing a missing array element
# Testing jq behavior with empty arrays
echo '[]' | jq '.[0].number'
echo '[]' | jq -r '.[0].number'
echo '[{"number": 123}]' | jq '.[0].number'Repository: duyet/claude-plugins
Length of output: 77
🏁 Script executed:
# Check if gh command is available and understand the behavior
# Also look for any test cases or documentation in the repo
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "*test*" \) | grep -i watchRepository: duyet/claude-plugins
Length of output: 98
🏁 Script executed:
# Search for any mentions of gh pr list in the codebase
rg "gh pr list" -A 2 -B 2Repository: duyet/claude-plugins
Length of output: 5153
🏁 Script executed:
# Check gh documentation or help
gh pr list --help | head -50Repository: duyet/claude-plugins
Length of output: 2445
Treat null PR lookup as not found.
gh pr list ... --jq '.[0].number' returns the literal string null when no results match; the current empty-string check does not catch this, allowing the script to proceed with PR_NUMBER="null" and fail on subsequent GitHub CLI operations.
Suggested fix
PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number')
-if [ -z "$PR_NUMBER" ]; then
+if [ -z "$PR_NUMBER" ] || [ "$PR_NUMBER" = "null" ]; then
echo "Error: No PR found for branch $BRANCH"
exit 1
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number') | |
| if [ -z "$PR_NUMBER" ]; then | |
| echo "Error: No PR found for branch $BRANCH" | |
| exit 1 | |
| fi | |
| PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number') | |
| if [ -z "$PR_NUMBER" ] || [ "$PR_NUMBER" = "null" ]; then | |
| echo "Error: No PR found for branch $BRANCH" | |
| exit 1 | |
| fi |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/examples/watch-and-fix.sh` around lines 37 - 41, The PR lookup assigns
PR_NUMBER using gh and the jq expression can return the literal string "null"
when no PR matches; update the check after retrieving PR_NUMBER (used with
BRANCH) to treat both empty and the string "null" as not found (e.g., test for
-z OR equals "null") and exit with the existing error path so subsequent GitHub
CLI commands don't run with PR_NUMBER="null".
| RUN_ID=$(gh run list --workflow=ci.yml --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null || echo "") | ||
|
|
||
| if [ -n "$RUN_ID" ]; then | ||
| echo "Watching CI run #$RUN_ID..." | ||
| gh run watch "$RUN_ID" --interval 10 || true | ||
|
|
||
| # Check CI status | ||
| CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion' 2>/dev/null || echo "unknown") | ||
| STATUS=$(gh run view "$RUN_ID" --json status --jq '.status' 2>/dev/null || echo "unknown") | ||
|
|
||
| echo "CI Status: $STATUS" | ||
| echo "CI Conclusion: $CONCLUSION" | ||
| else | ||
| echo "No CI run found, checking PR status..." | ||
| fi | ||
|
|
||
| # Get PR review status | ||
| REVIEW_STATE=$(gh pr view "$PR_NUMBER" --json reviewDecision --jq '.reviewDecision // "PENDING"') | ||
| echo "Review State: $REVIEW_STATE" | ||
|
|
||
| # Check if we can merge | ||
| if [ "$CONCLUSION" = "success" ] && { [ "$REVIEW_STATE" = "APPROVED" ] || [ "$REVIEW_STATE" = "NULL" ]; }; then | ||
| echo "✅ CI passed and reviews approved!" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "watch-and-fix.sh" -type fRepository: duyet/claude-plugins
Length of output: 98
🏁 Script executed:
cat -n github/examples/watch-and-fix.shRepository: duyet/claude-plugins
Length of output: 5338
Initialize CI state variables before the merge check to prevent script termination under set -u.
When no workflow run exists, CONCLUSION and STATUS are never initialized and remain unset. At line 78, the script accesses $CONCLUSION, which causes immediate termination under set -u (present at line 5). Additionally, if gh run list returns an empty array, jq produces the literal string null, which bypasses the || echo "" fallback on line 57, leaving RUN_ID="null".
Suggested fix
+CONCLUSION="unknown"
+STATUS="unknown"
RUN_ID=$(gh run list --workflow=ci.yml --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null || echo "")
+if [ "$RUN_ID" = "null" ]; then RUN_ID=""; fi
if [ -n "$RUN_ID" ]; then📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| RUN_ID=$(gh run list --workflow=ci.yml --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null || echo "") | |
| if [ -n "$RUN_ID" ]; then | |
| echo "Watching CI run #$RUN_ID..." | |
| gh run watch "$RUN_ID" --interval 10 || true | |
| # Check CI status | |
| CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion' 2>/dev/null || echo "unknown") | |
| STATUS=$(gh run view "$RUN_ID" --json status --jq '.status' 2>/dev/null || echo "unknown") | |
| echo "CI Status: $STATUS" | |
| echo "CI Conclusion: $CONCLUSION" | |
| else | |
| echo "No CI run found, checking PR status..." | |
| fi | |
| # Get PR review status | |
| REVIEW_STATE=$(gh pr view "$PR_NUMBER" --json reviewDecision --jq '.reviewDecision // "PENDING"') | |
| echo "Review State: $REVIEW_STATE" | |
| # Check if we can merge | |
| if [ "$CONCLUSION" = "success" ] && { [ "$REVIEW_STATE" = "APPROVED" ] || [ "$REVIEW_STATE" = "NULL" ]; }; then | |
| echo "✅ CI passed and reviews approved!" | |
| CONCLUSION="unknown" | |
| STATUS="unknown" | |
| RUN_ID=$(gh run list --workflow=ci.yml --branch "$BRANCH" --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null || echo "") | |
| if [ "$RUN_ID" = "null" ]; then RUN_ID=""; fi | |
| if [ -n "$RUN_ID" ]; then | |
| echo "Watching CI run #$RUN_ID..." | |
| gh run watch "$RUN_ID" --interval 10 || true | |
| # Check CI status | |
| CONCLUSION=$(gh run view "$RUN_ID" --json conclusion --jq '.conclusion' 2>/dev/null || echo "unknown") | |
| STATUS=$(gh run view "$RUN_ID" --json status --jq '.status' 2>/dev/null || echo "unknown") | |
| echo "CI Status: $STATUS" | |
| echo "CI Conclusion: $CONCLUSION" | |
| else | |
| echo "No CI run found, checking PR status..." | |
| fi | |
| # Get PR review status | |
| REVIEW_STATE=$(gh pr view "$PR_NUMBER" --json reviewDecision --jq '.reviewDecision // "PENDING"') | |
| echo "Review State: $REVIEW_STATE" | |
| # Check if we can merge | |
| if [ "$CONCLUSION" = "success" ] && { [ "$REVIEW_STATE" = "APPROVED" ] || [ "$REVIEW_STATE" = "NULL" ]; }; then | |
| echo "✅ CI passed and reviews approved!" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/examples/watch-and-fix.sh` around lines 57 - 79, Initialize CI status
vars and sanitize RUN_ID before the merge check: set CONCLUSION="unknown" and
STATUS="unknown" prior to the RUN_ID logic so they are always defined under set
-u, and change the RUN_ID assignment to return an empty string when jq yields
null (e.g. use --jq '.[0].databaseId // ""' or -r with '.[0].databaseId // ""')
and/or ensure the merge check tests RUN_ID for both empty and literal "null"
(e.g. if [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ]); keep REVIEW_STATE as-is
but ensure the later if that tests CONCLUSION uses the initialized CONCLUSION
variable.
|
|
||
| # Get review comments | ||
| echo "Fetching review comments..." | ||
| COMMENTS=$(gh pr view "$PR_NUMBER" --json comments -q '.comments[] | select(.author.type == "Bot" or .authorAssociation == "OWNER") | [.path, .line, .body] | @tsv' 2>/dev/null || echo "") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd github && pwd && head -n 110 examples/watch-and-fix.sh | tail -n 20Repository: duyet/claude-plugins
Length of output: 761
🏁 Script executed:
cat -n github/examples/watch-and-fix.sh | sed -n '85,110p'Repository: duyet/claude-plugins
Length of output: 1119
🏁 Script executed:
cat -n github/examples/watch-and-fix.sh | head -n 50Repository: duyet/claude-plugins
Length of output: 1704
🏁 Script executed:
rg -A 5 -B 5 "authorAssociation" github/examples/watch-and-fix.shRepository: duyet/claude-plugins
Length of output: 459
🏁 Script executed:
fd -t f "README|DOCS|\.md" github/examples/Repository: duyet/claude-plugins
Length of output: 46
🏁 Script executed:
find github -name "*.md" -o -name "README*" -o -name "*.txt" | head -20Repository: duyet/claude-plugins
Length of output: 238
🏁 Script executed:
rg -i "owner\|ai\|bot" github/examples/watch-and-fix.sh | head -20Repository: duyet/claude-plugins
Length of output: 46
🏁 Script executed:
ls -la github/examples/Repository: duyet/claude-plugins
Length of output: 444
🏁 Script executed:
cat -n github/examples/watch-and-fix.sh | sed -n '50,130p'Repository: duyet/claude-plugins
Length of output: 3383
🏁 Script executed:
cat -n github/commands/watch-and-fix.mdRepository: duyet/claude-plugins
Length of output: 4560
🏁 Script executed:
cat -n github/README.mdRepository: duyet/claude-plugins
Length of output: 7115
Limit parsed fix sources to trusted AI review authors.
The documentation states the script automatically fixes "issues identified in AI reviews" and "AI agents", but the filter at line 96 includes .authorAssociation == "OWNER", which allows human repository owners (not just bots) to trigger the fix pipeline. Either restrict the filter to bot authors only (.author.type == "Bot"), or update the documentation to clarify that human owners are intentionally included.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/examples/watch-and-fix.sh` at line 96, The current COMMENTS extraction
uses a GH query filter allowing `.authorAssociation == "OWNER"`, which lets
human repo owners trigger fixes; update the filter in the COMMENTS assignment
(the gh pr view command that builds COMMENTS) to restrict sources to bots only
by removing or replacing the `or .authorAssociation == "OWNER"` clause so the
selector only checks `.author.type == "Bot"`, ensuring only bot-authored
comments are parsed as trusted AI review sources.
| # Apply fixes using the fix skill | ||
| echo "Applying fixes..." | ||
| # This would invoke the fix:and-update-pr skill | ||
| # For now, just notify that fixes need to be applied | ||
| echo "⚠️ Fix automation requires fix:and-update-pr skill integration" | ||
| echo "Please manually fix issues or ensure fix plugin is installed." | ||
|
|
||
| # After fixes, the loop continues | ||
| echo "Waiting for CI to restart..." | ||
| sleep 10 |
There was a problem hiding this comment.
The loop cannot self-heal because fix execution is not implemented.
The script advertises automated fixing but only prints a warning and waits. This creates repeated iterations without applying or pushing changes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/examples/watch-and-fix.sh` around lines 125 - 134, The script
currently only prints a warning where it should run the automated fixer (the
block with the "Applying fixes..." echo and the "⚠️ Fix automation requires
fix:and-update-pr skill integration" message); replace that placeholder with a
real invocation to the fix orchestration (e.g. call the fix:and-update-pr
skill/command or an apply_fixes helper), capture and check its exit status,
commit and push any updated files or update the PR if fixes were applied, and
only continue the loop (or retry with backoff) on success—on failure emit an
error and either abort the loop or retry according to policy. Ensure you modify
the section that currently contains the two echo warnings and the comment about
fix:and-update-pr so it runs the fixer, handles errors, and updates the repo/PR
when fixes are applied.
| The watch-and-fix command: | ||
| 1. Waits for CI to complete | ||
| 2. Gets review comments from AI agents | ||
| 3. Parses and applies fixes | ||
| 4. Commits and pushes changes | ||
| 5. Repeats until CI passes and PR is approved | ||
| 6. Optionally auto-merges when ready |
There was a problem hiding this comment.
Watch-and-fix workflow is documented as fully automated, but current implementation is not.
This section says fixes are parsed/applied and committed/pushed, but github/examples/watch-and-fix.sh currently only logs a placeholder and asks for manual fixes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@github/skills/github.md` around lines 311 - 317, The docs currently claim the
"watch-and-fix" command fully automates parsing/applying fixes and pushing
commits, but github/examples/watch-and-fix.sh is only a placeholder; either
update github/skills/github.md to accurately describe the current manual
workflow (call out that github/examples/watch-and-fix.sh logs a placeholder and
requires manual edits) or implement the automation in
github/examples/watch-and-fix.sh to perform the listed steps: wait for CI, fetch
review comments (e.g., via gh api or gh pr review-comments), parse suggested
fixes, apply patches (git apply or patch), commit and push changes, and loop
until CI/approval—choose one and make the doc and the script consistent
(reference: the "watch-and-fix" command and github/examples/watch-and-fix.sh).
Summary
This PR removes the
terminal-ui-designplugin (consolidated withfrontend-design) and significantly enhances the GitHub and commit plugins with batch operations, PR templates, automation workflows, and comprehensive documentation.Changes
Removed
terminal-ui-design/plugin directory (4 files) - consolidated with frontend-designGitHub Plugin (v1.1.0 → v1.2.0)
/github:bulk-close-issues,/github:bulk-merge-prs,/github:bulk-labelgithub/README.mdwith usage examples and troubleshootingbulk-close-issues.sh- Close issues by label with confirmationbulk-merge-prs.sh- Merge approved PRs with passing CIpr-automation.sh- Auto-label, auto-assign, and welcome contributorsCommit Plugin (v1.2.1 → v1.3.0)
commit/.pr-templates/:default.md- General purpose PR templatebugfix.md- Bug fix PR template with root cause and regression riskfeature.md- New feature PR template with motivation and breaking changes/commit:and-create-prcommand:--template <name>option for explicit template selection--draftoption to create draft PRsMarketplace Updates
.claude-plugin/marketplace.json(13 → 12 plugins)marketplace.jsonwith new plugin versionsREADME.md- removed terminal-ui-design referencesCHANGELOG.mdwith all new features.github/ISSUE_TEMPLATE/feature_request.md- removed checkboxGitHub Actions
.github/workflows/pr-automation.yml.github/workflows/pr-automation.mdCode Quality Improvements
As part of the simplify review:
Testing
Run through documented examples to verify:
Generated with Claude Code
Summary by Sourcery
Introduce GitHub batch operation commands, PR templates for the commit plugin, and an automated PR triage workflow while removing the deprecated terminal-ui-design plugin.
New Features:
Enhancements:
CI:
Documentation:
Chores:
Summary by CodeRabbit
New Features
Documentation
Removed