Skip to content

feat(antigravity): add Google Antigravity client with sync-first cache parser - #355

Merged
junhoyeo merged 7 commits into
junhoyeo:mainfrom
ddarkr:feat/antigravity-collector
Apr 26, 2026
Merged

feat(antigravity): add Google Antigravity client with sync-first cache parser#355
junhoyeo merged 7 commits into
junhoyeo:mainfrom
ddarkr:feat/antigravity-collector

Conversation

@ddarkr

@ddarkr ddarkr commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add tokscale antigravity status|sync|purge-cache so Antigravity usage can be collected from the local language server while the editor is running
  • store confirmed Antigravity usage as cached JSONL artifacts and keep tokscale-core focused on parsing local data instead of live RPC collection
  • preserve previously confirmed Antigravity artifacts when older sessions no longer appear in the live window
  • normalize Antigravity model aliases so reporting and pricing lookup use stable canonical model names

Test proof

  • cargo test — passed
  • cargo test -p tokscale-cli antigravity — passed
  • cargo test -p tokscale-core antigravity — passed
  • cargo run -p tokscale-cli -- antigravity status — verified sync-first UX
  • cargo run -p tokscale-cli -- antigravity sync — verified cache sync flow
  • cargo run -p tokscale-cli -- models --antigravity --json — verified parsed reporting path

Summary by cubic

