From 34a79543471548d22daea1147b6a9076e848c678 Mon Sep 17 00:00:00 2001 From: Rex Lorenzo Date: Mon, 25 May 2026 23:40:49 -0700 Subject: [PATCH] feat: add Antigravity CLI support and Gemini EOL migration notice - Package skills as an Antigravity plugin under .antigravity/ and install via `agy plugin install`; review loops dispatch through the `agy` binary via a new agent-to-command mapping. - Surface a deprecation warning when Gemini CLI is detected, since free/Pro/Ultra tiers migrate to Antigravity CLI on 2026-06-18. --- .antigravity/plugin.json | 5 + .antigravity/skills/code-refinement/SKILL.md | 16 ++ .antigravity/skills/code-review/SKILL.md | 109 +++++++++++++ .antigravity/skills/commitmsg/SKILL.md | 34 ++++ .../skills/dependency-review/SKILL.md | 148 ++++++++++++++++++ .antigravity/skills/review-pr/SKILL.md | 94 +++++++++++ .gitignore | 2 + README.md | 10 +- bin/code-review-loop | 2 +- bin/plan-review-loop | 2 +- lib/lib-review-loop | 47 ++++-- setup | 111 ++++++++++--- test/lib-review-loop.bats | 2 +- test/smoke | 5 +- 14 files changed, 548 insertions(+), 39 deletions(-) create mode 100644 .antigravity/plugin.json create mode 100644 .antigravity/skills/code-refinement/SKILL.md create mode 100644 .antigravity/skills/code-review/SKILL.md create mode 100644 .antigravity/skills/commitmsg/SKILL.md create mode 100644 .antigravity/skills/dependency-review/SKILL.md create mode 100644 .antigravity/skills/review-pr/SKILL.md create mode 100644 .gitignore diff --git a/.antigravity/plugin.json b/.antigravity/plugin.json new file mode 100644 index 0000000..f549289 --- /dev/null +++ b/.antigravity/plugin.json @@ -0,0 +1,5 @@ +{ + "name": "ai-coding-setup", + "version": "0.1.0", + "description": "Set of skills to aid in utilizing Antigravity CLI in development workflows." +} diff --git a/.antigravity/skills/code-refinement/SKILL.md b/.antigravity/skills/code-refinement/SKILL.md new file mode 100644 index 0000000..bd9117e --- /dev/null +++ b/.antigravity/skills/code-refinement/SKILL.md @@ -0,0 +1,16 @@ +--- +name: code-refinement +description: "Review staged files for code quality (KISS, DRY, YAGNI, Clean Code) and fix linting issues." +--- + +# Code Refinement + +Review the staged files to ensure the changes adhere to the KISS, DRY, and YAGNI principles. Confirm that Clean Code standards are met (including clear, consistent naming and comments where needed). + +Check for opportunities to use established framework utilities, composables, or library functions instead of hand-rolled logic. If the staged code reimplements behavior that the project's framework or core libraries already provide, flag it and suggest the existing alternative. + +Verify that the project's UI framework components and utility classes are used where appropriate instead of custom CSS or HTML elements. Flag any custom styling that duplicates what the framework already provides. + +Run the project's linting command and fix all reported errors and warnings. Avoid using lint-suppression comments (e.g., eslint-disable, noqa, @ts-ignore) to make the lint pass unless absolutely necessary, and only with a clear justification in the code. + +Review tests and code coverage: check whether existing tests adequately cover the new or modified code, identify any gaps where additional tests are needed, and determine whether any existing tests must be updated to handle the new behavior correctly. When finished, ensure everything is ready for a high-quality code review. diff --git a/.antigravity/skills/code-review/SKILL.md b/.antigravity/skills/code-review/SKILL.md new file mode 100644 index 0000000..53c7e13 --- /dev/null +++ b/.antigravity/skills/code-review/SKILL.md @@ -0,0 +1,109 @@ +--- +name: code-review +description: "Review staged changes for security, correctness, performance, and clarity. Writes findings to agent-code-review.md." +--- + +# Role + +You are a senior code reviewer and security expert. You are tech stack agnostic and adapt your review to the project's languages and frameworks. +You only read and analyze the code — you must never modify any source code files in the repository. +The sole exception is writing your review output into a Markdown file. +You never ask the user what to do next and you produce exactly one review report per run. + +## Output Location + +- Always write your complete review to a file named `agent-code-review.md` in the project root. +- Overwrite the file completely on each run — do not append. +- This file is the only file you may create or modify. +- Do not stage, commit, or push this file. + +## Iterative Review Behavior + +- On each run, treat the task as a fresh review of the currently staged changes. +- Continue reviewing until there are no High or Medium severity issues and no Low severity blockers, then clearly state in the Summary that the code is good to go. + +## Scope and Inputs + +- Review only files that are currently staged in Git, not the entire repository. +- Focus on changed lines and minimal necessary surrounding context. +- Use unified diffs to compute accurate new file line numbers for comments. +- If information is missing, state reasonable assumptions and proceed. + +## How to Collect Context + +1. Verify staged files exist: git status --porcelain (look for changes in column 1) +2. Get the diff: git diff --staged --unified=0 --no-color +3. If diff is empty but status shows staged files: git diff --staged --no-color (fallback) +4. For context when needed: git diff --staged -U3 --no-color + Parse output: + - Hunk headers: @@ -oldStart,oldCount +newStart,newCount @@ + - Target line numbers from +newStart and +newCount + - File paths from diff --git lines + + Fallback if inconsistent: Always trust git status --porcelain over empty diff output. +5. For dead code detection or DRY/YAGNI opportunities, you may examine other project files (e.g., to confirm unused functions or repeated patterns). Restrict this exploration to the minimal files necessary to support the finding. + +## Review Policy + +Prioritize findings that materially improve: + +- Security, reliability, data integrity, privacy. +- Correctness and performance where clearly impactful. +- Clarity and Clean Code. + +Avoid nitpicks: + +- Do not flag purely stylistic issues unless a project style rule is clearly violated. +- Recommend formatting or lint rules only when they prevent bugs or confusion. + +## Security Checklist + +- Map each finding to OWASP Top Ten, e.g., A01 Broken Access Control, A02 Cryptographic Failures, A03 Injection, etc. +- For HTTP APIs, also consider OWASP API Top 10. +- Provide actionable mitigations. + +## Clean Code and Clarity Checks + +- Prefer small, focused functions, clear names, elimination of duplication, obvious control flow. +- Suggest local refactors near changed lines. +- Provide minimal viable patches as examples when safe. +- Identify dead code (unused variables, functions, imports, classes). +- Check for DRY violations (repeated logic or patterns that could be abstracted). +- Check for YAGNI violations (unnecessary code, abstractions, or parameters that add complexity without current value). + +## Output Format + +Write the following structure into `agent-code-review.md`: + +````markdown +# Code Review Report + +**Iteration:** N +**Date:** YYYY-MM-DD +**Scope:** Staged changes only + +## Summary + +- One paragraph on overall risk and clarity. +- Finding counts: High X, Medium Y, Low Z. +- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. + +## Findings + +For each finding: + +[Severity, Impact area] path/to/file.ext, line X or lines X-Y +- **Issue:** concise problem statement. +- **Why it matters:** link to security, maintainability, or clarity impact. +- **Recommendation:** specific, actionable fix. +- **Suggested patch example, if safe:** + +```diff +*** Begin Patch +*** Update File: path/to/file.ext +@@ +- old code ++ improved code +*** End Patch +``` +```` diff --git a/.antigravity/skills/commitmsg/SKILL.md b/.antigravity/skills/commitmsg/SKILL.md new file mode 100644 index 0000000..eb39911 --- /dev/null +++ b/.antigravity/skills/commitmsg/SKILL.md @@ -0,0 +1,34 @@ +--- +name: commitmsg +description: "Propose a single git commit message for the currently staged changes." +--- + +# Commit Message + +Propose a single git commit message for the currently staged changes. + +## Gather context + +Run these commands to understand the changes: + +- `git diff --staged` — the actual changes +- `git status -s` — staged file list +- `git log -n 20 --oneline` — recent style and to avoid repetition +- `git branch --show-current` — if it contains a ticket ID (e.g. ABC-123), prefix the subject line + +## Rules + +Use Conventional Commits. Pick the most accurate type; prefer `feat` for new behavior. Optional scope allowed. + +Subject: imperative, max 72 chars, no trailing period. Capture the big picture and intent, not implementation details. Optimize for future readers. + +Body: include bullets only when the subject alone is insufficient. Each bullet must answer "what would be unclear or risky if omitted?" Merge related items; skip internal plumbing, helpers, and test scaffolding unless they are the primary change. Wrap at 72 chars. Omit the body entirely for minor or single-focus changes. + +## Output + +```text +[ticket] type(scope): concise subject + +- Important change or impact +- Another distinct change, only if necessary +``` diff --git a/.antigravity/skills/dependency-review/SKILL.md b/.antigravity/skills/dependency-review/SKILL.md new file mode 100644 index 0000000..115d07c --- /dev/null +++ b/.antigravity/skills/dependency-review/SKILL.md @@ -0,0 +1,148 @@ +--- +name: dependency-review +description: "Audit package dependency updates for supply-chain risk: publish-age gate, changelog/diff verification, security advisories, community signals, and breaking changes." +--- + +# Package Update Supply Chain Review + +Review dependency updates to catch supply chain attacks, breaking changes, and risky packages before they land in your codebase. + +## When to Use This Skill + +Activate this review whenever a branch, PR, or working directory includes changes to dependency manifests or lockfiles. Common triggers include version bumps in package.json, requirements.txt, pyproject.toml, Gemfile, go.mod, Cargo.toml, pom.xml, build.gradle, composer.json, pubspec.yaml, or their corresponding lockfiles. + +## Review Workflow + +For each updated or newly added package, work through all five checks below. Present findings in a single summary report at the end, grouped by package. Flag any failing check as a **HOLD** and recommend the team investigate before merging. + +--- + +### 1. Publication Age Gate + +**Goal:** Confirm the release is at least 7 days old to allow the community time to discover and report compromises. + +**Steps:** + +1. Look up the package on its registry (npm, PyPI, RubyGems, crates.io, pub.dev, Maven Central, Go module proxy, Packagist, NuGet, etc.). +2. Find the publish date for the exact version being pulled in. +3. Calculate the number of days between the publish date and today. +4. If fewer than 7 days have elapsed, flag this as **HOLD - TOO NEW** and include the publish date, the age in days, and a recommendation to wait or pin to the prior version. + +**Why this matters:** Attackers who hijack a maintainer account or publish a typosquatted package are often caught within the first few days. Letting a release "bake" gives the community, automated scanners, and the maintainer time to notice anomalies. + +--- + +### 2. Changelog and Diff Verification + +**Goal:** Confirm the code changes match what the release notes claim. + +**Steps:** + +1. Locate the changelog, release notes, or GitHub releases page for the new version. +2. Identify the claimed changes (bug fixes, features, refactors, etc.). +3. Skim the actual source diff between the old and new version (use the repo's compare view, e.g. `github.com///compare/v1.2.3...v1.4.0`). +4. Look for discrepancies: Are there unexpected new files? New network calls? Obfuscated code? Post-install scripts that were not present before? +5. Pay special attention to install hooks (`preinstall`, `postinstall` in npm; `setup.py` entry points in Python; `build.rs` changes in Rust; etc.) since these execute automatically and are a top vector for supply chain attacks. + +**Red flags to call out:** + +- Minified or obfuscated source added to an otherwise readable codebase +- New outbound HTTP/DNS calls, especially to IP addresses or unusual domains +- Environment variable reads for tokens, keys, or credentials +- New native/binary dependencies or compiled assets +- Changes to CI config or build scripts that fetch remote resources + +--- + +### 3. Security Advisory Review + +**Goal:** Check whether the package or specific version has known vulnerabilities. + +**Steps:** + +1. Search the GitHub Advisory Database (GHSA), the National Vulnerability Database (NVD), and the ecosystem-specific advisory source (npm audit, pip-audit/Safety DB, RustSec, etc.) for the package name and version range. +2. Check whether the update itself is a security patch. If so, note the CVE(s) it addresses and confirm the fix is present in the version being adopted. +3. Check whether the new version introduces any new advisories. This can happen when a patch also pulls in a vulnerable transitive dependency. +4. Report findings as: **No known advisories**, **Fixes CVE-XXXX-YYYY (severity)**, or **HOLD - OPEN ADVISORY: CVE-XXXX-YYYY**. + +--- + +### 4. Community Signals + +**Goal:** See if real users are reporting problems, compromises, or regressions with this release. + +**Steps:** + +1. Check the package's GitHub Issues (filter to issues opened after the release date). +2. Search the repository's Discussions tab if available. +3. Search for the package name + version on relevant forums: Stack Overflow, Reddit (r/programming, r/node, r/python, r/rust, etc.), Hacker News, and the ecosystem's community channels (e.g. Discord servers for popular frameworks). +4. Look for patterns: multiple people reporting the same crash, unexpected behavior, or suspicious activity. +5. Note download counts and whether they are consistent with the package's historical trends. A sudden spike or drop can indicate typosquatting or an abandoned fork. + +**Report as:** A brief summary of community sentiment, or "No community issues found for this version" if clean. + +--- + +### 5. Breaking Changes and Migration Notes + +**Goal:** Identify API or behavioral changes that could break existing code. + +**Steps:** + +1. Check if the version bump follows semver. A major version bump signals intentional breaking changes. A minor or patch bump with breaking changes is a red flag on its own (either accidental or a sign of poor maintenance practices). +2. Read the migration guide or upgrade notes if one exists. +3. Look at the diff for: removed or renamed exports, changed function signatures, altered default values, removed configuration options, or dropped support for runtimes/platforms. +4. Search the codebase for usages of any changed or removed APIs. List the files and line numbers that may need updates. +5. Note any changes to the package's peer dependency requirements, minimum runtime versions (Node, Python, Ruby, etc.), or required environment variables. + +**Report as:** + +- **No breaking changes** for seamless upgrades. +- **Breaking changes detected** with a list of what changed and which files in the codebase are affected. +- **Potential breaking changes** for behavioral changes that may not cause compile/import errors but could alter runtime behavior (e.g., a default timeout changing from 30s to 5s). + +--- + +## Output Format + +Present the full review as a structured report. Here is the template: + +```text +# Package Update Review + +## Summary +- Packages reviewed: N +- Holds: N (list package names) +- Clean: N + +## Per-Package Review + +### : -> + +| Check | Status | Details | +|------------------------|--------------|----------------------------------| +| Publication age | PASS / HOLD | Published , days ago | +| Changelog verification | PASS / WARN | | +| Security advisories | PASS / HOLD | | +| Community signals | PASS / WARN | | +| Breaking changes | PASS / WARN | | + +**Recommendation:** APPROVE / HOLD / APPROVE WITH NOTES + +
+ +(Repeat for each package) +``` + +## Edge Cases + +- **New dependencies** (not just version bumps): Apply the same five checks but also verify the package is the intended one (check for typosquatting by comparing to similarly named popular packages) and review its overall maintenance health (last commit date, number of maintainers, bus factor). +- **Lockfile-only changes** with no manifest change: These can happen from transitive dependency resolution. Still review the transitive packages that changed, though a lighter touch is acceptable for patch-level transitive bumps in well-known packages. +- **Monorepos with many packages:** Group related packages (e.g., `@babel/*` or `@angular/*`) and note that they are part of a coordinated release, which reduces (but does not eliminate) the need for individual diff review. +- **Private/internal packages:** The publication age gate may not apply, but the diff verification and breaking change checks still do. + +## Tips for Efficiency + +- Start with the publication age gate; it is the fastest check and can immediately flag the riskiest updates. +- For large dependency updates (e.g., Dependabot batches), prioritize direct dependencies over transitive ones, and prioritize packages with install hooks. +- If a package has hundreds of thousands of weekly downloads and is maintained by a well-known org (e.g., Meta, Google, Vercel), the changelog and community checks can be lighter. But never skip the security advisory check. diff --git a/.antigravity/skills/review-pr/SKILL.md b/.antigravity/skills/review-pr/SKILL.md new file mode 100644 index 0000000..31f4fc5 --- /dev/null +++ b/.antigravity/skills/review-pr/SKILL.md @@ -0,0 +1,94 @@ +--- +name: review-pr +description: "Process unresolved review comments on a GitHub PR, fix valid issues, ensure CI passes, and re-request review." +--- + +# Review PR Feedback Loop + +## Constraints + +ALL shell operations: `gh api` with `--jq`/`--paginate` and bash only. No Python/Node/script files. No `curl` for GitHub API. Polling loops must be inline bash `while`/`sleep`. + +## Arguments + +- `$ARGUMENTS`: PR number (default: auto-detect via `gh pr view --json number -q .number`). + +## Setup + +Extract owner/name from `gh repo view --json owner,name`. Set `IGNORED_FILE=".review-pr-ignored-${PR_NUMBER}"` and `touch` it. Run the workflow loop (max 5 iterations). Delete `$IGNORED_FILE` on exit. + +## Workflow + +### 1. Fix failing CI + +Run `gh pr checks`. On failure: `gh run view --log-failed`, fix, commit, push, wait for green. + +### 2. Fetch unresolved threads + +ALWAYS re-fetch fresh each iteration. Use `gh api graphql --paginate --slurp` with `$endCursor`: + +```bash +gh api graphql --paginate --slurp \ + -f query='query($owner:String!,$repo:String!,$pr:Int!,$endCursor:String) { + repository(owner:$owner,name:$repo) { + pullRequest(number:$pr) { + reviewThreads(first:100,after:$endCursor) { + pageInfo { hasNextPage endCursor } + nodes { id isResolved comments(first:100){nodes{databaseId body path line author{login}}} } + } + } + } + }' \ + -f owner="{owner}" -f repo="{repo}" -F pr={PR_NUMBER} \ + --jq '[.[].data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false)]' +``` + +**Auto-resolve:** If a thread's first comment body matches any `$IGNORED_FILE` entry (`grep -qxF`), resolve via `resolveReviewThread` mutation without classifying. + +If unresolved threads remain → step 3. Do NOT re-request a bot review while threads are still open — process existing feedback first. Only when zero unresolved threads remain → step 5. + +### 3. Classify and resolve + +Read referenced file + context for each remaining thread, then classify: + +- **Already addressed / Informational / Inaccurate** — append body to `$IGNORED_FILE`, resolve (reply with brief explanation if inaccurate). +- **Valid fix** — implement minimal change. Must meet ALL: (1) fixes a real bug — wrong behavior, data loss, security, crash, or race condition; (2) net-simpler or complexity-neutral; (3) concrete, not speculative. +- **Nitpick / Low-value** — resolve WITHOUT implementing. Includes: style preferences not enforced by linter, docstring suggestions on clear code, subjective renames, unnecessary defensive checks, premature abstraction, "consider X instead of Y" where both work, type annotations beyond codebase norms. Append body to `$IGNORED_FILE`, reply with one-line rationale, resolve. + +### 4. Push fixes + +Stage, commit (`fix:`/`refactor:`/etc.), push, verify CI green, resolve fixed threads. Loop back to step 2. + +### 5. Ensure bot review covers latest commit + +Only reached when zero unresolved threads remain. Get HEAD SHA: `gh pr view {PR_NUMBER} --json commits --jq '.commits[-1].oid'`. Bots = logins ending in `[bot]`. Fetch their latest reviews: + +```bash +gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/reviews \ + --jq '[.[] | select(.user.login | endswith("[bot]"))] | group_by(.user.login) | map(max_by(.submitted_at))' +``` + +If a bot's latest review already covers HEAD → success. Stop. + +Otherwise, re-request and poll (first check 8 min, timeout 15 min, poll 60 s). `gh pr edit --add-reviewer` re-requests reviews from existing bot reviewers — do not skip this. + +```bash +bot_logins=$(gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/reviews \ + --jq '[.[] | select(.user.login | endswith("[bot]")) | .user.login] | unique | .[]') + +for bot in $bot_logins; do + gh pr edit {PR_NUMBER} --add-reviewer "$bot" +done + +end=$((SECONDS+900)); sleep 480 +while [ $SECONDS -lt $end ]; do + commit_id=$(gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/reviews \ + --jq '[.[] | select(.user.login=="{bot}")] | max_by(.submitted_at) | .commit_id') + [ "$commit_id" = "$head_sha" ] && break + sleep 60 +done +``` + +Timeout → tell user to re-run the review-pr skill and stop. Success → go back to step 2. + +Declare success when step 2 finds zero unresolved threads AND step 5 confirms a bot review on HEAD. Stop at iteration 5. Report: threads resolved, fixes made, threads auto-ignored, threads remaining, CI status. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b90abbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +.antigravitycli/ diff --git a/README.md b/README.md index 22f62ef..92a5879 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Set of prompts, skills, and scripts to aid in utilizing AI coding agents in deve - [Gemini CLI](https://github.com/google-gemini/gemini-cli) - [Codex CLI](https://github.com/openai/codex) - [Copilot CLI](https://docs.github.com/en/copilot/copilot-cli) + - Antigravity CLI (using the `agy` command) ## Quick Start @@ -32,6 +33,7 @@ The script detects which AI tools you have installed and walks you through insta | Gemini CLI | TOML (`.toml`) | `.gemini/commands/` | `~/.gemini/commands/` | | Codex CLI | Agent Skills (`SKILL.md`) | `.codex/skills/` | `~/.codex/skills/` | | Copilot CLI | Agent Skills (`SKILL.md`) | `.copilot/skills/` | `~/.copilot/skills/` | +| Antigravity CLI | Unified Plugin (`plugin.json`) | `.antigravity/` | `~/.gemini/antigravity-cli/plugins/ai-coding-setup/` | | Shared prompts | Markdown (`.md`) | `prompts/` | `~/.local/share/ai-coding-setup/prompts/` | ## Available Commands @@ -46,6 +48,7 @@ Propose a conventional commit message for the currently staged changes. Detects - Gemini CLI: `/commitmsg` - Codex CLI: `$commitmsg` - Copilot CLI: `/commitmsg` +- Antigravity CLI: `/commitmsg` ### /review-pr @@ -57,6 +60,7 @@ Process unresolved review comments on a GitHub PR, fix valid issues, ensure CI p - Gemini CLI: `/review-pr [PR_NUMBER]` - Codex CLI: `$review-pr [PR_NUMBER]` - Copilot CLI: `/review-pr [PR_NUMBER]` +- Antigravity CLI: `/review-pr [PR_NUMBER]` ### /code-refinement @@ -68,6 +72,7 @@ Review staged files for code quality (KISS, DRY, YAGNI, Clean Code), fix linting - Gemini CLI: `/code-refinement` - Codex CLI: `$code-refinement` - Copilot CLI: `/code-refinement` +- Antigravity CLI: `/code-refinement` ### /code-review @@ -79,6 +84,7 @@ Run a standalone code review on staged changes. Writes findings to `agent-code-r - Gemini CLI: `/code-review` - Codex CLI: `$code-review` - Copilot CLI: `/code-review` +- Antigravity CLI: `/code-review` ## Shared Prompts @@ -118,17 +124,19 @@ To add a command, create the appropriate file(s) for each tool you want to suppo 2. **Gemini CLI** — create `.gemini/commands/command-name.toml` (TOML with `description` and `prompt` fields, `{{args}}` placeholder) 3. **Codex CLI** — create `.codex/skills/command-name/SKILL.md` (markdown with YAML front matter containing `name` and `description`) 4. **Copilot CLI** — create `.copilot/skills/command-name/SKILL.md` (same format as Codex skills) +5. **Antigravity CLI** — create `.antigravity/skills/command-name/SKILL.md` (same format as Codex/Copilot skills) Run `./setup` again to install. ## Uninstalling -Delete the command/skill from the corresponding directory: +Delete the command/skill from the corresponding directory (or uninstall the plugin for Antigravity): - Claude: `~/.claude/commands/` - Gemini: `~/.gemini/commands/` - Codex: `~/.codex/skills/` - Copilot: `~/.copilot/skills/` +- Antigravity: Run `agy plugin uninstall ai-coding-setup` The setup script only manages commands it originally installed. diff --git a/bin/code-review-loop b/bin/code-review-loop index 4bbe079..155a92a 100755 --- a/bin/code-review-loop +++ b/bin/code-review-loop @@ -45,7 +45,7 @@ Options: -r, --reviewer AGENT Agent for code review (default: codex) -h, --help Show this help message -Agents: claude, codex, gemini, copilot +Agents: claude, codex, gemini, copilot, antigravity EOF exit 0 } diff --git a/bin/plan-review-loop b/bin/plan-review-loop index 95115cf..b2b52ae 100755 --- a/bin/plan-review-loop +++ b/bin/plan-review-loop @@ -46,7 +46,7 @@ Options: -r, --reviewer AGENT Agent for plan review (default: codex) -h, --help Show this help message -Agents: claude, codex, gemini, copilot +Agents: claude, codex, gemini, copilot, antigravity Examples: plan-review-loop PLAN-feature.md diff --git a/lib/lib-review-loop b/lib/lib-review-loop index c8043a3..e9b4dfd 100644 --- a/lib/lib-review-loop +++ b/lib/lib-review-loop @@ -38,7 +38,7 @@ fi PROMPTS_DIR="${AI_CODING_SETUP_PROMPTS_DIR:-$HOME/.local/share/ai-coding-setup/prompts}" # Valid agent names for --editor / --reviewer flags -VALID_AGENTS="claude codex gemini copilot" +VALID_AGENTS="claude codex gemini copilot antigravity" # Filenames that review loops create — never treat as agent artifacts KNOWN_REVIEW_FILES="agent-code-review.md agent-review-summary.md feedback-plan.md plan-review-summary.md" @@ -168,6 +168,15 @@ run_gemini() { 2> >(grep -v -E 'Warning:.*deprecated|YOLO mode|Session cleanup disabled|Loaded cached credentials' >&2) } +# Run Antigravity CLI with a prompt in non-interactive headless mode. +# Uses --dangerously-skip-permissions for auto-approval (equivalent to Codex --full-auto). +# Pipes via stdin for reliability with long prompts. +# $1 — prompt text +run_antigravity() { + local prompt="$1" + echo "$prompt" | agy -p " " --dangerously-skip-permissions --add-dir "$PWD" +} + # Run Copilot CLI with a prompt in non-interactive autonomous mode. # Uses --autopilot for multi-step execution and --yolo for auto-approval. # Disables MCP servers to keep autonomous runs scoped to local review work. @@ -184,18 +193,29 @@ run_copilot() { copilot -p "$prompt" --autopilot --yolo "${mcp_flags[@]}" } +# Map an agent name to its CLI command (most agents share the name, but +# Antigravity ships as `agy`). +# $1 — agent name +agent_command() { + case "$1" in + antigravity) echo "agy" ;; + *) echo "$1" ;; + esac +} + # Dispatch to the appropriate agent runner. -# $1 — agent name ("claude", "codex", "gemini", or "copilot") +# $1 — agent name ("claude", "codex", "gemini", "copilot", or "antigravity") # $2 — prompt text # $3 — allowed tools (only used by Claude; ignored by others) run_agent() { local agent="$1" prompt="$2" tools="${3:-}" case "$agent" in - claude) run_claude "$prompt" "$tools" ;; - codex) run_codex "$prompt" ;; - gemini) run_gemini "$prompt" ;; - copilot) run_copilot "$prompt" ;; - *) echo -e "${RED}ERROR: Unknown agent: $agent${NC}"; return 1 ;; + claude) run_claude "$prompt" "$tools" ;; + codex) run_codex "$prompt" ;; + gemini) run_gemini "$prompt" ;; + copilot) run_copilot "$prompt" ;; + antigravity) run_antigravity "$prompt" ;; + *) echo -e "${RED}ERROR: Unknown agent: $agent${NC}"; return 1 ;; esac } @@ -205,16 +225,17 @@ run_agent() { # Expects EDITOR_AGENT and REVIEWER_AGENT to be set by the caller. validate_tools() { local missing=() - command -v "$EDITOR_AGENT" &>/dev/null || missing+=("$EDITOR_AGENT") + command -v "$(agent_command "$EDITOR_AGENT")" &>/dev/null || missing+=("$EDITOR_AGENT") if [[ "$REVIEWER_AGENT" != "$EDITOR_AGENT" ]]; then - command -v "$REVIEWER_AGENT" &>/dev/null || missing+=("$REVIEWER_AGENT") + command -v "$(agent_command "$REVIEWER_AGENT")" &>/dev/null || missing+=("$REVIEWER_AGENT") fi if [[ ${#missing[@]} -gt 0 ]]; then echo -e "${RED}ERROR: Missing required tools: ${missing[*]}${NC}" - echo " Install Claude Code: https://docs.anthropic.com/en/docs/claude-code" - echo " Install Codex CLI: https://github.com/openai/codex" - echo " Install Gemini CLI: https://github.com/google-gemini/gemini-cli" - echo " Install Copilot CLI: https://docs.github.com/en/copilot/copilot-cli" + echo " Install Claude Code: https://docs.anthropic.com/en/docs/claude-code" + echo " Install Codex CLI: https://github.com/openai/codex" + echo " Install Gemini CLI: https://github.com/google-gemini/gemini-cli" + echo " Install Copilot CLI: https://docs.github.com/en/copilot/copilot-cli" + echo " Install Antigravity CLI: https://antigravity.google/" exit 1 fi } diff --git a/setup b/setup index f784fbc..bd99df2 100755 --- a/setup +++ b/setup @@ -4,7 +4,8 @@ set -euo pipefail # --------------------------------------------------------------------------- # ai-coding-setup installer # Installs AI coding agent commands/skills for Claude Code, Gemini CLI, -# Codex CLI, and Copilot CLI from this repo into user-level directories. +# Codex CLI, Copilot CLI, and Antigravity CLI from this repo into user-level +# directories. # --------------------------------------------------------------------------- RED='\033[0;31m' @@ -185,6 +186,10 @@ is_mcp_configured() { [[ -f "$HOME/.copilot/mcp-config.json" ]] \ && jq -e --arg n "$name" '.mcpServers[$n]' "$HOME/.copilot/mcp-config.json" &>/dev/null ;; + antigravity) + [[ -f "$HOME/.gemini/antigravity-cli/settings.json" ]] \ + && jq -e --arg n "$name" '.mcpServers[$n]' "$HOME/.gemini/antigravity-cli/settings.json" &>/dev/null + ;; esac } @@ -212,6 +217,16 @@ add_mcp_server() { '.mcpServers[$n] = {"type":"local","command":$c,"args":$a}' "$config") echo "$updated" | jq . > "$config" ;; + antigravity) + local config="$HOME/.gemini/antigravity-cli/settings.json" + mkdir -p "$(dirname "$config")" + [[ -f "$config" ]] || echo '{}' > "$config" + local args_json updated + args_json=$(printf '%s\n' "$@" | jq -R . | jq -s .) + updated=$(jq --arg n "$name" --arg c "$cmd" --argjson a "$args_json" \ + '.mcpServers[$n] = {"command":$c,"args":$a}' "$config") + echo "$updated" | jq . > "$config" + ;; esac } @@ -230,6 +245,11 @@ is_mcp_permitted() { && jq -e --arg p "$permission" '(.tools.allowed // []) | index($p)' \ "$HOME/.gemini/settings.json" &>/dev/null ;; + antigravity) + [[ -f "$HOME/.gemini/antigravity-cli/settings.json" ]] \ + && jq -e --arg p "$permission" '(.permissions.allow // []) | index($p)' \ + "$HOME/.gemini/antigravity-cli/settings.json" &>/dev/null + ;; *) return 0 ;; esac } @@ -252,6 +272,15 @@ add_mcp_permission() { '.tools.allowed = ((.tools.allowed // []) + [$p])' "$file") echo "$updated" | jq . > "$file" ;; + antigravity) + local file="$HOME/.gemini/antigravity-cli/settings.json" + mkdir -p "$(dirname "$file")" + [[ -f "$file" ]] || echo '{}' > "$file" + local updated + updated=$(jq --arg p "$permission" \ + '.permissions.allow = ((.permissions.allow // []) + [$p])' "$file") + echo "$updated" | jq . > "$file" + ;; esac } @@ -934,8 +963,8 @@ done # ---- prerequisite checks -------------------------------------------------- -if [[ ! -d ".claude/commands" ]] && [[ ! -d ".gemini/commands" ]] && [[ ! -d ".codex/skills" ]] && [[ ! -d ".copilot/skills" ]]; then - print_error "No command directories found (.claude/commands, .gemini/commands, .codex/skills, .copilot/skills)." +if [[ ! -d ".claude/commands" ]] && [[ ! -d ".gemini/commands" ]] && [[ ! -d ".codex/skills" ]] && [[ ! -d ".copilot/skills" ]] && [[ ! -d ".antigravity/skills" ]]; then + print_error "No command directories found (.claude/commands, .gemini/commands, .codex/skills, .copilot/skills, .antigravity/skills)." print_error "Please run this script from the ai-coding-setup repository root." exit 1 fi @@ -983,18 +1012,44 @@ if command -v copilot &>/dev/null; then detected_tools+=("copilot") fi +if command -v agy &>/dev/null; then + detected_tools+=("antigravity") +fi + if [[ ${#detected_tools[@]} -eq 0 ]]; then print_error "No supported AI coding tools detected." echo "" echo " Install at least one of:" - echo " - Claude Code: https://docs.anthropic.com/en/docs/claude-code" - echo " - Gemini CLI: https://github.com/google-gemini/gemini-cli" - echo " - Codex CLI: https://github.com/openai/codex" - echo " - Copilot CLI: https://docs.github.com/en/copilot/copilot-cli" + echo " - Claude Code: https://docs.anthropic.com/en/docs/claude-code" + echo " - Gemini CLI: https://github.com/google-gemini/gemini-cli" + echo " - Codex CLI: https://github.com/openai/codex" + echo " - Copilot CLI: https://docs.github.com/en/copilot/copilot-cli" + echo " - Antigravity CLI: https://antigravity.google/" echo "" exit 1 fi +# ---- Gemini CLI EOL notice ------------------------------------------------- +# Google is transitioning Gemini CLI free/Pro/Ultra tiers to Antigravity CLI on +# 2026-06-18. Enterprise/Cloud users are unaffected. Surface this once at +# detection time so users know to migrate. + +if printf '%s\n' "${detected_tools[@]}" | grep -qx gemini; then + echo "" + if [[ "$(date -u +%Y%m%d)" -ge 20260618 ]]; then + print_warning "Gemini CLI free/Pro/Ultra tiers reached end-of-life on 2026-06-18." + echo " Those tiers are now served by Antigravity CLI (agy). If you don't have a" + echo " Gemini Code Assist Standard/Enterprise license or a paid API key," + echo " uninstall Gemini CLI and use Antigravity CLI instead." + echo " Migration guide: https://antigravity.google/docs/gcli-migration" + else + print_warning "Gemini CLI free/Pro/Ultra tiers stop serving on 2026-06-18." + echo " Those tiers move to Antigravity CLI (agy). Plan to migrate before then;" + echo " Enterprise/Cloud users are unaffected." + echo " Migration guide: https://antigravity.google/docs/gcli-migration" + fi +fi + # ---- tool selection -------------------------------------------------------- echo "" @@ -1004,10 +1059,11 @@ echo "" for i in "${!detected_tools[@]}"; do tool="${detected_tools[$i]}" case "$tool" in - claude) echo -e " ${BOLD}$((i + 1)))${NC} Claude Code" ;; - gemini) echo -e " ${BOLD}$((i + 1)))${NC} Gemini CLI" ;; - codex) echo -e " ${BOLD}$((i + 1)))${NC} Codex CLI" ;; - copilot) echo -e " ${BOLD}$((i + 1)))${NC} Copilot CLI" ;; + claude) echo -e " ${BOLD}$((i + 1)))${NC} Claude Code" ;; + gemini) echo -e " ${BOLD}$((i + 1)))${NC} Gemini CLI" ;; + codex) echo -e " ${BOLD}$((i + 1)))${NC} Codex CLI" ;; + copilot) echo -e " ${BOLD}$((i + 1)))${NC} Copilot CLI" ;; + antigravity) echo -e " ${BOLD}$((i + 1)))${NC} Antigravity CLI" ;; esac done @@ -1051,19 +1107,33 @@ for tool in "${selected_tools[@]}"; do configure_mcp "gemini" "Gemini CLI" "gemini" ;; codex) - install_commands "Codex CLI Skills" \ + install_commands "Codex CLI" \ ".codex/skills" "$HOME/.codex/skills" \ "skill" "$MD_MARKER" "\$" "get_skill_description" configure_codex_settings configure_mcp "codex" "Codex CLI" "codex" ;; copilot) - install_commands "Copilot CLI Skills" \ + install_commands "Copilot CLI" \ ".copilot/skills" "$HOME/.copilot/skills" \ "skill" "$MD_MARKER" "/" "get_skill_description" configure_copilot_settings configure_mcp "copilot" "Copilot CLI" "copilot" ;; + antigravity) + echo "" + echo -e "${BOLD}── Antigravity CLI ──${NC}" + if prompt_yes_no " Setup Antigravity CLI?"; then + if agy plugin install "$PWD/.antigravity"; then + print_success "Installed Antigravity CLI plugin" + configure_mcp "antigravity" "Antigravity CLI" "agy" + else + print_error "agy plugin install failed — see output above" + fi + else + print_info "Skipped Antigravity CLI plugin" + fi + ;; esac done @@ -1157,7 +1227,7 @@ if [[ ${#review_loop_scripts[@]} -gt 0 ]] && [[ ! -f "$config_file" ]]; then # code changes) and codex/gemini for reviewing (second opinion), but fall # back to the same agent for both roles if only one tool is available. _default_editor="" _default_reviewer="" - for _t in claude codex gemini copilot; do + for _t in claude codex gemini copilot antigravity; do [[ " ${selected_tools[*]} " == *" $_t "* ]] || continue [[ -z "$_default_editor" ]] && _default_editor="$_t" [[ -n "$_default_editor" ]] && [[ "$_t" != "$_default_editor" ]] && _default_reviewer="$_t" @@ -1177,10 +1247,10 @@ if [[ ${#review_loop_scripts[@]} -gt 0 ]] && [[ ! -f "$config_file" ]]; then # ai-coding-setup — default agent configuration for review loops. # These defaults can be overridden per-invocation with --editor / --reviewer flags. -# Agent for editing/implementation (claude, codex, gemini, copilot) +# Agent for editing/implementation (claude, codex, gemini, copilot, antigravity) EDITOR_AGENT=$_default_editor -# Agent for reviewing (claude, codex, gemini, copilot) +# Agent for reviewing (claude, codex, gemini, copilot, antigravity) REVIEWER_AGENT=$_default_reviewer CONF print_success "Created $config_file" @@ -1198,10 +1268,11 @@ echo "Use your commands in:" for tool in "${selected_tools[@]}"; do case "$tool" in - claude) echo -e " Claude Code — type ${BOLD}/command-name${NC} in the prompt" ;; - gemini) echo -e " Gemini CLI — type ${BOLD}/command-name${NC} in the prompt" ;; - codex) echo -e " Codex CLI — type ${BOLD}\$skill-name${NC} to invoke a skill" ;; - copilot) echo -e " Copilot CLI — type ${BOLD}/skill-name${NC} in the prompt" ;; + claude) echo -e " Claude Code — type ${BOLD}/command-name${NC} in the prompt" ;; + gemini) echo -e " Gemini CLI — type ${BOLD}/command-name${NC} in the prompt" ;; + codex) echo -e " Codex CLI — type ${BOLD}\$skill-name${NC} to invoke a skill" ;; + copilot) echo -e " Copilot CLI — type ${BOLD}/skill-name${NC} in the prompt" ;; + antigravity) echo -e " Antigravity CLI — type ${BOLD}/skill-name${NC} in the prompt" ;; esac done diff --git a/test/lib-review-loop.bats b/test/lib-review-loop.bats index 1e47654..ebfd7dd 100644 --- a/test/lib-review-loop.bats +++ b/test/lib-review-loop.bats @@ -10,7 +10,7 @@ load test_helper @test "validate_agent_name accepts all valid agents" { source_lib - for agent in claude codex gemini copilot; do + for agent in claude codex gemini copilot antigravity; do run validate_agent_name "$agent" "--editor" assert_success done diff --git a/test/smoke b/test/smoke index db1a094..ea7f287 100755 --- a/test/smoke +++ b/test/smoke @@ -24,7 +24,8 @@ source "$PROJECT_ROOT/lib/lib-review-loop" # ---- configuration ------------------------------------------------------- TIMEOUT=120 # seconds per agent invocation -ALL_AGENTS="claude codex gemini copilot" +ALL_AGENTS="claude codex gemini copilot antigravity" +export GEMINI_CLI_TRUST_WORKSPACE=true # ---- usage --------------------------------------------------------------- @@ -65,7 +66,7 @@ done installed=() for agent in $ALL_AGENTS; do - if command -v "$agent" &>/dev/null; then + if command -v "$(agent_command "$agent")" &>/dev/null; then installed+=("$agent") fi done