Skip to content

Fix Antigravity, duplicate accounts, strip not-ready providers; prepare 1.5.12#156

Merged
tsouth89 merged 5 commits into
mainfrom
fix/provider-bugs-and-1.5.12
Jul 26, 2026
Merged

Fix Antigravity, duplicate accounts, strip not-ready providers; prepare 1.5.12#156
tsouth89 merged 5 commits into
mainfrom
fix/provider-bugs-and-1.5.12

Conversation

@tsouth89

@tsouth89 tsouth89 commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

Three reliability fixes plus the 1.5.12 version bump so we can ship them.

  1. [Bug]: Antigravity detection fails on Windows when language server uses --https_server_port 0 #153 Antigravity detection - Accept language servers that use --https_server_port 0 without --extension_server_port (Antigravity 2.3+ on Windows). Discover the API via PID listening ports.
  2. [Bug]: #155 Duplicate Codex cards - After Accounts auto-registers the ambient home, prune ambient account_id=None ghost rows from the provider cache and resync the UI on refresh-complete.
  3. Taskbar strip - Only show error-free readings. Enabling a provider that is not installed/signed in no longer adds a blank dash pill. Error snapshots no longer put Antigravity's session label ("Claude") on the window.

Version bump to 1.5.12 (build 114).

Related issue

Fixes #153
Fixes #155

Affected areas

  • Tray panel
  • Settings UI
  • Config file / settings persistence
  • CLI
  • Provider-specific behavior
  • Installer / release packaging
  • Startup / background behavior
  • Documentation
  • Other:

Validation

  • Other:
    • cargo test --manifest-path rust/Cargo.toml antigravity (11 passed)
    • cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml pruning_ / expected_keys / provider_cache (passed)
    • npm test -- --run src/hooks/useProviders.test.tsx (18 passed)
    • npm test -- --run src/floatbar/FloatBar.test.tsx (22 passed)

UI / tray proof

  • Visual proof was not practical; manual validation and explanation attached
    • [Bug]: #155 repro is cache keying after ambient register; unit tests assert ambient ghost prune and UI authoritative resync.
    • Strip test asserts an Antigravity error placeholder with primaryLabel Claude does not render a pill.

Notes for reviewers

After squash-merge to protected main, tag v1.5.12 on that commit only to start the signed Windows release workflow (tag must match version files and be an ancestor of main).

Release notes: .github/release-notes-1.5.12.md

Summary by CodeRabbit

  • Bug Fixes

    • Improved Antigravity detection across IDE and CLI launch modes, including additional port and authentication configurations.
    • Removed duplicate or stale account usage cards after account registration or refresh.
    • Prevented unavailable, unauthenticated, or error-state providers from appearing in the always-visible taskbar strip.
    • Corrected provider branding, colors, and native icons for Gemini, Antigravity, Copilot, and other services.
  • Release

    • Updated the application to version 1.5.12.

tsouth89 added 3 commits July 26, 2026 09:26
Antigravity 2.3+ on Windows advertises --https_server_port 0 and omits
--extension_server_port, so process detection never accepted the language
server. Accept CSRF + PID (or a real advertised port) and discover the API
via listening-port enumeration.

Opening Accounts auto-registers the ambient Codex home with a UUID, while
the earlier ambient reading (account_id=None) stayed in the cache forever.
Prune cache rows to the cycle's expected keys after refresh, and resync the
UI authoritatively on refresh-complete so ghost cards leave the overview.

Fixes #153, #155
Enabling a provider only put an error placeholder in the cache. The strip
showed it as a blank dash pill, and Antigravity's session window label is
"Claude", so the pill looked like a broken Claude seat with the wrong
identity.

Only error-free readings belong on the always-visible capacity strip.
Overview and Settings still show setup failures so the user can finish
auth. Error snapshots no longer carry session_label as primary_label.
Version bump to 1.5.12 (build 114). Ships Antigravity Windows detection,
duplicate-account cache prune, and taskbar strip eligibility for not-ready
providers. After merge, tag v1.5.12 on the squash commit on protected main.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ceiling 0b05e32 Commit Preview URL

Branch Preview URL
Jul 26 2026, 02:05 PM

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ee38f10-6fcc-4323-ad56-188467c202c9

📥 Commits

Reviewing files that changed from the base of the PR and between bb09096 and 0b05e32.

📒 Files selected for processing (1)
  • rust/src/providers/antigravity/mod.rs