Adds Antigravity support: tokscale antigravity syncs usage from the local language server into a cached JSONL store, and tokscale-core parses it with canonical model aliases for accurate pricing. Run tokscale antigravity sync while the editor is open; synced usage appears in local reports by default (optional --client antigravity filter; legacy --antigravity; TUI hotkey a).

  • New Features

    • New tokscale antigravity subcommands: status, sync, purge-cache.
    • Cache at ~/.config/tokscale/antigravity-cache/sessions/*.jsonl; manifest preserves prior confirmed artifacts.
    • Core wiring: added antigravity client (scans cached JSONL), parser, and pricing alias normalization for placeholders and “thinking” variants (e.g., model_placeholder_m26claude-opus-4-6, gemini-3-flash-cgemini-3-flash-preview).
    • Reporting/UI: included in default local parsing; optional --client antigravity (legacy --antigravity) and TUI entry (hotkey a).
  • Bug Fixes

    • Skip broken trajectory RPC connections; parse chunked responses without truncation.
    • Cleanup hardening: persist the manifest before deletion, restrict cleanup to cache-relative session .jsonl paths, canonicalize targets and reject symlink escapes, and remove stale legacy artifacts after sync.
    • Discovery fallbacks: tolerate missing lsof, probe declared RPC ports when discovery returns nothing, and improve status/sync diagnostics.
    • Preserve numeric retry timestamps in exported metadata.

Written for commit 78706fe. Summary will update on new commits.


Open in Devin Review

@vercel

vercel Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

@ddarkr is attempting to deploy a commit to the Inevitable Team on Vercel.

A member of the Team first needs to authorize it.

cubic-dev-ai[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2d7c24c61f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tokscale-cli/src/antigravity.rs Outdated
Comment on lines +723 to +727
let response = rpc_request(
connection,
"GetAllCascadeTrajectories",
&serde_json::json!({}),
)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Continue syncing when one RPC connection fails

list_trajectory_summaries currently propagates any single rpc_request error with ?, so tokscale antigravity sync aborts even if other detected language-server connections are healthy. This is user-visible when one editor instance exits or transiently fails between heartbeat probing and trajectory listing: one bad process prevents exporting sessions from all remaining processes. Treat per-connection RPC failures as best-effort (skip/log) to keep sync resilient.

Useful? React with 👍 / 👎.

Comment thread crates/tokscale-cli/src/antigravity.rs Outdated
Comment on lines +1171 to +1174
.get("createdAt")
.or_else(|| usage.get("timestamp"))
.and_then(Value::as_str)
.and_then(|text| chrono::DateTime::parse_from_rfc3339(text).ok())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Parse numeric retry timestamps before writing artifacts

Timestamp extraction for retry usage only accepts RFC3339 strings via as_str, so numeric createdAt/timestamp fields become null in emitted JSONL rows. The antigravity parser later drops usage rows with non-positive timestamps, which silently undercounts tokens/cost whenever the RPC payload uses epoch numbers instead of strings. Add numeric timestamp handling here before falling back to created_at.

Useful? React with 👍 / 👎.

cubic-dev-ai[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12d2b21b96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tokscale-cli/src/antigravity.rs Outdated
Comment on lines +622 to +625
let mut ports = parse_ports(&run_command(
"lsof",
&["-Pan", "-p", &pid_str, "-iTCP", "-sTCP:LISTEN"],
)?);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle missing lsof gracefully during sync

Connection discovery hard-fails when lsof is unavailable because find_listening_ports propagates run_command("lsof", ...) errors with ?. On systems where lsof is not installed (common in minimal Linux setups), tokscale antigravity status/sync will abort as soon as an Antigravity process candidate is found, so users cannot refresh cache data despite having a running editor. This should degrade to a warning and skip that process instead of failing the whole command.

Useful? React with 👍 / 👎.

cubic-dev-ai[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20a5ac4f82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tokscale-cli/src/antigravity.rs Outdated
Comment on lines +389 to +391
let artifact_path = cache_dir.join(relative_path);
if artifact_path.exists() {
fs::remove_file(&artifact_path)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restrict artifact deletion to cache directory

delete_artifact_relative_path trusts artifact_path from the manifest and directly does cache_dir.join(relative_path) before remove_file. Because join accepts absolute paths and .. segments, a corrupted/edited manifest can cause sync cleanup to delete files outside ~/.config/tokscale/antigravity-cache (for example an absolute path or ../../...). This makes artifact cleanup unsafe against malformed local state and can lead to unintended data loss.

Useful? React with 👍 / 👎.

Comment thread crates/tokscale-cli/src/antigravity.rs Outdated
Comment on lines +509 to +510
let ports = find_listening_ports(candidate.pid)?;
for port in ports {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Probe declared RPC port when port scan returns nothing

Connection discovery only iterates ports returned by find_listening_ports, so candidates are dropped when lsof is unavailable/restricted or returns no rows. Fresh evidence in this commit: ProcessCandidate.declared_port is parsed from --extension_server_port but never used during probing, which means antigravity status/sync can still report zero connections even though the process advertises a usable RPC port.

Useful? React with 👍 / 👎.

cubic-dev-ai[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1660f1be3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tokscale-core/src/clients.rs Outdated
relative: ".config/tokscale/antigravity-cache/sessions",
pattern: "*.jsonl",
headless: false,
parse_local: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mark antigravity as parseable in local defaults

ClientId::Antigravity is registered with parse_local: false, but default local parse paths (e.g., parse_local_unified_messages and run_clients_command) build their source list from ClientId::iter().filter(|c| c.parse_local()). That means synced Antigravity cache files are omitted unless callers explicitly pass "antigravity", so default local workflows can silently miss this new client’s data. Make Antigravity parse-local (or explicitly include it in those defaults) so the new integration is visible without manual source overrides.

Useful? React with 👍 / 👎.

ddarkr and others added 7 commits April 26, 2026 16:05
Limit stale artifact deletion to session jsonl files under the cache root and include Antigravity in default local parsing so synced sessions are visible without explicit source filters.
Adds Antigravity to ClientFilter (variant + as_filter_str/to_client_id/
from_client_id arms), the legacy hidden `--antigravity` flag in
ClientFlags, the TUI client color palette (#6366F1), and the README
`Possible values` list so the new client is reachable through every
filter surface.
resolve_cache_relative_artifact_path now canonicalizes the resolved
candidate when it exists and verifies the canonical path remains under
the canonical sessions cache root, so a symlink planted inside the
sessions directory cannot redirect deletes to arbitrary files outside
the cache. Adds a regression test that creates a symlink pointing
outside the cache and asserts the deletion is rejected.
@junhoyeo
junhoyeo force-pushed the feat/antigravity-collector branch from 135ac58 to 78706fe Compare April 26, 2026 07:20
@vercel

vercel Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
tokscale Ignored Ignored Preview Apr 26, 2026 7:20am

Request Review

@junhoyeo junhoyeo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for the persistence on this, @ddarkr! The sync-first architecture is the right call — keeps tokscale-core RPC-free and parsable offline. Approving and squash merging with credit to @bruce-shi for the original RPC endpoint discovery in #345.

@junhoyeo junhoyeo changed the title feat(core): add antigravity support feat(antigravity): add Google Antigravity client with sync-first cache parser Apr 26, 2026
@junhoyeo
junhoyeo merged commit d73b4fa into junhoyeo:main Apr 26, 2026
13 of 15 checks passed

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

junhoyeo added a commit that referenced this pull request Apr 26, 2026
…nd client filter UX (#467)

Pre-release correctness and security fixes across the four PRs landed this cycle (#464, #454, #359, #355).

## Antigravity

Trust boundary around the local language-server RPC was too loose:

- Bound RPC body sizes at 16 MiB (Content-Length, chunked, and read-to-end paths)
- Verify process identity by checking the executable path (`lsof` on macOS, `/proc/<pid>/exe` on Linux); accept paths containing either `antigravity` or `language_server` since some Antigravity-flavored servers launch from generic `language_server` binaries with `--app_data_dir antigravity`
- Probe candidate endpoints with a real RPC call and JSON-shape check (probe body capped at 4 KiB) instead of trusting any 200 response; consume HTTP headers before reading body so the cap applies to the JSON body alone
- Lock concurrent syncs on a per-cache PID lock file with bounded retry (3 attempts) instead of unbounded recursion. Eviction is gated on PID liveness only — long-running syncs no longer get stomped on by age-based timeouts.
- Enforce manifest version on load: future versions abort, older versions start fresh
- Recover corrupted manifests by moving them aside as `manifest.json.corrupt-<ts>` instead of failing every subsequent sync

## Codebuff

Parser correctness around silent data loss:

- Accumulate run-state usage across the full reverse `messageHistory` walk instead of returning on the first signal-bearing entry. Previously a newest assistant entry carrying only a model id would short-circuit the walk and silently drop real token counts on earlier entries.
- Include the source-array ordinal in the fallback dedup key so two id-less assistant messages with identical session/timestamp/model/tokens no longer collapse into a single record
- Reject non-positive numeric timestamps in the shared `parse_timestamp_value`/`parse_timestamp_str` helpers so messages with `timestamp: 0` or negative epochs fall through to chat-id / file-mtime fallback chain

## TUI + parsing

User-visible client-filter UX:

- Move `SYNTHETIC_HOTKEY` from `'x'` to `'n'`. `'x'` collided with Mux's hotkey, and the dispatch order made the displayed `[x]` for Synthetic purely cosmetic
- Enable `ignore_case` on `--client/-c` so `OPENCODE`, `Codebuff`, and `antigravity` all parse as the same canonical filter

## Test results

- `cargo test -p tokscale-cli` — 415 unit + 83 integration, all pass
- `cargo test -p tokscale-core` — 566 unit + 10 codebuff + 3 hermes, all pass
- `cargo check --workspace` — clean

Each fix has a regression test where applicable.
junhoyeo added a commit that referenced this pull request Apr 26, 2026
The Korean, Japanese, and Simplified Chinese READMEs were not updated when
Codebuff (#454), Goose (#457), and Antigravity (#355) landed. The English
README also picked up missing Goose and Antigravity entries during this
sweep. Sync all four to the same client list, settings table, Windows
locations, Data Sources sections, and `tokscale antigravity` command
documentation.
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.

2 participants