antigravity-exit
Scan a public GitHub repo for Gemini CLI usage and emit a migration checklist to Antigravity CLI before the 2026-06-18 cutoff. Built for dev teams and indie hackers caught by Google's 30-day deprecation window.
What it does
- Paste
owner/repo(or agithub.comURL) → backend fetches the repo tree via GitHub REST, walks files matchingpackage.json|.yml|.yaml|.sh|.bash|.zsh|.fish|.md|.gemini/*|Dockerfile|Makefile|*.toml(capped at 200 files / 4 MB / 30 s) and looks for known Gemini CLI signatures. - Per finding, it joins to the curated
mappings/known.jsontable to surface the Antigravity CLI replacement, or flagsNO ANTIGRAVITY EQUIVALENT — escalate to Googleif the surface has no published mapping yet. - Each scan gets a stable, shareable URL with full per-file findings and a downloadable Markdown checklist.
- The home page renders a leaderboard of pre-scanned popular OSS repos by exposure score (0–100) plus a giant countdown to the 2026-06-18 cutoff and the current 7-day npm downloads of
@google/gemini-cli(proof the at-risk user base is still huge).
No login, no payments, no LLM calls — deterministic scanning + table lookup against real-time public data.
Endpoints (all under /antigravity-exit)
| Method | Path | Purpose |
|---|---|---|
| GET | /health | Liveness — {ok:true} HTTP 200 |
| POST | /api/scan | Body {repo:"owner/name"} → runs scan synchronously (cap 30s), returns {id, exposureScore, findingsCount, …} |
| GET | /api/scan/:id | Full scan: findings grouped by file with mapping resolution |
| GET | /api/scan/:id/checklist.md | Markdown checklist download |
| GET | /api/leaderboard | Top N pre-scanned repos. Query ?sort=score\|stars\|updated&limit=50 |
| GET | /api/mappings | Gemini → Antigravity mapping table + announcement snapshot metadata |
| GET | /api/announcement | Latest scraped announcement (text + hash + history) |
| GET | /api/stats | {cutoffIso, daysLeft, npm7dRange, npm7dTotal, scansTotal, exposedReposTotal, announcement} |
| GET | / | SPA shell (leaderboard) |
| GET | /scan/:id | Static SPA — deep view of a scan |
| GET | /mappings | Static SPA — full mapping table |
Live data sources
| Source | URL | Refresh |
|---|---|---|
| GitHub REST — repo metadata | https://api.github.com/repos/{owner}/{repo} | per scan + nightly via popular-repos cron |
| GitHub REST — git tree | https://api.github.com/repos/{owner}/{repo}/git/trees/{sha}?recursive=1 | per scan |
| GitHub raw — file content | https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path} | per scan, only allow-listed extensions, capped 200 files / 4 MB |
| Google Developers Blog announcement | https://developers.googleblog.com/en/an-important-update-transitioning-gemini-cli-to-antigravity-cli/ | hourly (0 ) — diffed by SHA256 of normalized text |
| npm registry — downloads | https://api.npmjs.org/downloads/range/last-week/@google/gemini-cli | every 6h (0 /6 ) |
| npm registry — package metadata | https://registry.npmjs.org/@google/gemini-cli | every 6h |
| Popular-OSS re-scan | curated list in scrapers/popular-repos.list | nightly (15 4 *) |
A GITHUB_TOKEN from the vault lifts requests to the 5000/h authenticated rate limit; it never leaves the server. If you run unauthenticated you'll likely get rate-limited on the first big repo scan.
Mapping table
mappings/known.json is a curated reference table — equivalent to a dictionary, version-controlled with the code. The hourly scraper re-fetches the official announcement and stores a SHA256 — when the doc changes the mappings page surfaces a banner so a human knows to refresh the table. Entries without a known target are stored as replacement: null and rendered as red "NO MAPPING YET" rows. We do not fabricate replacements.
Run locally
npm install
PORT=4828 node server.js
# open http://localhost:4828/antigravity-exit/
The server creates data/antigravity-exit.db (SQLite, WAL). On boot it kicks off the announcement + npm fetchers immediately, plus the popular-repos scan after 5 seconds. Cron jobs continue afterwards.
Pattern set
| pattern_id | Matches | Severity |
|---|---|---|
| pkg.json.dep | "@google/gemini-cli" in package.json deps | high |
| pkg.json.script | gemini / gemini-cli token inside package.json scripts. | high |
| gh-actions.uses | uses: google-gemini/.+ or gemini-cli in .github/workflows/.yml | high |
| gh-actions.run | run: step invoking gemini or npx gemini-cli | high |
| shell.gemini-bin | gemini / gemini-cli in shell scripts / Makefile / Dockerfile | high |
| dotgemini.dir | any path under .gemini/ | med |
| env.api-key | reference to GEMINI_API_KEY env var | med |
| docs.mention | README/markdown mentions of gemini-cli | info |
| agent.skills | .gemini/skills / .gemini/hooks / .gemini/subagents | high |
exposure_score (0–100) = 30 if any high, +5/extra high (cap 60), +5/distinct file (cap 30), +1/med (cap 10).
Layout
antigravity-exit/
├── server.js # Express bootstrap, cron registration
├── db.js # better-sqlite3 init, migrations, WAL
├── config.js # PORT, BASE_PATH, GITHUB_TOKEN, allowlist
├── routes/ # health, scan, leaderboard, mappings, stats
├── scanners/ # github API client, regex patterns, orchestrator
├── scrapers/ # announcement (hourly), npm (6h), popular-repos (nightly)
├── mappings/known.json # curated Gemini → Antigravity table
└── public/ # vanilla SPA: index.html, scan.html, mappings.html, app.js, style.css
Out of scope (by spec)
- Auth, OAuth, private-repo scans, repo upload — public URL only.
- PR auto-generation against scanned repos.
- Migration for the Gemini API SDK (non-CLI).
- Enterprise Code-Assist customers (exempt per Google's announcement).
- LLM calls — no OpenRouter, no Anthropic SDK.
Honesty notes
- The mapping table is hand-curated from public announcement text and tagged with confidence (
official/inferred/unknown). Anything Google has not actually published isreplacement: null— we deliberately do not invent migration paths. - All scan data (tree, files, metadata, stars, downloads, announcement text) is fetched live from GitHub, npm, and developers.googleblog.com at runtime. No seed data, no
Math.random(). - After 2026-06-18 this product becomes a historical artifact and the countdown reads
PASSED.