📝 Walkthrough

Walkthrough

Ceiling 1.5.12 improves Antigravity IDE/CLI detection, removes stale provider account readings, hides unauthenticated providers from the float bar, updates provider glyph rendering, and bumps release metadata and package versions.

Changes

Provider refresh and presentation updates

Layer / File(s) Summary
Antigravity process detection and API probing
rust/src/providers/antigravity/mod.rs
Windows detection now supports IDE and CLI processes, zero advertised ports, both flag forms, tokenless CLI requests, and conditional CSRF handling.
Provider cache identity and refresh synchronization
apps/desktop-tauri/src-tauri/src/commands/..., apps/desktop-tauri/src/hooks/...
Refresh cycles prune stale provider/account rows, error snapshots omit session labels, and refresh-complete performs an authoritative cache resynchronization with updated tests.
Provider glyphs, branding, and strip eligibility
apps/desktop-tauri/src-tauri/src/taskbar_widget.rs, apps/desktop-tauri/src/components/providers/ProviderIcon.tsx, apps/desktop-tauri/src/floatbar/...
Gemini and Antigravity receive native glyphs and colors, SVG branding is strengthened, and error readings are excluded from the float bar.
1.5.12 version and release records
.github/release-notes-1.5.12.md, CHANGELOG.md, apps/desktop-tauri/..., rust/Cargo.toml, version.env, docs/HANDOFF.md
Release documentation, package versions, crate versions, Tauri metadata, marketing version, and build number are updated to 1.5.12.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WindowsProcessEnumeration
  participant AntigravityDetector
  participant LocalConnectAPI
  WindowsProcessEnumeration->>AntigravityDetector: enumerate matching IDE or CLI process
  AntigravityDetector->>WindowsProcessEnumeration: discover PID listening ports
  AntigravityDetector->>LocalConnectAPI: probe candidate API port
  LocalConnectAPI-->>AntigravityDetector: return user status and quota data
Loading

Possibly related PRs

Suggested reviewers: finesssee

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes release-note/version bumps and taskbar icon/tinting changes that are not required by #153 or #155. Move release prep and visual polish to a separate PR so this one stays focused on the two linked bug fixes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the Antigravity, duplicate-account, and release/version work.
Linked Issues check ✅ Passed The PR addresses Antigravity Windows detection with https_server_port 0 and prunes stale ambient account rows, matching #153 and #155.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/provider-bugs-and-1.5.12

Comment @coderabbitai help to get the list of available commands.

Antigravity CLI (agy) hosts the same local quota API as the IDE language
server but without a CSRF token and under a different process name. Match
agy.exe / antigravity-cli by image path only so shell scripts that merely
mention agy are not mistaken for the server, and allow empty CSRF for CLI
matches only.

Native taskbar only had bitmaps for Codex/Claude/Cursor/Grok, so Gemini
fell through to a hollow ring. Add Gemini and Antigravity 16x16 marks,
brand colors, and stronger strip SVG tinting so first-class seats stay
readable. Gemini remains a separate provider (oauth_creds) from Antigravity.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
apps/desktop-tauri/src-tauri/src/commands/providers.rs (1)

250-253: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Silent skip when the state lock is poisoned.

Every other state.lock() site in this module logs on failure; here a poisoned lock silently leaves ghost rows in the cache with no diagnostic. A tracing::warn! in the else keeps the failure debuggable.

♻️ Proposed tweak
-    if let Ok(mut guard) = state.lock() {
-        prune_stale_provider_readings(&mut guard.provider_cache, &expected, &inputs.enabled_ids);
-    }
+    match state.lock() {
+        Ok(mut guard) => {
+            prune_stale_provider_readings(
+                &mut guard.provider_cache,
+                &expected,
+                &inputs.enabled_ids,
+            );
+        }
+        Err(_) => tracing::warn!("Provider state poisoned; skipped stale-reading pruning"),
+    }

