diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index dec8ba0..af73ff4 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -8,7 +8,7 @@ "name": "pr-comments-resolver", "source": { "source": "local", - "path": "." + "path": "./plugins/codex/pr-comments-resolver" }, "policy": { "installation": "AVAILABLE", diff --git a/.augment-plugin/marketplace.json b/.augment-plugin/marketplace.json index 0756447..47e0e70 100644 --- a/.augment-plugin/marketplace.json +++ b/.augment-plugin/marketplace.json @@ -7,7 +7,7 @@ "name": "pr-comments-resolver", "description": "Resolve unresolved PR/MR review comments across GitHub, GitLab, Bitbucket Cloud, and Azure DevOps", "version": "1.1.3", - "source": ".", + "source": "./plugins/augment/pr-comments-resolver", "category": "code-review", "tags": [ "pr", diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 37306fa..7f97e04 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ "plugins": [ { "name": "pr-comments-resolver", - "source": "./", + "source": "./plugins/claude/pr-comments-resolver", "description": "Resolve unresolved PR/MR review comments across GitHub, GitLab, Bitbucket Cloud, and Azure DevOps", "version": "1.1.3", "category": "code-review", diff --git a/.github/workflows/build-dist-on-pr-merge.yml b/.github/workflows/build-dist-on-pr-merge.yml deleted file mode 100644 index fa7774c..0000000 --- a/.github/workflows/build-dist-on-pr-merge.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Build Dist On PR Merge - -on: - pull_request: - types: [closed] - branches: [main] - -jobs: - build-agent: - if: github.event.pull_request.merged == true - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - agent: [claude, codex, augment, junie, roo] - - steps: - - uses: actions/checkout@v6 - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - - name: Build ${{ matrix.agent }} - run: bash scripts/build.sh ${{ matrix.agent }} - - - name: Upload ${{ matrix.agent }} outputs - uses: actions/upload-artifact@v7 - with: - name: build-${{ matrix.agent }} - include-hidden-files: true - path: | - dist/${{ matrix.agent }}/ - skills/resolve-comments/SKILL.md - .codex-plugin/ - .agents/plugins/ - icon.png - README.md - LICENSE - PRIVACY.md - - commit-dist: - if: github.event.pull_request.merged == true - needs: build-agent - runs-on: ubuntu-latest - permissions: - contents: write - - steps: - - uses: actions/checkout@v6 - with: - ref: main - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - - name: Download built artifacts - uses: actions/download-artifact@v8 - with: - path: .artifacts - - - name: Merge artifacts into workspace - run: | - cp -R .artifacts/build-claude/skills/. skills/ - cp -R .artifacts/build-codex/dist/. dist/ - cp -R .artifacts/build-augment/dist/. dist/ - cp -R .artifacts/build-junie/dist/. dist/ - cp -R .artifacts/build-roo/dist/. dist/ - - - name: Validate generated files - run: python3 scripts/validate.py - - - name: Commit updated dist outputs - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add dist/ skills/ - if git diff --cached --quiet; then - echo "No generated changes to commit." - exit 0 - fi - git commit -m "chore: rebuild generated skill artifacts" - git push origin main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9a63c2b..2cc8a1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,49 +1,68 @@ name: Release +# Single ordered pipeline that runs after a merge to main: +# 1. determine the next SemVer version (dry-run, no tag pushed yet) +# 2. sync that version into the plugin manifests +# 3. regenerate all agent artifacts (skills/, dist/, plugins/) from core/ + adapters/ +# 4. validate + smoke-test the generated artifacts +# 5. commit the regenerated artifacts back to main (only if something changed) +# 6. create + push the version tag on that commit +# +# The tag therefore always points at the commit that contains the freshly +# generated artifacts. +# +# Loop prevention: +# - Commits pushed with the default GITHUB_TOKEN do NOT trigger new workflow +# runs (GitHub's built-in recursion guard). +# - The artifact commit additionally carries "[skip ci]" as belt-and-suspenders. +# - Pushing a tag does not trigger this workflow (it only listens on branch pushes). +# +# Permissions / branch protection assumptions: +# - github-actions[bot] (via GITHUB_TOKEN with contents: write) must be allowed +# to push directly to main. If main is protected with "require pull request", +# the bot must be on the bypass list. This is unchanged from the previous +# release workflow, which already pushed to main. + on: push: branches: [main] jobs: - tag: - name: SemVer Tag + release: + name: Build, Commit Artifacts & Tag runs-on: ubuntu-latest permissions: contents: write - outputs: - new_tag: ${{ steps.tag.outputs.new_tag }} - new_version: ${{ steps.tag.outputs.new_version }} + steps: - uses: actions/checkout@v6 with: + ref: main fetch-depth: 0 - - name: Bump version and push tag - id: tag + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.11" + + # 1. Resolve the next version WITHOUT creating the tag yet. + - name: Determine next version (dry run) + id: version uses: mathieudutour/github-tag-action@v6.2 with: github_token: ${{ secrets.GITHUB_TOKEN }} default_bump: patch tag_prefix: v release_branches: main + dry_run: true - sync-version: - name: Sync Version To Manifests - needs: tag - if: needs.tag.outputs.new_tag != '' - runs-on: ubuntu-latest - permissions: - contents: write - - steps: - - uses: actions/checkout@v6 - with: - ref: main - fetch-depth: 0 - - - name: Update manifests + # 2. Sync the resolved version into the plugin manifests so the generated + # plugins/ packages embed the correct version. Skipped when there is no + # version bump (e.g. a docs-only commit). + - name: Sync version into manifests + if: steps.version.outputs.new_version != '' env: - VERSION: ${{ needs.tag.outputs.new_version }} + VERSION: ${{ steps.version.outputs.new_version }} run: | set -euo pipefail tmp="$(mktemp)" @@ -65,28 +84,60 @@ jobs: } # Claude - bump_root .claude-plugin/plugin.json + bump_root .claude-plugin/plugin.json bump_plugins_entry .claude-plugin/marketplace.json # Augment (root version on both files + plugins[] entry) - bump_root .augment-plugin/plugin.json - bump_root .augment-plugin/marketplace.json + bump_root .augment-plugin/plugin.json + bump_root .augment-plugin/marketplace.json bump_plugins_entry .augment-plugin/marketplace.json # Codex - bump_root .codex-plugin/plugin.json + bump_root .codex-plugin/plugin.json + + # 3. Regenerate all agent artifacts from the sources. + - name: Build all agents + run: bash scripts/build.sh all + + # 4. Validate + smoke-test the generated artifacts. + - name: Validate generated files + run: python3 scripts/validate.py + + - name: Smoke test + run: bash tests/build_test.sh - - name: Commit version bump + # 5. Commit regenerated artifacts + manifests back to main, only if changed. + - name: Commit regenerated artifacts + id: commit env: - TAG: ${{ needs.tag.outputs.new_tag }} - VERSION: ${{ needs.tag.outputs.new_version }} + TAG: ${{ steps.version.outputs.new_tag }} run: | + set -euo pipefail git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add .claude-plugin/ .augment-plugin/ .codex-plugin/ + git add skills/ dist/ plugins/ .claude-plugin/ .augment-plugin/ .codex-plugin/ if git diff --cached --quiet; then - echo "Manifests already at version ${VERSION}; nothing to commit." + echo "No generated changes to commit." + echo "committed=false" >> "$GITHUB_OUTPUT" exit 0 fi - git commit -m "chore: sync manifest version to ${TAG} [skip ci]" + msg="chore: rebuild generated artifacts" + if [ -n "${TAG:-}" ]; then + msg="chore: rebuild generated artifacts and sync version to ${TAG}" + fi + git commit -m "${msg} [skip ci]" git push origin main + echo "committed=true" >> "$GITHUB_OUTPUT" + + # 6. Tag the local HEAD of main, which now contains the freshly generated + # artifacts. We tag explicitly with git (rather than re-running the tag + # action) because the action tags GITHUB_SHA — the original triggering + # commit — which would miss the artifact commit pushed in step 5. + - name: Create and push release tag + if: steps.version.outputs.new_tag != '' + env: + TAG: ${{ steps.version.outputs.new_tag }} + run: | + set -euo pipefail + git tag -a "$TAG" -m "$TAG" + git push origin "$TAG" diff --git a/.github/workflows/verify-build.yml b/.github/workflows/verify-build.yml index e7694ad..b71da28 100644 --- a/.github/workflows/verify-build.yml +++ b/.github/workflows/verify-build.yml @@ -1,9 +1,13 @@ name: Verify build +# PR sanity check: the sources must build cleanly and pass validation + smoke +# tests. Generated artifacts (skills/, dist/, plugins/) are produced and +# committed automatically after merge by release.yml, so contributors are NOT +# required to build and commit them locally — this workflow therefore does not +# enforce drift against committed outputs. + on: pull_request: - push: - branches: [main] jobs: verify: @@ -16,10 +20,6 @@ jobs: python-version: "3.11" - name: Build all agents run: bash scripts/build.sh all - - name: Verify no drift in committed outputs - run: | - git diff --exit-code -- skills/ dist/ \ - || { echo "Generated files are out of date — run 'bash scripts/build.sh all' and commit."; exit 1; } - name: Validate frontmatter and coverage run: python3 scripts/validate.py - name: Smoke test diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f7222..828a88d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - `persistence-step.md` snippets gain the `Reply/Resolve permission` field (per-adapter naming). Memories without the field trigger the one-time prompt — fully back-compat. +- Marketplace manifests for Claude, Augment, and Codex now point to generated agent-specific plugin bundles under `plugins/` instead of the repository root, so Git-based marketplace installs resolve an installable plugin directory after clone. ## [1.0.0] - 2026-05-12 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c061a4..021bae3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,7 @@ This repository ships generated outputs for multiple agents. The canonical logic .codex-plugin/ Codex plugin manifest .agents/plugins/ Codex repo-scoped marketplace manifest .augment-plugin/ Augment plugin manifests +plugins/ Generated marketplace-ready plugin bundles core/ Canonical workflow and platform modules adapters/ Per-agent frontmatter, prelude, and snippets skills/resolve-comments/ Claude build output @@ -79,6 +80,7 @@ bash tests/build_test.sh - `.codex-plugin/plugin.json` — Codex plugin identity and skill path - `.agents/plugins/marketplace.json` — Codex repo-scoped marketplace listing - `.augment-plugin/*.json` — Augment manifests +- `plugins//pr-comments-resolver/` — generated marketplace install bundles ## Commit Style @@ -101,11 +103,12 @@ Types: `feat`, `fix`, `docs`, `refactor`, `chore` ## Releasing -Releases and generated artifacts are handled by the GitHub Actions workflows in `.github/workflows/`. `verify-build.yml` enforces no drift in committed outputs, and merged PRs trigger `build-dist-on-pr-merge.yml` to rebuild and commit generated artifacts. +Releases and generated artifacts are fully automated by the GitHub Actions workflows in `.github/workflows/`. You do **not** need to build or commit generated outputs (`skills/`, `dist/`, `plugins/`) — edit only the sources under `core/` and `adapters/`. -Version metadata is synchronized by `release.yml`. +- On a pull request, `verify-build.yml` builds the sources and runs validation + smoke tests as a sanity check (it does not enforce drift against committed outputs). +- After a merge to `main`, `release.yml` runs a single ordered pipeline: it resolves the next version, syncs it into the manifests, rebuilds all artifacts, validates and smoke-tests them, commits the regenerated artifacts back to `main` (only if anything changed), and finally tags that commit. The tag therefore always points at the commit containing the freshly generated artifacts. -If you need a manual local check before opening a PR: +If you want to sanity-check the build locally before opening a PR: ```bash bash scripts/build.sh all diff --git a/README.md b/README.md index 240a5bf..43f05d6 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ For platforms with two paths the skill prompts on first use. The choice is persi ### Augment -Augment reads the same `.claude-plugin/` manifests as Claude, plus its own `.augment-plugin/`. Install via Augment's plugin/marketplace UI by pointing it at this repository. +Augment reads the same `.claude-plugin/` manifests as Claude, plus its own `.augment-plugin/`. The repository now ships an agent-specific plugin bundle under `plugins/augment/pr-comments-resolver`, so the marketplace entry points at an installable plugin directory instead of the repo root. Install via Augment's plugin/marketplace UI by pointing it at this repository. ### Codex -Codex auto-discovers `.codex-plugin/` and the repo-scoped marketplace at `.agents/plugins/marketplace.json`. +Codex auto-discovers `.codex-plugin/` and the repo-scoped marketplace at `.agents/plugins/marketplace.json`. The marketplace entry points at `plugins/codex/pr-comments-resolver`, which contains a self-contained Codex plugin bundle. If plugin installation from repo marketplaces is available in your Codex build, use the repository directly: diff --git a/plugins/augment/pr-comments-resolver/.augment-plugin/plugin.json b/plugins/augment/pr-comments-resolver/.augment-plugin/plugin.json new file mode 100644 index 0000000..dfa6fd0 --- /dev/null +++ b/plugins/augment/pr-comments-resolver/.augment-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "name": "pr-comments-resolver", + "version": "1.1.2", + "description": "Resolve unresolved PR/MR review comments across GitHub, GitLab, Bitbucket Cloud, and Azure DevOps", + "author": { + "name": "Marcel Strahl @ Dropelikeit", + "url": "https://github.com/Dropelikeit" + }, + "keywords": [ + "pr", + "code-review", + "github", + "gitlab", + "bitbucket", + "azure-devops", + "merge-request", + "review" + ], + "skills": "./skills/" +} diff --git a/plugins/augment/pr-comments-resolver/icon.png b/plugins/augment/pr-comments-resolver/icon.png new file mode 100644 index 0000000..e09bdd1 Binary files /dev/null and b/plugins/augment/pr-comments-resolver/icon.png differ diff --git a/plugins/augment/pr-comments-resolver/skills/resolve-comments/SKILL.md b/plugins/augment/pr-comments-resolver/skills/resolve-comments/SKILL.md new file mode 100644 index 0000000..13d5280 --- /dev/null +++ b/plugins/augment/pr-comments-resolver/skills/resolve-comments/SKILL.md @@ -0,0 +1,293 @@ +--- +name: resolve-comments +description: Use when resolving unresolved PR or MR review comments, working through reviewer feedback, or addressing code review threads on GitHub, GitLab, Bitbucket Cloud, or Azure DevOps repositories +--- + +# Resolve PR/MR Review Comments + +Work through all unresolved review comments from a pull request or merge request on GitHub, GitLab, Bitbucket Cloud, or Azure DevOps. + +> This skill activates implicitly when its description matches your request. You can also reference it explicitly by name. + +## Step 1: Platform Detection & CLI Verification + +### 1.1 Check Memory + +Check the agent's persistent memory (if available) for a previously saved `pr-comments-resolver-platform` configuration. If found, run a quick auth verification using the recorded `Auth method` and the platform module's `Auth verification` section. + +If the memory exists and auth is healthy, skip to Step 1.6 (Load Platform Module). + +If the memory is stale (auth fails) or not found, continue with detection. + +**Back-compat:** memories from older versions may not contain an `Auth method` field. Treat a missing `Auth method` as `cli`. + +### 1.2 Detect Platform + +Get the remote URL: + +```bash +git remote get-url origin +``` + +Match the URL against known patterns: + +| URL Contains | Platform | +|---|---| +| `github.com` | GitHub | +| `gitlab.com` | GitLab | +| `bitbucket.org` | Bitbucket Cloud | +| `dev.azure.com` or `visualstudio.com` | Azure DevOps | + +If the URL does not match any known pattern (e.g., a self-hosted instance), ask the user which platform this repository is hosted on. Offer the options: GitHub, GitLab, Bitbucket Cloud, Azure DevOps, Other. Ask the user directly in chat with the listed options. + +If the user picks "Other", inform them: "This skill currently supports GitHub, GitLab, Bitbucket Cloud, and Azure DevOps. Other hosting platforms are not yet supported." Then stop. + +### 1.3 Select Auth Method (Bitbucket and Azure only) + +For `bitbucket` and `azure`, if memory does not already record an `Auth method`, ask the user which method to use. Ask the user directly in chat with the listed options. + +Options: + +- **Bitbucket**: `CLI (acli)` or `MCP (Atlassian Remote, OAuth)`. +- **Azure DevOps**: `CLI (az + azure-devops extension)` or `MCP (@azure-devops/mcp, PAT-based)`. + +For `github` and `gitlab`, `Auth method` is always `cli` — no prompt is shown. + +Remember the chosen value as `Auth method` (it gets written to memory in Step 1.5). + +### 1.4 Verify Auth + +Use the platform module's `Auth verification` section, following the path that matches the chosen `Auth method` (Path A for `cli`, Path B for `mcp`). If auth is not healthy, follow the module's stop-with-instructions guidance. + +### 1.5 Persist Platform (if supported) + +Augment reads `AGENTS.md` for project guidelines. To persist platform info across runs, add a `## pr-comments-resolver` section (or place these lines in `AGENTS.local.md` if you want to keep them out of version control): + +``` +## pr-comments-resolver + +- platform: +- auth-method: +- cli-tool: # only when auth-method = cli +- mcp-server: # only when auth-method = mcp +- token-env-var: $ # only when MCP auth uses a PAT +- org-or-workspace: # bitbucket workspace or azure organization +- repository: +- reply-resolve-permission: # a = post & resolve, b = post only, c = none +``` + +Memories without `auth-method` from older runs are treated as `auth-method: cli`. Memories without `reply-resolve-permission` trigger the one-time Step 4.0 prompt. + +### 1.6 Load Platform Module + +Read the file `platforms/.md` (relative to this SKILL.md). It contains the platform-specific instructions for auth verification, repository identifier, PR/MR number detection, comment fetching, posting replies, and resolving threads. Use it as the authoritative source for those operations throughout the rest of this skill. + +Platform modules may invoke the MCP Config Writer for setting up an MCP server. The writer's procedure is: + +### MCP Config Writer + +This adapter does not currently include automatic MCP server configuration support. If a platform module requires MCP setup (Bitbucket MCP via Atlassian Remote, or Azure DevOps MCP via `@azure-devops/mcp`), instruct the user how to configure their host manually: + +- Show the user the MCP server entry the platform module wants to add (server id, command, args, and env-var-reference env block). +- Tell them to add it to their adapter's MCP configuration (e.g., Codex / Augment / Junie / Roo configuration file — exact path depends on the user's setup). +- Remind them: never paste a literal PAT into the config. Use the env-variable reference exactly as shown. +- Ask them to confirm when done, then stop and tell them to restart their agent. + +### 1.7 Get Repository Identifier + +See the platform module's `Repository identifier` section. + +## Step 2: Determine PR/MR Number + +If `$ARGUMENTS` is provided, use it as the PR/MR number. + +If `$ARGUMENTS` is empty or not provided, detect automatically from the current branch. See the platform module's `PR number` (or `MR IID`) section. + +If no PR/MR exists for the current branch, ask the user for the PR/MR number. Ask the user directly in chat with the listed options. + +## Step 3: Fetch & Display Unresolved Comments + +Use the platform module's `Fetch unresolved …` section to obtain the list of unresolved review threads/discussions and map them to the uniform `{file, line, author, body, thread_id}` shape. Then render them via the `Display Unresolved Comments` block below. + +### Display Unresolved Comments + +Show unresolved comments as a numbered list: + +``` +## Unresolved PR Comments (X of Y total) + +1. **path/to/file.ts:42** - @author + > Comment text here... + +2. **path/to/file.ts:108** - @author (outdated) + > Another comment... +``` + +The `(outdated)` marker means the code has changed since the comment was written — check relevance before acting. + +If there are no unresolved comments, inform the user and stop. + +## Step 3.5: Classify & Confirm + +Classify each unresolved comment into one of two buckets: + +- **deferred**: the comment flags a missing critical or larger piece of work — typically (a) a missing module/feature, (b) a security or correctness gap, (c) a refactor that touches more than two files, or (d) a reviewer-applied marker such as `blocker`, `critical`, or `must-fix`. +- **normal**: everything else (in-place edits within existing logic). + +Use these signals as a heuristic — the user confirms the final split: + +- **Scope**: would the fix introduce a new file/module, or change one existing function? +- **Keywords**: presence of `missing`, `not implemented`, `should also handle`, `security`, `race`, `architecture`, `refactor entire`, `add support for`, or localized equivalents. +- **Cross-file**: would the fix touch >2 files or require a design decision? +- **Severity markers**: explicit `blocker` / `critical` / `must-fix` labels or words from the reviewer. + +Present the proposed split via the Classification block below. + +Display the proposed classification as two numbered lists. Use the comment numbers from the Step 3 unresolved-comments display so the user does not need to look up identifiers. + +~~~ +## Classification (proposed) + +Deferred (): + . : — @ — "" + reason: + ... + +Normal (): + + +Reply with one of: + OK + move →normal + move →deferred + exclude +~~~ + +Emit the block as plain text and read free-form input. Re-render the block after each edit until the user replies `OK`. + +Repeat the presentation, accepting `move →normal`, `move →deferred`, `exclude `, or `OK`, until the user types `OK`. Excluded comments are dropped from both buckets (matches the existing exclude behaviour). + +## Step 4: Create Tasks & Resolve Comments + +Track each unresolved comment as a separate work item and address them sequentially. + +### 4.0 Reply/Resolve Permission (one-time per project) + +Read the project memory `pr-comments-resolver-platform`. If the field `Reply/Resolve permission` is absent, ask the user once via AskUserQuestion: + +- `a` — post replies AND resolve threads on my behalf +- `b` — post replies only (you resolve manually) +- `c` — no, I'll handle posting and resolving myself + +Persist the answer in the same project memory written by Step 1.5 (`pr-comments-resolver-platform`). On later runs, skip this prompt unless the user explicitly resets. + +Apply the chosen permission in **every** reply/resolve interaction that follows in Step 4 and Step 4b, including the no-code-change path (post a short justification → `a`: reply + resolve, `b`: reply only, `c`: show the justification to the user). + +### 4.0.1 Clarification Routine + +When a comment is unclear, ask **one** short clarifying question. Before asking, scan prior user answers in the current session — if the answer is already implied, state the inferred assumption and continue instead of asking. Keep clarifications terse; expand only on explicit request. Add a one-line example when the question itself is ambiguous. + +Then work through each task sequentially: + +1. **Read the affected file** at the referenced location +2. **Understand the comment** in the context of the surrounding code +3. If the comment is marked `(outdated)`, check whether the feedback is still relevant before acting +4. **If unclear**: Ask the user what exactly is expected. Ask the user directly in chat with the listed options. +5. **Implement the change** according to the reviewer's feedback +6. **Mark the task as completed** + +Important: +- Work through comments sequentially, not in parallel — changes may overlap in the same file +- Follow conventions from AGENTS.md if present in the project +- Respect existing code patterns and architecture in the project + +## Step 4b: Resolve Deferred Bucket + +If the deferred bucket from Step 3.5 is empty, skip this step entirely. + +Otherwise announce: "Now handling N deferred items." Process items strictly in the order shown in the Step 3.5 list, one at a time. + +For each deferred item: + +1. Detect which design skills are visible to the running agent: + + These harnesses do not currently expose a skills registry; assume `[s]` and `[b]` are unavailable. Show them marked unavailable; allow the user to type a path to a local skill file if they want to invoke one manually. Record this as a transient session fact — do NOT persist it. + +2. Ask the user how to handle this specific item. Present five options; unavailable skills are shown but marked unavailable: + + - `[s]` use SDD (spec → plan → tasks) + - `[b]` use Brainstorming skill + - `[p]` enter plan mode (built-in) + - `[d]` just do it (no design skill — agent proceeds inline) + - `[x]` skip this item (recorded as deferred-skipped in the summary) + +3. Execute the chosen route. `s`/`b` invoke the corresponding skill; `p` activates plan mode and waits for ExitPlanMode; `d` follows the normal Step 4 inline path; `x` records the skip and continues. + +4. After the route completes, apply the Reply/Resolve permission from Step 4.0 exactly as in the normal flow. + +## Step 5: Verification + +After all comments have been addressed, run project-defined verification commands. + +### 5.1 Find Verification Commands + +Check the project's AGENTS.md for defined verification commands (linting, static analysis, tests). Look for sections like "Commands", "Scripts", "Testing", or similar. + +Examples of what you might find: +- PHP: `task cs-fixer`, `task psalm`, `task test` +- JavaScript/TypeScript: `npm run lint`, `npm test` +- Python: `ruff check .`, `pytest` +- Go: `go vet ./...`, `go test ./...` + +### 5.2 Run Verification + +If verification commands are found in AGENTS.md, run them in order. + +If no verification commands are found, ask the user (offer a "skip verification" option as well): Ask the user directly in chat with the listed options. +> "What verification commands should I run for this project? (e.g., lint, tests, type checks)" + +### 5.3 Fix Issues + +If any verification step fails: +1. Analyze the error output +2. Fix the issue +3. Re-run the failing verification command +4. Repeat until all checks pass + +## Step 6: Self-Review + +Review all changes made: + +```bash +git diff +``` + +Check for: + +### Reusability +- Is existing code reused instead of duplicated? +- Are new abstractions justified or unnecessary? + +### Code Quality +- Is the code clear and understandable? +- Does it follow existing patterns in the project? + +### Security +- No SQL injection, XSS, command injection, or other OWASP Top 10 vulnerabilities? +- Are inputs validated at system boundaries? +- No secrets or sensitive data in the code? + +### Project-Specific Conventions +Check any project-specific conventions and patterns defined in the project's AGENTS.md. The checks above are universal — defer to whatever the project documents for language- or framework-specific rules. + +If you find issues during self-review, fix them immediately and re-run verification from Step 5. + +## Step 7: Summary + +Show the user a summary of the work done: + +- **Comments addressed**: List each comment with file path, line number, and what was changed +- **Files modified**: List each file with a brief description of changes +- **Verification results**: Which commands ran and their pass/fail status +- **Self-review results**: Any issues found and fixed during self-review +- **Unresolved comments**: If any comments could not be addressed, state the reason (e.g., unclear intent, requires architectural change, blocked by external dependency) diff --git a/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/azure.md b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/azure.md new file mode 100644 index 0000000..143d29b --- /dev/null +++ b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/azure.md @@ -0,0 +1,109 @@ +# Platform Module: Azure DevOps + +This module is loaded by the orchestrator when the detected platform is `azure` (remote URL contains `dev.azure.com` or `visualstudio.com`). + +## Auth method + +Routed by the orchestrator (kernel Step 1.3). Follow **Path A (CLI)** or **Path B (MCP)** below according to the `Auth method` value recorded in memory for this repository. + +For reference, the two options the orchestrator presents are: + +- `CLI (az + azure-devops extension)` — uses `az login` (or `az devops login` with a PAT). +- `MCP (@azure-devops/mcp)` — PAT-based MCP server via `npx`, configured with an env-variable reference (no secret on disk). + +## Path A — CLI (az) + +### Auth verification + +```bash +az --version +az extension show --name azure-devops +az account show +``` + +Any failure → instruct: + +- Install the Azure CLI: https://learn.microsoft.com/cli/azure/install-azure-cli +- `az extension add --name azure-devops` +- `az login` (or `az devops login` if you prefer PAT-based auth — this is informational only, the skill does not automate it) + +Then stop. + +### Repository identifier + +Parse `https://dev.azure.com///_git/` into `//`. Variations like `https://.visualstudio.com//_git/` should also be handled — extract ``, ``, `` consistently. + +### PR number (if not provided) + +```bash +az repos pr list --repository --output json +``` + +Match against the current branch. If there is exactly one match, use it. Otherwise ask the user. Ask the user directly in chat with the listed options. + +### Fetch unresolved threads + +```bash +az repos pr show --id --output json +``` + +For each thread, fetch comments via the Azure DevOps REST API through `az rest` (the `az repos pr` surface for threads is limited): + +```bash +az rest --method get --url "https://dev.azure.com///_apis/git/repositories//pullRequests//threads?api-version=7.1" +``` + +Filter on threads whose `status` is not `closed`, `fixed`, `wontFix`, or `byDesign`. Map to the uniform comment shape. + +### Post reply / resolve thread + +Use `az rest` against: + +- `POST .../pullRequests//threads//comments` to reply. +- `PATCH .../pullRequests//threads/` with body `{"status": "fixed"}` to resolve. + +Exact request bodies are verified at execution time against the installed Azure DevOps REST API version. + +## Path B — MCP (@azure-devops/mcp) + +### Prompts (in order) + +1. Ask: "Azure DevOps organisation name?" (free-text, required). Ask the user directly in chat with the listed options. +2. Ask: "Name of the env variable holding your PAT?" — offer `AZURE_DEVOPS_PAT` as the default and let the user pick another name. Ask the user directly in chat with the listed options. + +### Env-var presence check + +Read the chosen env variable from the current process environment. If unset, tell the user how to set it in their shell profile, for example: + +```bash +echo 'export AZURE_DEVOPS_PAT=...' >> ~/.zshrc +source ~/.zshrc +``` + +Then stop the skill and instruct them to re-run after the variable is in place. Do not write the MCP config until the env variable is set. + +### Setup + +Invoke the MCP Config Writer (see Step 1.5 of the orchestrator) with this entry, substituting `` and ``: + +```json +{ + "mcpServers": { + "ado": { + "command": "npx", + "args": ["-y", "@azure-devops/mcp", "", "--authentication", "pat"], + "env": { + "PERSONAL_ACCESS_TOKEN": "${}" + } + } + } +} +``` + +Persist memory: `Auth method: mcp`, `MCP server id: ado`, `Org / Workspace: `, `Token env var: $`. **Never persist the token value.** + +After the writer completes, tell the user to restart Claude Code, then stop the skill. + +### Repository identifier, comment fetch, replies, resolves + +Use the `ado` MCP tools (names like `pull_request_get_comments`, `pull_request_create_comment`, `pull_request_resolve_thread` — verified at execution time against the live MCP inventory). Map results to the uniform comment shape. diff --git a/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md new file mode 100644 index 0000000..c19ac32 --- /dev/null +++ b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md @@ -0,0 +1,76 @@ +# Platform Module: Bitbucket Cloud + +This module is loaded by the orchestrator when the detected platform is `bitbucket` (remote URL contains `bitbucket.org`). + +## Auth method + +Routed by the orchestrator (kernel Step 1.3). Follow **Path A (CLI)** or **Path B (MCP)** below according to the `Auth method` value recorded in memory for this repository. + +For reference, the two options the orchestrator presents are: + +- `CLI (acli)` — Atlassian's command-line tool, uses local auth tokens managed by `acli auth login`. +- `MCP (Atlassian Remote)` — official OAuth-based MCP server at `https://mcp.atlassian.com/v1/sse`. No PAT required; OAuth happens in the browser on first MCP tool call. + +## Path A — CLI (acli) + +### Auth verification + +```bash +acli auth status +``` + +- Missing CLI: "Install acli from https://developer.atlassian.com/cloud/acli/ and run `acli auth login`". Then stop. +- Not authenticated: "Run `acli auth login`". Then stop. + +### Repository identifier + +Parse the remote URL `https://bitbucket.org//` into `/`. + +### PR number (if not provided) + +Use `acli` to list open PRs scoped to the current branch: + +```bash +acli bitbucket pr list --repository / +``` + +(Exact subcommand surface depends on the installed `acli` version — verify against `acli bitbucket pr --help` at execution time.) Match the result against the current branch; if there are zero or multiple matches, ask the user. Ask the user directly in chat with the listed options. + +### Fetch unresolved comments + +```bash +acli bitbucket pr comments --repository / --id +``` + +(Exact subcommand verified at execution time.) Map the response to the uniform `{id, file, line, author, body, thread_id, resolved}` shape. Filter to `resolved: false`. + +### Post reply / resolve thread + +Use the `acli` PR comment reply and resolve subcommands. Exact command names are verified at execution time against the installed version. + +## Path B — MCP (Atlassian Remote) + +### Auth verification + +Check whether Atlassian MCP tools (e.g. tools whose names begin with `atlassian_` or contain `bitbucket_pr_`) are present in the current tool inventory. If yes → proceed to the operations below. If no → run the setup step. + +### Setup + +Invoke the MCP Config Writer (see Step 1.5 of the orchestrator) with this entry: + +```json +{ + "mcpServers": { + "atlassian": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.atlassian.com/v1/sse"] + } + } +} +``` + +No PAT prompt — OAuth is used. The user authenticates in the browser on first MCP tool call. After the Config Writer writes the entry, persist memory with `Auth method: mcp`, `MCP server id: atlassian`, no `Token env var`. Tell the user to restart Claude Code and complete the OAuth flow on first invocation. Stop the skill. + +### Repository identifier, comment fetch, replies, resolves + +Use the Atlassian MCP tools for Bitbucket PR threads. Exact tool names are verified against the live MCP inventory at execution time, then mapped to the uniform comment shape. diff --git a/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/github.md b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/github.md new file mode 100644 index 0000000..bfd99bf --- /dev/null +++ b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/github.md @@ -0,0 +1,67 @@ +# Platform Module: GitHub + +This module is loaded by the orchestrator when the detected platform is `github`. Read it once when dispatched and follow the steps in order. + +## Auth verification + +Run: +```bash +gh auth status +``` + +If the CLI is not installed: "Install the GitHub CLI: https://cli.github.com/ — then run `gh auth login`". Then stop. +If installed but not authenticated: "Run `gh auth login`". Then stop. + +## Repository identifier + +```bash +gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"' +``` +Format: `/`. + +## PR number (if not provided by user) + +```bash +gh pr view --json number,title --jq '"\(.number) \(.title)"' +``` + +## Fetch unresolved review threads + +Load all review threads via the GraphQL API. The `isResolved` status is only available through GraphQL. + +```bash +gh api graphql -f query=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + title + url + reviewThreads(first: 100) { + nodes { + isResolved + isOutdated + path + line + startLine + comments(first: 50) { + nodes { + author { login } + body + createdAt + url + } + } + } + } + } + } +}' -F owner=OWNER -F repo=REPO -F pr=PR_NUMBER +``` + +Replace `OWNER`, `REPO`, and `PR_NUMBER` with the values from the orchestrator. + +Filter: keep only threads where `isResolved` is `false`. Use `isOutdated` to mark `(outdated)` in the display. + +## Post reply and resolve thread + +To post a reply to a review thread, use `gh api` against the GraphQL `addPullRequestReviewThreadReply` mutation, then call `resolveReviewThread`. Exact mutation calls are looked up at execution time against the installed `gh` version. diff --git a/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md new file mode 100644 index 0000000..d7dd54e --- /dev/null +++ b/plugins/augment/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md @@ -0,0 +1,49 @@ +# Platform Module: GitLab + +This module is loaded by the orchestrator when the detected platform is `gitlab`. + +## Auth verification + +```bash +glab auth status +``` + +Missing CLI: "Install the GitLab CLI: https://gitlab.com/gitlab-org/cli — then run `glab auth login`". Then stop. +Not authenticated: "Run `glab auth login`". Then stop. + +## Repository identifier + +```bash +glab repo view --output json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['full_name'])" +``` +Format: `/`. + +## MR IID (if not provided) + +```bash +glab mr view --output json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['iid'], d['title'])" +``` + +## Fetch unresolved discussions + +```bash +glab api "projects/:id/merge_requests/MR_IID/discussions" +``` + +Replace `MR_IID` with the merge request IID. The `:id` is automatically resolved by `glab` to the current project. + +Filter: +- Keep discussions where at least one note has `resolvable: true` AND `resolved: false`. +- Skip discussions where all resolvable notes are `resolved: true`. + +Field mapping: +- `position.new_path` → file path +- `position.new_line` → line number +- `note.author.username` → author +- `note.body` → comment body + +**Outdated:** GitLab has no `isOutdated`. If `position` is `null`, mark `(outdated)`. Best-effort heuristic. + +## Post reply and resolve discussion + +Use `glab api` POST against the discussion notes endpoint to reply, and PUT against the discussion to set `resolved: true`. Exact endpoints are looked up at execution time against the installed `glab` version. diff --git a/plugins/claude/pr-comments-resolver/.claude-plugin/plugin.json b/plugins/claude/pr-comments-resolver/.claude-plugin/plugin.json new file mode 100644 index 0000000..3c147d1 --- /dev/null +++ b/plugins/claude/pr-comments-resolver/.claude-plugin/plugin.json @@ -0,0 +1,24 @@ +{ + "name": "pr-comments-resolver", + "version": "1.1.3", + "description": "Resolve unresolved PR/MR review comments across GitHub, GitLab, Bitbucket Cloud, and Azure DevOps", + "author": { + "name": "Marcel Strahl @ Dropelikeit", + "email": "support@marcel-strahl.de", + "url": "https://github.com/Dropelikeit" + }, + "homepage": "https://github.com/Dropelikeit/pr-comments-resolver", + "repository": "https://github.com/Dropelikeit/pr-comments-resolver", + "license": "MIT", + "icon": "icon.png", + "keywords": [ + "pr", + "code-review", + "github", + "gitlab", + "bitbucket", + "azure-devops", + "merge-request", + "review" + ] +} diff --git a/plugins/claude/pr-comments-resolver/icon.png b/plugins/claude/pr-comments-resolver/icon.png new file mode 100644 index 0000000..e09bdd1 Binary files /dev/null and b/plugins/claude/pr-comments-resolver/icon.png differ diff --git a/plugins/claude/pr-comments-resolver/skills/resolve-comments/SKILL.md b/plugins/claude/pr-comments-resolver/skills/resolve-comments/SKILL.md new file mode 100644 index 0000000..ca31316 --- /dev/null +++ b/plugins/claude/pr-comments-resolver/skills/resolve-comments/SKILL.md @@ -0,0 +1,320 @@ +--- +name: resolve-comments +description: Use when resolving unresolved PR or MR review comments, working through reviewer feedback, or addressing code review threads on GitHub, GitLab, Bitbucket Cloud, or Azure DevOps repositories +trigger: /resolve-comments +--- + +# Resolve PR/MR Review Comments + +Work through all unresolved review comments from a pull request or merge request on GitHub, GitLab, Bitbucket Cloud, or Azure DevOps. + +## Step 1: Platform Detection & CLI Verification + +### 1.1 Check Memory + +Check the agent's persistent memory (if available) for a previously saved `pr-comments-resolver-platform` configuration. If found, run a quick auth verification using the recorded `Auth method` and the platform module's `Auth verification` section. + +If the memory exists and auth is healthy, skip to Step 1.6 (Load Platform Module). + +If the memory is stale (auth fails) or not found, continue with detection. + +**Back-compat:** memories from older versions may not contain an `Auth method` field. Treat a missing `Auth method` as `cli`. + +### 1.2 Detect Platform + +Get the remote URL: + +```bash +git remote get-url origin +``` + +Match the URL against known patterns: + +| URL Contains | Platform | +|---|---| +| `github.com` | GitHub | +| `gitlab.com` | GitLab | +| `bitbucket.org` | Bitbucket Cloud | +| `dev.azure.com` or `visualstudio.com` | Azure DevOps | + +If the URL does not match any known pattern (e.g., a self-hosted instance), ask the user which platform this repository is hosted on. Offer the options: GitHub, GitLab, Bitbucket Cloud, Azure DevOps, Other. Use AskUserQuestion to present the options. + +If the user picks "Other", inform them: "This skill currently supports GitHub, GitLab, Bitbucket Cloud, and Azure DevOps. Other hosting platforms are not yet supported." Then stop. + +### 1.3 Select Auth Method (Bitbucket and Azure only) + +For `bitbucket` and `azure`, if memory does not already record an `Auth method`, ask the user which method to use. Use AskUserQuestion to present the options. + +Options: + +- **Bitbucket**: `CLI (acli)` or `MCP (Atlassian Remote, OAuth)`. +- **Azure DevOps**: `CLI (az + azure-devops extension)` or `MCP (@azure-devops/mcp, PAT-based)`. + +For `github` and `gitlab`, `Auth method` is always `cli` — no prompt is shown. + +Remember the chosen value as `Auth method` (it gets written to memory in Step 1.5). + +### 1.4 Verify Auth + +Use the platform module's `Auth verification` section, following the path that matches the chosen `Auth method` (Path A for `cli`, Path B for `mcp`). If auth is not healthy, follow the module's stop-with-instructions guidance. + +### 1.5 Persist Platform (if supported) + +After successful detection and CLI verification (and, for bitbucket/azure, auth-method selection), save a project memory: + +~~~markdown +--- +name: pr-comments-resolver-platform +description: Detected hosting platform, auth method, and identifier for this repository +type: project +--- + +Platform: +Auth method: +CLI tool: # only when Auth method = cli +MCP server id: # only when Auth method = mcp +Token env var: $ # only when MCP auth uses a PAT (e.g. azure mcp); omit for OAuth (atlassian) and all cli paths +Org / Workspace: # bitbucket workspace or azure organization; omit for github/gitlab +Repository: +Reply/Resolve permission: # a = post & resolve, b = post only, c = none +~~~ + +> Back-compat: memories saved by older versions of this skill may lack `Auth method`. When that field is missing, treat it as `cli`. +> +> Back-compat: memories without `Reply/Resolve permission` trigger the one-time Step 4.0 prompt. + +### 1.6 Load Platform Module + +Read the file `platforms/.md` (relative to this SKILL.md). It contains the platform-specific instructions for auth verification, repository identifier, PR/MR number detection, comment fetching, posting replies, and resolving threads. Use it as the authoritative source for those operations throughout the rest of this skill. + +Platform modules may invoke the MCP Config Writer for setting up an MCP server. The writer's procedure is: + +### MCP Config Writer + +When a platform module needs to add an MCP server entry, follow this procedure exactly. Do not silently overwrite existing configuration. + +**Target file selection.** Ask the user where to write the config: + +- User scope: `~/.claude.json` (default) +- Project scope: `.mcp.json` in the repository root + +Use the AskUserQuestion helper. + +**Procedure:** + +1. Read the target file. If it does not exist, treat the starting content as `{"mcpServers": {}}`. +2. If `mcpServers.` does not exist: insert the new entry and write the file back. Inform the user where the entry was added. +3. If `mcpServers.` already exists: + 1. Compute the diff between the existing entry and the entry we intend to write. + 2. If identical: no-op. Inform the user "MCP entry already present and matches; nothing to write." + 3. If different: show the diff to the user and ask via AskUserQuestion: `Overwrite` / `Keep existing` / `Abort`. Apply the chosen action. + +**Secret handling.** + +- Never write a token literal into the config. Use `${ENV_VAR_NAME}` placeholders in the `env` section. +- Verify the named env variable is set in the current shell environment before writing. If unset, instruct the user to add it to their shell profile (e.g. `export AZURE_DEVOPS_PAT=...` in `~/.zshrc`), then stop the skill until they confirm. + +**Restart notice.** + +After writing, tell the user: "MCP server configured. Restart Claude Code to load the new server. Re-run `/resolve-comments` afterwards." Stop the skill in this session. + +### 1.7 Get Repository Identifier + +See the platform module's `Repository identifier` section. + +## Step 2: Determine PR/MR Number + +If `$ARGUMENTS` is provided, use it as the PR/MR number. + +If `$ARGUMENTS` is empty or not provided, detect automatically from the current branch. See the platform module's `PR number` (or `MR IID`) section. + +If no PR/MR exists for the current branch, ask the user for the PR/MR number. Use AskUserQuestion to present the options. + +## Step 3: Fetch & Display Unresolved Comments + +Use the platform module's `Fetch unresolved …` section to obtain the list of unresolved review threads/discussions and map them to the uniform `{file, line, author, body, thread_id}` shape. Then render them via the `Display Unresolved Comments` block below. + +### Display Unresolved Comments + +Show unresolved comments as a numbered list: + +``` +## Unresolved PR Comments (X of Y total) + +1. **path/to/file.ts:42** - @author + > Comment text here... + +2. **path/to/file.ts:108** - @author (outdated) + > Another comment... +``` + +The `(outdated)` marker means the code has changed since the comment was written — check relevance before acting. + +If there are no unresolved comments, inform the user and stop. + +## Step 3.5: Classify & Confirm + +Classify each unresolved comment into one of two buckets: + +- **deferred**: the comment flags a missing critical or larger piece of work — typically (a) a missing module/feature, (b) a security or correctness gap, (c) a refactor that touches more than two files, or (d) a reviewer-applied marker such as `blocker`, `critical`, or `must-fix`. +- **normal**: everything else (in-place edits within existing logic). + +Use these signals as a heuristic — the user confirms the final split: + +- **Scope**: would the fix introduce a new file/module, or change one existing function? +- **Keywords**: presence of `missing`, `not implemented`, `should also handle`, `security`, `race`, `architecture`, `refactor entire`, `add support for`, or localized equivalents. +- **Cross-file**: would the fix touch >2 files or require a design decision? +- **Severity markers**: explicit `blocker` / `critical` / `must-fix` labels or words from the reviewer. + +Present the proposed split via the Classification block below. + +Display the proposed classification as two numbered lists. Use the comment numbers from the Step 3 unresolved-comments display so the user does not need to look up identifiers. + +~~~ +## Classification (proposed) + +Deferred (): + . : — @ — "" + reason: + ... + +Normal (): + + +Reply with one of: + OK + move →normal + move →deferred + exclude +~~~ + +Use AskUserQuestion when the harness supports it; otherwise emit the block as plain text and read free-form input. Re-render the block after each edit until the user replies `OK`. + +Repeat the presentation, accepting `move →normal`, `move →deferred`, `exclude `, or `OK`, until the user types `OK`. Excluded comments are dropped from both buckets (matches the existing exclude behaviour). + +## Step 4: Create Tasks & Resolve Comments + +Create a TodoWrite task for each unresolved comment. + +### 4.0 Reply/Resolve Permission (one-time per project) + +Read the project memory `pr-comments-resolver-platform`. If the field `Reply/Resolve permission` is absent, ask the user once via AskUserQuestion: + +- `a` — post replies AND resolve threads on my behalf +- `b` — post replies only (you resolve manually) +- `c` — no, I'll handle posting and resolving myself + +Persist the answer in the same project memory written by Step 1.5 (`pr-comments-resolver-platform`). On later runs, skip this prompt unless the user explicitly resets. + +Apply the chosen permission in **every** reply/resolve interaction that follows in Step 4 and Step 4b, including the no-code-change path (post a short justification → `a`: reply + resolve, `b`: reply only, `c`: show the justification to the user). + +### 4.0.1 Clarification Routine + +When a comment is unclear, ask **one** short clarifying question. Before asking, scan prior user answers in the current session — if the answer is already implied, state the inferred assumption and continue instead of asking. Keep clarifications terse; expand only on explicit request. Add a one-line example when the question itself is ambiguous. + +Then work through each task sequentially: + +1. **Read the affected file** at the referenced location +2. **Understand the comment** in the context of the surrounding code +3. If the comment is marked `(outdated)`, check whether the feedback is still relevant before acting +4. **If unclear**: Ask the user what exactly is expected. Use AskUserQuestion to present the options. +5. **Implement the change** according to the reviewer's feedback +6. **Mark the task as completed** + +Important: +- Work through comments sequentially, not in parallel — changes may overlap in the same file +- Follow conventions from CLAUDE.md (or AGENTS.md as fallback) if present in the project +- Respect existing code patterns and architecture in the project + +## Step 4b: Resolve Deferred Bucket + +If the deferred bucket from Step 3.5 is empty, skip this step entirely. + +Otherwise announce: "Now handling N deferred items." Process items strictly in the order shown in the Step 3.5 list, one at a time. + +For each deferred item: + +1. Detect which design skills are visible to the running agent: + + Check the list of available skills surfaced by the harness. Note whether `superpowers:brainstorming` and either `sdd` or `superpowers:sdd` are present. Record this as a transient session fact — do NOT persist it; skill availability can change between sessions. + +If neither is available, only the built-in plan mode (`[p]`), inline (`[d]`), and skip (`[x]`) options are real choices; show `[s]` and `[b]` as unavailable with a one-line note ("requires the SDD / Brainstorming skill — not installed"). + +2. Ask the user how to handle this specific item. Present five options; unavailable skills are shown but marked unavailable: + + - `[s]` use SDD (spec → plan → tasks) + - `[b]` use Brainstorming skill + - `[p]` enter plan mode (built-in) + - `[d]` just do it (no design skill — agent proceeds inline) + - `[x]` skip this item (recorded as deferred-skipped in the summary) + +3. Execute the chosen route. `s`/`b` invoke the corresponding skill; `p` activates plan mode and waits for ExitPlanMode; `d` follows the normal Step 4 inline path; `x` records the skip and continues. + +4. After the route completes, apply the Reply/Resolve permission from Step 4.0 exactly as in the normal flow. + +## Step 5: Verification + +After all comments have been addressed, run project-defined verification commands. + +### 5.1 Find Verification Commands + +Check the project's CLAUDE.md (or AGENTS.md as fallback) for defined verification commands (linting, static analysis, tests). Look for sections like "Commands", "Scripts", "Testing", or similar. + +Examples of what you might find: +- PHP: `task cs-fixer`, `task psalm`, `task test` +- JavaScript/TypeScript: `npm run lint`, `npm test` +- Python: `ruff check .`, `pytest` +- Go: `go vet ./...`, `go test ./...` + +### 5.2 Run Verification + +If verification commands are found in CLAUDE.md (or AGENTS.md as fallback), run them in order. + +If no verification commands are found, ask the user (offer a "skip verification" option as well): Use AskUserQuestion to present the options. +> "What verification commands should I run for this project? (e.g., lint, tests, type checks)" + +### 5.3 Fix Issues + +If any verification step fails: +1. Analyze the error output +2. Fix the issue +3. Re-run the failing verification command +4. Repeat until all checks pass + +## Step 6: Self-Review + +Review all changes made: + +```bash +git diff +``` + +Check for: + +### Reusability +- Is existing code reused instead of duplicated? +- Are new abstractions justified or unnecessary? + +### Code Quality +- Is the code clear and understandable? +- Does it follow existing patterns in the project? + +### Security +- No SQL injection, XSS, command injection, or other OWASP Top 10 vulnerabilities? +- Are inputs validated at system boundaries? +- No secrets or sensitive data in the code? + +### Project-Specific Conventions +Check any project-specific conventions and patterns defined in the project's CLAUDE.md (or AGENTS.md as fallback). The checks above are universal — defer to whatever the project documents for language- or framework-specific rules. + +If you find issues during self-review, fix them immediately and re-run verification from Step 5. + +## Step 7: Summary + +Show the user a summary of the work done: + +- **Comments addressed**: List each comment with file path, line number, and what was changed +- **Files modified**: List each file with a brief description of changes +- **Verification results**: Which commands ran and their pass/fail status +- **Self-review results**: Any issues found and fixed during self-review +- **Unresolved comments**: If any comments could not be addressed, state the reason (e.g., unclear intent, requires architectural change, blocked by external dependency) diff --git a/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/azure.md b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/azure.md new file mode 100644 index 0000000..27f1f0b --- /dev/null +++ b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/azure.md @@ -0,0 +1,109 @@ +# Platform Module: Azure DevOps + +This module is loaded by the orchestrator when the detected platform is `azure` (remote URL contains `dev.azure.com` or `visualstudio.com`). + +## Auth method + +Routed by the orchestrator (kernel Step 1.3). Follow **Path A (CLI)** or **Path B (MCP)** below according to the `Auth method` value recorded in memory for this repository. + +For reference, the two options the orchestrator presents are: + +- `CLI (az + azure-devops extension)` — uses `az login` (or `az devops login` with a PAT). +- `MCP (@azure-devops/mcp)` — PAT-based MCP server via `npx`, configured with an env-variable reference (no secret on disk). + +## Path A — CLI (az) + +### Auth verification + +```bash +az --version +az extension show --name azure-devops +az account show +``` + +Any failure → instruct: + +- Install the Azure CLI: https://learn.microsoft.com/cli/azure/install-azure-cli +- `az extension add --name azure-devops` +- `az login` (or `az devops login` if you prefer PAT-based auth — this is informational only, the skill does not automate it) + +Then stop. + +### Repository identifier + +Parse `https://dev.azure.com///_git/` into `//`. Variations like `https://.visualstudio.com//_git/` should also be handled — extract ``, ``, `` consistently. + +### PR number (if not provided) + +```bash +az repos pr list --repository --output json +``` + +Match against the current branch. If there is exactly one match, use it. Otherwise ask the user. Use AskUserQuestion to present the options. + +### Fetch unresolved threads + +```bash +az repos pr show --id --output json +``` + +For each thread, fetch comments via the Azure DevOps REST API through `az rest` (the `az repos pr` surface for threads is limited): + +```bash +az rest --method get --url "https://dev.azure.com///_apis/git/repositories//pullRequests//threads?api-version=7.1" +``` + +Filter on threads whose `status` is not `closed`, `fixed`, `wontFix`, or `byDesign`. Map to the uniform comment shape. + +### Post reply / resolve thread + +Use `az rest` against: + +- `POST .../pullRequests//threads//comments` to reply. +- `PATCH .../pullRequests//threads/` with body `{"status": "fixed"}` to resolve. + +Exact request bodies are verified at execution time against the installed Azure DevOps REST API version. + +## Path B — MCP (@azure-devops/mcp) + +### Prompts (in order) + +1. Ask: "Azure DevOps organisation name?" (free-text, required). Use AskUserQuestion to present the options. +2. Ask: "Name of the env variable holding your PAT?" — offer `AZURE_DEVOPS_PAT` as the default and let the user pick another name. Use AskUserQuestion to present the options. + +### Env-var presence check + +Read the chosen env variable from the current process environment. If unset, tell the user how to set it in their shell profile, for example: + +```bash +echo 'export AZURE_DEVOPS_PAT=...' >> ~/.zshrc +source ~/.zshrc +``` + +Then stop the skill and instruct them to re-run after the variable is in place. Do not write the MCP config until the env variable is set. + +### Setup + +Invoke the MCP Config Writer (see Step 1.5 of the orchestrator) with this entry, substituting `` and ``: + +```json +{ + "mcpServers": { + "ado": { + "command": "npx", + "args": ["-y", "@azure-devops/mcp", "", "--authentication", "pat"], + "env": { + "PERSONAL_ACCESS_TOKEN": "${}" + } + } + } +} +``` + +Persist memory: `Auth method: mcp`, `MCP server id: ado`, `Org / Workspace: `, `Token env var: $`. **Never persist the token value.** + +After the writer completes, tell the user to restart Claude Code, then stop the skill. + +### Repository identifier, comment fetch, replies, resolves + +Use the `ado` MCP tools (names like `pull_request_get_comments`, `pull_request_create_comment`, `pull_request_resolve_thread` — verified at execution time against the live MCP inventory). Map results to the uniform comment shape. diff --git a/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md new file mode 100644 index 0000000..eaef7d4 --- /dev/null +++ b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md @@ -0,0 +1,76 @@ +# Platform Module: Bitbucket Cloud + +This module is loaded by the orchestrator when the detected platform is `bitbucket` (remote URL contains `bitbucket.org`). + +## Auth method + +Routed by the orchestrator (kernel Step 1.3). Follow **Path A (CLI)** or **Path B (MCP)** below according to the `Auth method` value recorded in memory for this repository. + +For reference, the two options the orchestrator presents are: + +- `CLI (acli)` — Atlassian's command-line tool, uses local auth tokens managed by `acli auth login`. +- `MCP (Atlassian Remote)` — official OAuth-based MCP server at `https://mcp.atlassian.com/v1/sse`. No PAT required; OAuth happens in the browser on first MCP tool call. + +## Path A — CLI (acli) + +### Auth verification + +```bash +acli auth status +``` + +- Missing CLI: "Install acli from https://developer.atlassian.com/cloud/acli/ and run `acli auth login`". Then stop. +- Not authenticated: "Run `acli auth login`". Then stop. + +### Repository identifier + +Parse the remote URL `https://bitbucket.org//` into `/`. + +### PR number (if not provided) + +Use `acli` to list open PRs scoped to the current branch: + +```bash +acli bitbucket pr list --repository / +``` + +(Exact subcommand surface depends on the installed `acli` version — verify against `acli bitbucket pr --help` at execution time.) Match the result against the current branch; if there are zero or multiple matches, ask the user. Use AskUserQuestion to present the options. + +### Fetch unresolved comments + +```bash +acli bitbucket pr comments --repository / --id +``` + +(Exact subcommand verified at execution time.) Map the response to the uniform `{id, file, line, author, body, thread_id, resolved}` shape. Filter to `resolved: false`. + +### Post reply / resolve thread + +Use the `acli` PR comment reply and resolve subcommands. Exact command names are verified at execution time against the installed version. + +## Path B — MCP (Atlassian Remote) + +### Auth verification + +Check whether Atlassian MCP tools (e.g. tools whose names begin with `atlassian_` or contain `bitbucket_pr_`) are present in the current tool inventory. If yes → proceed to the operations below. If no → run the setup step. + +### Setup + +Invoke the MCP Config Writer (see Step 1.5 of the orchestrator) with this entry: + +```json +{ + "mcpServers": { + "atlassian": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.atlassian.com/v1/sse"] + } + } +} +``` + +No PAT prompt — OAuth is used. The user authenticates in the browser on first MCP tool call. After the Config Writer writes the entry, persist memory with `Auth method: mcp`, `MCP server id: atlassian`, no `Token env var`. Tell the user to restart Claude Code and complete the OAuth flow on first invocation. Stop the skill. + +### Repository identifier, comment fetch, replies, resolves + +Use the Atlassian MCP tools for Bitbucket PR threads. Exact tool names are verified against the live MCP inventory at execution time, then mapped to the uniform comment shape. diff --git a/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/github.md b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/github.md new file mode 100644 index 0000000..bfd99bf --- /dev/null +++ b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/github.md @@ -0,0 +1,67 @@ +# Platform Module: GitHub + +This module is loaded by the orchestrator when the detected platform is `github`. Read it once when dispatched and follow the steps in order. + +## Auth verification + +Run: +```bash +gh auth status +``` + +If the CLI is not installed: "Install the GitHub CLI: https://cli.github.com/ — then run `gh auth login`". Then stop. +If installed but not authenticated: "Run `gh auth login`". Then stop. + +## Repository identifier + +```bash +gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"' +``` +Format: `/`. + +## PR number (if not provided by user) + +```bash +gh pr view --json number,title --jq '"\(.number) \(.title)"' +``` + +## Fetch unresolved review threads + +Load all review threads via the GraphQL API. The `isResolved` status is only available through GraphQL. + +```bash +gh api graphql -f query=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + title + url + reviewThreads(first: 100) { + nodes { + isResolved + isOutdated + path + line + startLine + comments(first: 50) { + nodes { + author { login } + body + createdAt + url + } + } + } + } + } + } +}' -F owner=OWNER -F repo=REPO -F pr=PR_NUMBER +``` + +Replace `OWNER`, `REPO`, and `PR_NUMBER` with the values from the orchestrator. + +Filter: keep only threads where `isResolved` is `false`. Use `isOutdated` to mark `(outdated)` in the display. + +## Post reply and resolve thread + +To post a reply to a review thread, use `gh api` against the GraphQL `addPullRequestReviewThreadReply` mutation, then call `resolveReviewThread`. Exact mutation calls are looked up at execution time against the installed `gh` version. diff --git a/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md new file mode 100644 index 0000000..d7dd54e --- /dev/null +++ b/plugins/claude/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md @@ -0,0 +1,49 @@ +# Platform Module: GitLab + +This module is loaded by the orchestrator when the detected platform is `gitlab`. + +## Auth verification + +```bash +glab auth status +``` + +Missing CLI: "Install the GitLab CLI: https://gitlab.com/gitlab-org/cli — then run `glab auth login`". Then stop. +Not authenticated: "Run `glab auth login`". Then stop. + +## Repository identifier + +```bash +glab repo view --output json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['full_name'])" +``` +Format: `/`. + +## MR IID (if not provided) + +```bash +glab mr view --output json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['iid'], d['title'])" +``` + +## Fetch unresolved discussions + +```bash +glab api "projects/:id/merge_requests/MR_IID/discussions" +``` + +Replace `MR_IID` with the merge request IID. The `:id` is automatically resolved by `glab` to the current project. + +Filter: +- Keep discussions where at least one note has `resolvable: true` AND `resolved: false`. +- Skip discussions where all resolvable notes are `resolved: true`. + +Field mapping: +- `position.new_path` → file path +- `position.new_line` → line number +- `note.author.username` → author +- `note.body` → comment body + +**Outdated:** GitLab has no `isOutdated`. If `position` is `null`, mark `(outdated)`. Best-effort heuristic. + +## Post reply and resolve discussion + +Use `glab api` POST against the discussion notes endpoint to reply, and PUT against the discussion to set `resolved: true`. Exact endpoints are looked up at execution time against the installed `glab` version. diff --git a/plugins/codex/pr-comments-resolver/.codex-plugin/plugin.json b/plugins/codex/pr-comments-resolver/.codex-plugin/plugin.json new file mode 100644 index 0000000..c73115f --- /dev/null +++ b/plugins/codex/pr-comments-resolver/.codex-plugin/plugin.json @@ -0,0 +1,40 @@ +{ + "name": "pr-comments-resolver", + "version": "1.1.3", + "description": "Resolve unresolved PR/MR review comments across GitHub, GitLab, Bitbucket Cloud, and Azure DevOps", + "author": { + "name": "Dropelikeit", + "url": "https://github.com/Dropelikeit" + }, + "homepage": "https://github.com/Dropelikeit/pr-comments-resolver", + "repository": "https://github.com/Dropelikeit/pr-comments-resolver", + "license": "MIT", + "keywords": [ + "pull-request", + "code-review", + "automation", + "github", + "gitlab", + "bitbucket", + "azure-devops" + ], + "skills": "./skills/", + "interface": { + "displayName": "PR Comments Resolver", + "shortDescription": "Resolve unresolved PR/MR review comments from Codex", + "longDescription": "Automates unresolved review comment resolution across GitHub, GitLab, Bitbucket Cloud, and Azure DevOps with configurable verification commands.", + "developerName": "Dropelikeit", + "category": "Productivity", + "websiteURL": "https://github.com/Dropelikeit/pr-comments-resolver", + "privacyPolicyURL": "https://github.com/Dropelikeit/pr-comments-resolver/blob/main/PRIVACY.md", + "termsOfServiceURL": "https://github.com/Dropelikeit/pr-comments-resolver/blob/main/LICENSE", + "defaultPrompt": [ + "Resolve unresolved review comments on my current PR.", + "Resolve unresolved comments for PR #42 and run project checks.", + "Find unresolved MR comments and fix them one by one." + ], + "brandColor": "#2563EB", + "composerIcon": "./icon.png", + "logo": "./icon.png" + } +} diff --git a/plugins/codex/pr-comments-resolver/icon.png b/plugins/codex/pr-comments-resolver/icon.png new file mode 100644 index 0000000..e09bdd1 Binary files /dev/null and b/plugins/codex/pr-comments-resolver/icon.png differ diff --git a/plugins/codex/pr-comments-resolver/skills/resolve-comments/SKILL.md b/plugins/codex/pr-comments-resolver/skills/resolve-comments/SKILL.md new file mode 100644 index 0000000..7e32016 --- /dev/null +++ b/plugins/codex/pr-comments-resolver/skills/resolve-comments/SKILL.md @@ -0,0 +1,278 @@ +--- +name: resolve-comments +description: Use when resolving unresolved PR or MR review comments, working through reviewer feedback, or addressing code review threads on GitHub, GitLab, Bitbucket Cloud, or Azure DevOps repositories +--- + +# Resolve PR/MR Review Comments + +Work through all unresolved review comments from a pull request or merge request on GitHub, GitLab, Bitbucket Cloud, or Azure DevOps. + +> Invoke this skill via `$resolve-comments` or the `/skills` command. This skill is stateless: platform detection runs on every invocation. + +## Step 1: Platform Detection & CLI Verification + +### 1.1 Check Memory + +Check the agent's persistent memory (if available) for a previously saved `pr-comments-resolver-platform` configuration. If found, run a quick auth verification using the recorded `Auth method` and the platform module's `Auth verification` section. + +If the memory exists and auth is healthy, skip to Step 1.6 (Load Platform Module). + +If the memory is stale (auth fails) or not found, continue with detection. + +**Back-compat:** memories from older versions may not contain an `Auth method` field. Treat a missing `Auth method` as `cli`. + +### 1.2 Detect Platform + +Get the remote URL: + +```bash +git remote get-url origin +``` + +Match the URL against known patterns: + +| URL Contains | Platform | +|---|---| +| `github.com` | GitHub | +| `gitlab.com` | GitLab | +| `bitbucket.org` | Bitbucket Cloud | +| `dev.azure.com` or `visualstudio.com` | Azure DevOps | + +If the URL does not match any known pattern (e.g., a self-hosted instance), ask the user which platform this repository is hosted on. Offer the options: GitHub, GitLab, Bitbucket Cloud, Azure DevOps, Other. Ask the user directly in chat with the listed options. + +If the user picks "Other", inform them: "This skill currently supports GitHub, GitLab, Bitbucket Cloud, and Azure DevOps. Other hosting platforms are not yet supported." Then stop. + +### 1.3 Select Auth Method (Bitbucket and Azure only) + +For `bitbucket` and `azure`, if memory does not already record an `Auth method`, ask the user which method to use. Ask the user directly in chat with the listed options. + +Options: + +- **Bitbucket**: `CLI (acli)` or `MCP (Atlassian Remote, OAuth)`. +- **Azure DevOps**: `CLI (az + azure-devops extension)` or `MCP (@azure-devops/mcp, PAT-based)`. + +For `github` and `gitlab`, `Auth method` is always `cli` — no prompt is shown. + +Remember the chosen value as `Auth method` (it gets written to memory in Step 1.5). + +### 1.4 Verify Auth + +Use the platform module's `Auth verification` section, following the path that matches the chosen `Auth method` (Path A for `cli`, Path B for `mcp`). If auth is not healthy, follow the module's stop-with-instructions guidance. + +### 1.5 Persist Platform (if supported) + +Codex has no persistent memory layer for skills. Skip persistence — platform detection re-runs on every invocation, and the Step 4.0 Reply/Resolve permission prompt is asked once per session. + +### 1.6 Load Platform Module + +Read the file `platforms/.md` (relative to this SKILL.md). It contains the platform-specific instructions for auth verification, repository identifier, PR/MR number detection, comment fetching, posting replies, and resolving threads. Use it as the authoritative source for those operations throughout the rest of this skill. + +Platform modules may invoke the MCP Config Writer for setting up an MCP server. The writer's procedure is: + +### MCP Config Writer + +This adapter does not currently include automatic MCP server configuration support. If a platform module requires MCP setup (Bitbucket MCP via Atlassian Remote, or Azure DevOps MCP via `@azure-devops/mcp`), instruct the user how to configure their host manually: + +- Show the user the MCP server entry the platform module wants to add (server id, command, args, and env-var-reference env block). +- Tell them to add it to their adapter's MCP configuration (e.g., Codex / Augment / Junie / Roo configuration file — exact path depends on the user's setup). +- Remind them: never paste a literal PAT into the config. Use the env-variable reference exactly as shown. +- Ask them to confirm when done, then stop and tell them to restart their agent. + +### 1.7 Get Repository Identifier + +See the platform module's `Repository identifier` section. + +## Step 2: Determine PR/MR Number + +If `$ARGUMENTS` is provided, use it as the PR/MR number. + +If `$ARGUMENTS` is empty or not provided, detect automatically from the current branch. See the platform module's `PR number` (or `MR IID`) section. + +If no PR/MR exists for the current branch, ask the user for the PR/MR number. Ask the user directly in chat with the listed options. + +## Step 3: Fetch & Display Unresolved Comments + +Use the platform module's `Fetch unresolved …` section to obtain the list of unresolved review threads/discussions and map them to the uniform `{file, line, author, body, thread_id}` shape. Then render them via the `Display Unresolved Comments` block below. + +### Display Unresolved Comments + +Show unresolved comments as a numbered list: + +``` +## Unresolved PR Comments (X of Y total) + +1. **path/to/file.ts:42** - @author + > Comment text here... + +2. **path/to/file.ts:108** - @author (outdated) + > Another comment... +``` + +The `(outdated)` marker means the code has changed since the comment was written — check relevance before acting. + +If there are no unresolved comments, inform the user and stop. + +## Step 3.5: Classify & Confirm + +Classify each unresolved comment into one of two buckets: + +- **deferred**: the comment flags a missing critical or larger piece of work — typically (a) a missing module/feature, (b) a security or correctness gap, (c) a refactor that touches more than two files, or (d) a reviewer-applied marker such as `blocker`, `critical`, or `must-fix`. +- **normal**: everything else (in-place edits within existing logic). + +Use these signals as a heuristic — the user confirms the final split: + +- **Scope**: would the fix introduce a new file/module, or change one existing function? +- **Keywords**: presence of `missing`, `not implemented`, `should also handle`, `security`, `race`, `architecture`, `refactor entire`, `add support for`, or localized equivalents. +- **Cross-file**: would the fix touch >2 files or require a design decision? +- **Severity markers**: explicit `blocker` / `critical` / `must-fix` labels or words from the reviewer. + +Present the proposed split via the Classification block below. + +Display the proposed classification as two numbered lists. Use the comment numbers from the Step 3 unresolved-comments display so the user does not need to look up identifiers. + +~~~ +## Classification (proposed) + +Deferred (): + . : — @ — "" + reason: + ... + +Normal (): + + +Reply with one of: + OK + move →normal + move →deferred + exclude +~~~ + +Emit the block as plain text and read free-form input. Re-render the block after each edit until the user replies `OK`. + +Repeat the presentation, accepting `move →normal`, `move →deferred`, `exclude `, or `OK`, until the user types `OK`. Excluded comments are dropped from both buckets (matches the existing exclude behaviour). + +## Step 4: Create Tasks & Resolve Comments + +Maintain an internal step list as you work through each comment sequentially. + +### 4.0 Reply/Resolve Permission (one-time per project) + +Read the project memory `pr-comments-resolver-platform`. If the field `Reply/Resolve permission` is absent, ask the user once via AskUserQuestion: + +- `a` — post replies AND resolve threads on my behalf +- `b` — post replies only (you resolve manually) +- `c` — no, I'll handle posting and resolving myself + +Persist the answer in the same project memory written by Step 1.5 (`pr-comments-resolver-platform`). On later runs, skip this prompt unless the user explicitly resets. + +Apply the chosen permission in **every** reply/resolve interaction that follows in Step 4 and Step 4b, including the no-code-change path (post a short justification → `a`: reply + resolve, `b`: reply only, `c`: show the justification to the user). + +### 4.0.1 Clarification Routine + +When a comment is unclear, ask **one** short clarifying question. Before asking, scan prior user answers in the current session — if the answer is already implied, state the inferred assumption and continue instead of asking. Keep clarifications terse; expand only on explicit request. Add a one-line example when the question itself is ambiguous. + +Then work through each task sequentially: + +1. **Read the affected file** at the referenced location +2. **Understand the comment** in the context of the surrounding code +3. If the comment is marked `(outdated)`, check whether the feedback is still relevant before acting +4. **If unclear**: Ask the user what exactly is expected. Ask the user directly in chat with the listed options. +5. **Implement the change** according to the reviewer's feedback +6. **Mark the task as completed** + +Important: +- Work through comments sequentially, not in parallel — changes may overlap in the same file +- Follow conventions from AGENTS.md if present in the project +- Respect existing code patterns and architecture in the project + +## Step 4b: Resolve Deferred Bucket + +If the deferred bucket from Step 3.5 is empty, skip this step entirely. + +Otherwise announce: "Now handling N deferred items." Process items strictly in the order shown in the Step 3.5 list, one at a time. + +For each deferred item: + +1. Detect which design skills are visible to the running agent: + + These harnesses do not currently expose a skills registry; assume `[s]` and `[b]` are unavailable. Show them marked unavailable; allow the user to type a path to a local skill file if they want to invoke one manually. Record this as a transient session fact — do NOT persist it. + +2. Ask the user how to handle this specific item. Present five options; unavailable skills are shown but marked unavailable: + + - `[s]` use SDD (spec → plan → tasks) + - `[b]` use Brainstorming skill + - `[p]` enter plan mode (built-in) + - `[d]` just do it (no design skill — agent proceeds inline) + - `[x]` skip this item (recorded as deferred-skipped in the summary) + +3. Execute the chosen route. `s`/`b` invoke the corresponding skill; `p` activates plan mode and waits for ExitPlanMode; `d` follows the normal Step 4 inline path; `x` records the skip and continues. + +4. After the route completes, apply the Reply/Resolve permission from Step 4.0 exactly as in the normal flow. + +## Step 5: Verification + +After all comments have been addressed, run project-defined verification commands. + +### 5.1 Find Verification Commands + +Check the project's AGENTS.md for defined verification commands (linting, static analysis, tests). Look for sections like "Commands", "Scripts", "Testing", or similar. + +Examples of what you might find: +- PHP: `task cs-fixer`, `task psalm`, `task test` +- JavaScript/TypeScript: `npm run lint`, `npm test` +- Python: `ruff check .`, `pytest` +- Go: `go vet ./...`, `go test ./...` + +### 5.2 Run Verification + +If verification commands are found in AGENTS.md, run them in order. + +If no verification commands are found, ask the user (offer a "skip verification" option as well): Ask the user directly in chat with the listed options. +> "What verification commands should I run for this project? (e.g., lint, tests, type checks)" + +### 5.3 Fix Issues + +If any verification step fails: +1. Analyze the error output +2. Fix the issue +3. Re-run the failing verification command +4. Repeat until all checks pass + +## Step 6: Self-Review + +Review all changes made: + +```bash +git diff +``` + +Check for: + +### Reusability +- Is existing code reused instead of duplicated? +- Are new abstractions justified or unnecessary? + +### Code Quality +- Is the code clear and understandable? +- Does it follow existing patterns in the project? + +### Security +- No SQL injection, XSS, command injection, or other OWASP Top 10 vulnerabilities? +- Are inputs validated at system boundaries? +- No secrets or sensitive data in the code? + +### Project-Specific Conventions +Check any project-specific conventions and patterns defined in the project's AGENTS.md. The checks above are universal — defer to whatever the project documents for language- or framework-specific rules. + +If you find issues during self-review, fix them immediately and re-run verification from Step 5. + +## Step 7: Summary + +Show the user a summary of the work done: + +- **Comments addressed**: List each comment with file path, line number, and what was changed +- **Files modified**: List each file with a brief description of changes +- **Verification results**: Which commands ran and their pass/fail status +- **Self-review results**: Any issues found and fixed during self-review +- **Unresolved comments**: If any comments could not be addressed, state the reason (e.g., unclear intent, requires architectural change, blocked by external dependency) diff --git a/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/azure.md b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/azure.md new file mode 100644 index 0000000..143d29b --- /dev/null +++ b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/azure.md @@ -0,0 +1,109 @@ +# Platform Module: Azure DevOps + +This module is loaded by the orchestrator when the detected platform is `azure` (remote URL contains `dev.azure.com` or `visualstudio.com`). + +## Auth method + +Routed by the orchestrator (kernel Step 1.3). Follow **Path A (CLI)** or **Path B (MCP)** below according to the `Auth method` value recorded in memory for this repository. + +For reference, the two options the orchestrator presents are: + +- `CLI (az + azure-devops extension)` — uses `az login` (or `az devops login` with a PAT). +- `MCP (@azure-devops/mcp)` — PAT-based MCP server via `npx`, configured with an env-variable reference (no secret on disk). + +## Path A — CLI (az) + +### Auth verification + +```bash +az --version +az extension show --name azure-devops +az account show +``` + +Any failure → instruct: + +- Install the Azure CLI: https://learn.microsoft.com/cli/azure/install-azure-cli +- `az extension add --name azure-devops` +- `az login` (or `az devops login` if you prefer PAT-based auth — this is informational only, the skill does not automate it) + +Then stop. + +### Repository identifier + +Parse `https://dev.azure.com///_git/` into `//`. Variations like `https://.visualstudio.com//_git/` should also be handled — extract ``, ``, `` consistently. + +### PR number (if not provided) + +```bash +az repos pr list --repository --output json +``` + +Match against the current branch. If there is exactly one match, use it. Otherwise ask the user. Ask the user directly in chat with the listed options. + +### Fetch unresolved threads + +```bash +az repos pr show --id --output json +``` + +For each thread, fetch comments via the Azure DevOps REST API through `az rest` (the `az repos pr` surface for threads is limited): + +```bash +az rest --method get --url "https://dev.azure.com///_apis/git/repositories//pullRequests//threads?api-version=7.1" +``` + +Filter on threads whose `status` is not `closed`, `fixed`, `wontFix`, or `byDesign`. Map to the uniform comment shape. + +### Post reply / resolve thread + +Use `az rest` against: + +- `POST .../pullRequests//threads//comments` to reply. +- `PATCH .../pullRequests//threads/` with body `{"status": "fixed"}` to resolve. + +Exact request bodies are verified at execution time against the installed Azure DevOps REST API version. + +## Path B — MCP (@azure-devops/mcp) + +### Prompts (in order) + +1. Ask: "Azure DevOps organisation name?" (free-text, required). Ask the user directly in chat with the listed options. +2. Ask: "Name of the env variable holding your PAT?" — offer `AZURE_DEVOPS_PAT` as the default and let the user pick another name. Ask the user directly in chat with the listed options. + +### Env-var presence check + +Read the chosen env variable from the current process environment. If unset, tell the user how to set it in their shell profile, for example: + +```bash +echo 'export AZURE_DEVOPS_PAT=...' >> ~/.zshrc +source ~/.zshrc +``` + +Then stop the skill and instruct them to re-run after the variable is in place. Do not write the MCP config until the env variable is set. + +### Setup + +Invoke the MCP Config Writer (see Step 1.5 of the orchestrator) with this entry, substituting `` and ``: + +```json +{ + "mcpServers": { + "ado": { + "command": "npx", + "args": ["-y", "@azure-devops/mcp", "", "--authentication", "pat"], + "env": { + "PERSONAL_ACCESS_TOKEN": "${}" + } + } + } +} +``` + +Persist memory: `Auth method: mcp`, `MCP server id: ado`, `Org / Workspace: `, `Token env var: $`. **Never persist the token value.** + +After the writer completes, tell the user to restart Claude Code, then stop the skill. + +### Repository identifier, comment fetch, replies, resolves + +Use the `ado` MCP tools (names like `pull_request_get_comments`, `pull_request_create_comment`, `pull_request_resolve_thread` — verified at execution time against the live MCP inventory). Map results to the uniform comment shape. diff --git a/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md new file mode 100644 index 0000000..c19ac32 --- /dev/null +++ b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/bitbucket.md @@ -0,0 +1,76 @@ +# Platform Module: Bitbucket Cloud + +This module is loaded by the orchestrator when the detected platform is `bitbucket` (remote URL contains `bitbucket.org`). + +## Auth method + +Routed by the orchestrator (kernel Step 1.3). Follow **Path A (CLI)** or **Path B (MCP)** below according to the `Auth method` value recorded in memory for this repository. + +For reference, the two options the orchestrator presents are: + +- `CLI (acli)` — Atlassian's command-line tool, uses local auth tokens managed by `acli auth login`. +- `MCP (Atlassian Remote)` — official OAuth-based MCP server at `https://mcp.atlassian.com/v1/sse`. No PAT required; OAuth happens in the browser on first MCP tool call. + +## Path A — CLI (acli) + +### Auth verification + +```bash +acli auth status +``` + +- Missing CLI: "Install acli from https://developer.atlassian.com/cloud/acli/ and run `acli auth login`". Then stop. +- Not authenticated: "Run `acli auth login`". Then stop. + +### Repository identifier + +Parse the remote URL `https://bitbucket.org//` into `/`. + +### PR number (if not provided) + +Use `acli` to list open PRs scoped to the current branch: + +```bash +acli bitbucket pr list --repository / +``` + +(Exact subcommand surface depends on the installed `acli` version — verify against `acli bitbucket pr --help` at execution time.) Match the result against the current branch; if there are zero or multiple matches, ask the user. Ask the user directly in chat with the listed options. + +### Fetch unresolved comments + +```bash +acli bitbucket pr comments --repository / --id +``` + +(Exact subcommand verified at execution time.) Map the response to the uniform `{id, file, line, author, body, thread_id, resolved}` shape. Filter to `resolved: false`. + +### Post reply / resolve thread + +Use the `acli` PR comment reply and resolve subcommands. Exact command names are verified at execution time against the installed version. + +## Path B — MCP (Atlassian Remote) + +### Auth verification + +Check whether Atlassian MCP tools (e.g. tools whose names begin with `atlassian_` or contain `bitbucket_pr_`) are present in the current tool inventory. If yes → proceed to the operations below. If no → run the setup step. + +### Setup + +Invoke the MCP Config Writer (see Step 1.5 of the orchestrator) with this entry: + +```json +{ + "mcpServers": { + "atlassian": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.atlassian.com/v1/sse"] + } + } +} +``` + +No PAT prompt — OAuth is used. The user authenticates in the browser on first MCP tool call. After the Config Writer writes the entry, persist memory with `Auth method: mcp`, `MCP server id: atlassian`, no `Token env var`. Tell the user to restart Claude Code and complete the OAuth flow on first invocation. Stop the skill. + +### Repository identifier, comment fetch, replies, resolves + +Use the Atlassian MCP tools for Bitbucket PR threads. Exact tool names are verified against the live MCP inventory at execution time, then mapped to the uniform comment shape. diff --git a/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/github.md b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/github.md new file mode 100644 index 0000000..bfd99bf --- /dev/null +++ b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/github.md @@ -0,0 +1,67 @@ +# Platform Module: GitHub + +This module is loaded by the orchestrator when the detected platform is `github`. Read it once when dispatched and follow the steps in order. + +## Auth verification + +Run: +```bash +gh auth status +``` + +If the CLI is not installed: "Install the GitHub CLI: https://cli.github.com/ — then run `gh auth login`". Then stop. +If installed but not authenticated: "Run `gh auth login`". Then stop. + +## Repository identifier + +```bash +gh repo view --json owner,name --jq '"\(.owner.login)/\(.name)"' +``` +Format: `/`. + +## PR number (if not provided by user) + +```bash +gh pr view --json number,title --jq '"\(.number) \(.title)"' +``` + +## Fetch unresolved review threads + +Load all review threads via the GraphQL API. The `isResolved` status is only available through GraphQL. + +```bash +gh api graphql -f query=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + title + url + reviewThreads(first: 100) { + nodes { + isResolved + isOutdated + path + line + startLine + comments(first: 50) { + nodes { + author { login } + body + createdAt + url + } + } + } + } + } + } +}' -F owner=OWNER -F repo=REPO -F pr=PR_NUMBER +``` + +Replace `OWNER`, `REPO`, and `PR_NUMBER` with the values from the orchestrator. + +Filter: keep only threads where `isResolved` is `false`. Use `isOutdated` to mark `(outdated)` in the display. + +## Post reply and resolve thread + +To post a reply to a review thread, use `gh api` against the GraphQL `addPullRequestReviewThreadReply` mutation, then call `resolveReviewThread`. Exact mutation calls are looked up at execution time against the installed `gh` version. diff --git a/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md new file mode 100644 index 0000000..d7dd54e --- /dev/null +++ b/plugins/codex/pr-comments-resolver/skills/resolve-comments/platforms/gitlab.md @@ -0,0 +1,49 @@ +# Platform Module: GitLab + +This module is loaded by the orchestrator when the detected platform is `gitlab`. + +## Auth verification + +```bash +glab auth status +``` + +Missing CLI: "Install the GitLab CLI: https://gitlab.com/gitlab-org/cli — then run `glab auth login`". Then stop. +Not authenticated: "Run `glab auth login`". Then stop. + +## Repository identifier + +```bash +glab repo view --output json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['full_name'])" +``` +Format: `/`. + +## MR IID (if not provided) + +```bash +glab mr view --output json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['iid'], d['title'])" +``` + +## Fetch unresolved discussions + +```bash +glab api "projects/:id/merge_requests/MR_IID/discussions" +``` + +Replace `MR_IID` with the merge request IID. The `:id` is automatically resolved by `glab` to the current project. + +Filter: +- Keep discussions where at least one note has `resolvable: true` AND `resolved: false`. +- Skip discussions where all resolvable notes are `resolved: true`. + +Field mapping: +- `position.new_path` → file path +- `position.new_line` → line number +- `note.author.username` → author +- `note.body` → comment body + +**Outdated:** GitLab has no `isOutdated`. If `position` is `null`, mark `(outdated)`. Best-effort heuristic. + +## Post reply and resolve discussion + +Use `glab api` POST against the discussion notes endpoint to reply, and PUT against the discussion to set `resolved: true`. Exact endpoints are looked up at execution time against the installed `glab` version. diff --git a/scripts/build.sh b/scripts/build.sh index ad9865f..056121b 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -18,6 +18,71 @@ out_path_for() { esac } +plugin_package_dir_for() { + case "$1" in + claude) echo "plugins/claude/pr-comments-resolver" ;; + codex) echo "plugins/codex/pr-comments-resolver" ;; + augment) echo "plugins/augment/pr-comments-resolver" ;; + *) return 1 ;; + esac +} + +plugin_manifest_dir_for() { + case "$1" in + claude) echo ".claude-plugin" ;; + codex) echo ".codex-plugin" ;; + augment) echo ".augment-plugin" ;; + *) return 1 ;; + esac +} + +plugin_manifest_src_for() { + case "$1" in + claude) echo ".claude-plugin/plugin.json" ;; + codex) echo ".codex-plugin/plugin.json" ;; + augment) echo ".augment-plugin/plugin.json" ;; + *) return 1 ;; + esac +} + +skill_root_dir_for() { + case "$1" in + claude) echo "skills" ;; + codex) echo "dist/codex/skills" ;; + augment) echo "dist/augment/skills" ;; + junie) echo "dist/junie/.junie/skills" ;; + roo) echo "dist/roo/.roo/skills" ;; + *) return 1 ;; + esac +} + +package_marketplace_plugin() { + local agent="$1" + local package_dir + local manifest_dir + local manifest_src + local tmp_manifest + + package_dir="$(plugin_package_dir_for "$agent")" || return 0 + manifest_dir="$(plugin_manifest_dir_for "$agent")" + manifest_src="$(plugin_manifest_src_for "$agent")" + + mkdir -p "$package_dir/$manifest_dir" "$package_dir/skills" + rm -rf "$package_dir/skills/resolve-comments" + cp -R "$(skill_root_dir_for "$agent")/resolve-comments" "$package_dir/skills/" + cp icon.png "$package_dir/icon.png" + + tmp_manifest="$package_dir/$manifest_dir/plugin.json" + cp "$manifest_src" "$tmp_manifest" + + case "$agent" in + codex|augment) + sed -i.bak 's#"skills": "\./dist/[a-z]*/skills/"#"skills": "./skills/"#' "$tmp_manifest" + rm -f "$tmp_manifest.bak" + ;; + esac +} + build_one() { local agent="$1" local adapter_dir="adapters/${agent}" @@ -42,6 +107,7 @@ build_one() { echo "Built $agent -> $out" build_platforms "$agent" + package_marketplace_plugin "$agent" } build_platforms() { diff --git a/scripts/validate.py b/scripts/validate.py index d488753..1251b2b 100755 --- a/scripts/validate.py +++ b/scripts/validate.py @@ -21,6 +21,21 @@ "roo": ROOT / "dist/roo/.roo/skills/resolve-comments/SKILL.md", } +PLUGIN_BUNDLES = { + "claude": { + "manifest": ROOT / "plugins/claude/pr-comments-resolver/.claude-plugin/plugin.json", + "skill": ROOT / "plugins/claude/pr-comments-resolver/skills/resolve-comments/SKILL.md", + }, + "codex": { + "manifest": ROOT / "plugins/codex/pr-comments-resolver/.codex-plugin/plugin.json", + "skill": ROOT / "plugins/codex/pr-comments-resolver/skills/resolve-comments/SKILL.md", + }, + "augment": { + "manifest": ROOT / "plugins/augment/pr-comments-resolver/.augment-plugin/plugin.json", + "skill": ROOT / "plugins/augment/pr-comments-resolver/skills/resolve-comments/SKILL.md", + }, +} + PLATFORM_NAMES = ["github", "gitlab", "bitbucket", "azure"] errors = [] @@ -97,12 +112,26 @@ def validate_platform_files(): errors.append(f"{p}: empty file") +def validate_plugin_bundles(): + for agent, bundle in PLUGIN_BUNDLES.items(): + manifest = bundle["manifest"] + skill = bundle["skill"] + if not manifest.exists(): + errors.append(f"{agent}: plugin bundle manifest missing at {manifest}") + if not skill.exists(): + errors.append(f"{agent}: plugin bundle skill missing at {skill}") + continue + if "