As per coding guidelines, "Use tracing for diagnostics".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop-tauri/src-tauri/src/commands/providers.rs` around lines 250 -
253, Update the state.lock() handling around prune_stale_provider_readings to
add a tracing::warn! diagnostic when the lock is poisoned, matching the logging
behavior of other state.lock() sites in this module while preserving the
existing pruning path on successful locking.

Source: Coding guidelines

apps/desktop-tauri/src/floatbar/FloatBar.css (1)

799-807: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Brand tint is now forced regardless of the light-background contrast mode.

color: var(--brand …) !important applies in floatbar--light-bg too, so near-white brands (e.g. Grok's silver) sit on an 18%-tint badge over a light surface and can wash out. Consider scoping the override, or darkening via color-mix(… , currentColor) under .floatbar--light-bg.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop-tauri/src/floatbar/FloatBar.css` around lines 799 - 807, Scope
the brand color, background, and inset box-shadow overrides in the
`.floatbar__bar .floatbar__provider-icon .provider-icon` rule so they do not
force low-contrast near-white brand colors in `.floatbar--light-bg`; preserve
the existing branded styling for other modes and the SVG sizing in
`.provider-icon--svg`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop-tauri/src/floatbar/FloatBar.tsx`:
- Around line 533-540: Update the eligibility logic around isFloatBarEligible in
the visible useMemo so transient fetch errors do not remove providers that have
previously produced a successful reading. Suppress only providers that have
never reached a ready/authenticated state, while retaining established error
snapshots for ProviderPill to render its existing stale or “—” state and
preserve pill layout.

In `@docs/HANDOFF.md`:
- Line 9: Update the release state entry in HANDOFF.md to mark Ceiling 1.5.12 as
the public release and advance the package/next-draft version to the appropriate
post-release version, preserving the existing release-link and description
format.

In `@rust/src/providers/antigravity/mod.rs`:
- Around line 199-226: Update parse_process_info to avoid returning a tokenless,
port-zero CLI candidate before stronger matches: retain the best candidate while
scanning, immediately prefer candidates with a non-zero advertised port and/or
CSRF token, and return the tokenless CLI only as a fallback after all processes
are examined. Preserve the existing eligibility checks and ProcessInfo fields.

---

Nitpick comments:
In `@apps/desktop-tauri/src-tauri/src/commands/providers.rs`:
- Around line 250-253: Update the state.lock() handling around
prune_stale_provider_readings to add a tracing::warn! diagnostic when the lock
is poisoned, matching the logging behavior of other state.lock() sites in this
module while preserving the existing pruning path on successful locking.

In `@apps/desktop-tauri/src/floatbar/FloatBar.css`:
- Around line 799-807: Scope the brand color, background, and inset box-shadow
overrides in the `.floatbar__bar .floatbar__provider-icon .provider-icon` rule
so they do not force low-contrast near-white brand colors in
`.floatbar--light-bg`; preserve the existing branded styling for other modes and
the SVG sizing in `.provider-icon--svg`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bed85bb9-0ef2-41d1-8ebb-391fce2c4683

📥 Commits

Reviewing files that changed from the base of the PR and between 62e180d and bb09096.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • .github/release-notes-1.5.12.md
  • CHANGELOG.md
  • apps/desktop-tauri/package.json
  • apps/desktop-tauri/src-tauri/Cargo.toml
  • apps/desktop-tauri/src-tauri/src/commands/bridge.rs
  • apps/desktop-tauri/src-tauri/src/commands/providers.rs
  • apps/desktop-tauri/src-tauri/src/commands/tests.rs
  • apps/desktop-tauri/src-tauri/src/taskbar_widget.rs
  • apps/desktop-tauri/src-tauri/tauri.conf.json
  • apps/desktop-tauri/src/components/providers/ProviderIcon.tsx
  • apps/desktop-tauri/src/floatbar/FloatBar.css
  • apps/desktop-tauri/src/floatbar/FloatBar.test.tsx
  • apps/desktop-tauri/src/floatbar/FloatBar.tsx
  • apps/desktop-tauri/src/hooks/useProviders.test.tsx
  • apps/desktop-tauri/src/hooks/useProviders.ts
  • docs/HANDOFF.md
  • rust/Cargo.toml
  • rust/src/providers/antigravity/mod.rs
  • version.env

Comment on lines 533 to +540
const visible = useMemo(() => {
const enabled = new Set(settings.enabledProviders);
const eligible = providers.filter((p) => enabled.has(p.providerId));
// Enabled alone is not enough: skip not-yet-ready error placeholders so
// turning on Antigravity without the app installed does not mint a blank
// "Claude" pill on the taskbar.
const eligible = providers.filter(
(p) => enabled.has(p.providerId) && isFloatBarEligible(p),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Transient fetch failures now make an established pill vanish, not just gray out.

The filter is on the current reading's error, not on "never authenticated". When a working provider's next refresh errors, its cached row becomes an error snapshot and the pill disappears — the capsule reflows and the number is lost until recovery, which is a bigger jolt than the previous stale/"—" pill. If the intent is only to suppress never-ready providers (as the new test's name suggests), consider retaining the last successful reading with a stale chip instead.

Also note ProviderPill's error branches (exhausted via provider.error, the "—" label) are now dead from this call site.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop-tauri/src/floatbar/FloatBar.tsx` around lines 533 - 540, Update
the eligibility logic around isFloatBarEligible in the visible useMemo so
transient fetch errors do not remove providers that have previously produced a
successful reading. Suppress only providers that have never reached a
ready/authenticated state, while retaining established error snapshots for
ProviderPill to render its existing stale or “—” state and preserve pill layout.

Comment thread docs/HANDOFF.md
- Repository: `C:\projects\personal\ceiling`
- Trunk: protected `main`; create short-lived feature branches for new work. PRs squash-merge.
- Public release: [Ceiling 1.5.6](https://github.com/tsouth89/ceiling/releases/tag/v1.5.6). Package / next draft: **1.5.11** (everything since 1.5.6: multi-account strip pin, Charts trust/efficiency, strip polish, constraining-window taskbar meters, Grok API-equivalent $ charts).
- Public release: [Ceiling 1.5.11](https://github.com/tsouth89/ceiling/releases/tag/v1.5.11). Package / next draft: **1.5.12** (Antigravity detection, duplicate-account prune, strip hides not-ready providers).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the handoff release state.

This PR releases 1.5.12, but the handoff still says 1.5.11 is public and 1.5.12 is the next draft. Update the public release and next-draft version to reflect the post-release state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/HANDOFF.md` at line 9, Update the release state entry in HANDOFF.md to
mark Ceiling 1.5.12 as the public release and advance the package/next-draft
version to the appropriate post-release version, preserving the existing
release-link and description format.

Comment on lines +199 to +226
let port = match extension_port {
Some(p) if p > 0 => p,
_ => match https_port {
Some(p) if p > 0 => p,
_ => 0,
},
};

// Need a real advertised port or a PID to enumerate listening ports.
if port == 0 && pid.is_none() {
continue;
}

// IDE language_server requires CSRF. Tokenless IDE matches are skipped so a
// later valid IDE (or CLI) candidate can still be found.
// CLI accepts an empty token — its local server does not check CSRF.
let token = match (is_cli, csrf_token) {
(_, Some(token)) => token,
(true, None) => String::new(),
(false, None) => continue,
};

return Some(ProcessInfo {
csrf_token: token,
extension_server_csrf_token: ext_csrf_token,
extension_port: port,
pid,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

First match wins, so a transient agy process can shadow a live IDE language server.

parse_process_info returns on the first accepted candidate. A short-lived CLI (agy -p …, port 0, no listening Connect port) enumerated before the IDE's language_server.exe will be selected, and find_api_port then fails with "Could not find Antigravity API port" even though the IDE was discoverable. Consider collecting candidates and preferring ones with a non-zero advertised port / CSRF token before falling back to the tokenless CLI.

♻️ Sketch
-            return Some(ProcessInfo {
-                csrf_token: token,
-                extension_server_csrf_token: ext_csrf_token,
-                extension_port: port,
-                pid,
-            });
+            let candidate = ProcessInfo {
+                csrf_token: token,
+                extension_server_csrf_token: ext_csrf_token,
+                extension_port: port,
+                pid,
+            };
+            // Prefer a candidate that advertises a real port or a CSRF token;
+            // keep a tokenless CLI only as a fallback.
+            if candidate.extension_port > 0 || !candidate.csrf_token.is_empty() {
+                return Some(candidate);
+            }
+            fallback.get_or_insert(candidate);

(then return fallback; instead of None)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/src/providers/antigravity/mod.rs` around lines 199 - 226, Update
parse_process_info to avoid returning a tokenless, port-zero CLI candidate
before stronger matches: retain the best candidate while scanning, immediately
prefer candidates with a non-zero advertised port and/or CSRF token, and return
the tokenless CLI only as a fallback after all processes are examined. Preserve
the existing eligibility checks and ProcessInfo fields.

@tsouth89
tsouth89 merged commit 2032f1d into main Jul 26, 2026
10 of 11 checks passed
@tsouth89
tsouth89 deleted the fix/provider-bugs-and-1.5.12 branch July 26, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: [Bug]: Antigravity detection fails on Windows when language server uses --https_server_port 0

1 participant