Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3481c49
Delete dead OpenCode scraper module
Finesssee Oct 10, 2026
e974e9b
Delete dead MiniMax localStorage importer
Finesssee Oct 10, 2026
0f76a5f
Share the OpenCode server-function request builder
Finesssee Oct 10, 2026
c8927f6
Table-drive OpenRouter key-meter and OpenCode parser tests
Finesssee Oct 10, 2026
101d979
Share the OpenRouter bearer JSON GET and spend-window table
Finesssee Oct 10, 2026
8a5703b
Share OpenRouter and OpenCode Go error constructors
Finesssee Oct 10, 2026
7aea531
Share the OpenCode Go snapshot builder
Finesssee Oct 10, 2026
0c24a44
Extract OpenCode Go local window and month helpers
Finesssee Oct 10, 2026
26cb94b
Move OpenCode Go local reader tests into local/tests.rs
Finesssee Oct 10, 2026
200592d
Share OpenCode Go local test fixtures
Finesssee Oct 10, 2026
47115d7
Share Kimi clock, integer and client helpers (PBG-36)
Finesssee Oct 10, 2026
82d75e6
Settle Kimi web token attempts in one place (PBG-35)
Finesssee Oct 10, 2026
b3282b0
Share Kimi web snapshot and rate-limit test helpers (PBG-64)
Finesssee Oct 10, 2026
55674d5
Share the MiniMax HTTP client, console GET and status mapping (PBG-08)
Finesssee Oct 10, 2026
df5e3ba
Share MiniMax row windows and the billing window table (PBG-37)
Finesssee Oct 10, 2026
a4f7826
Table-drive MiniMax coding-plan lanes, reset text and clock rollover …
Finesssee Oct 10, 2026
1e5a7da
Share MiniMax billing-record and base_resp test tables (PBG-64)
Finesssee Oct 10, 2026
cc822ef
Move MiniMax provider tests into minimax/tests.rs
Finesssee Oct 10, 2026
f265576
Move MiniMax billing summary into minimax/billing.rs
Finesssee Oct 10, 2026
d7d72f2
Satisfy clippy in the Kimi and OpenRouter table tests
Finesssee Oct 10, 2026
91468aa
Pin Antigravity SQLite schema inspection and row byte charging
Finesssee Oct 10, 2026
ef7c32b
Share Antigravity SQLite row checks and schema inspector (PBG-17)
Finesssee Oct 10, 2026
ff5bcf2
Pin Antigravity IDE flag capture and port precedence
Finesssee Oct 10, 2026
1af8111
Share Antigravity loopback client and user-status request (PBG-18)
Finesssee Oct 10, 2026
38518c1
Pin Antigravity group family titles and model window slugs
Finesssee Oct 10, 2026
efd9893
Share Antigravity group family, slug, version probe and proto checks …
Finesssee Oct 10, 2026
7d24f7a
Share Antigravity protobuf test fixtures (PBG-57)
Finesssee Oct 10, 2026
1431553
Share Antigravity SQLite test database helpers (PBG-58)
Finesssee Oct 10, 2026
8c1d7ec
Table-drive Antigravity process, user-status and fallback tests (PBG-59)
Finesssee Oct 10, 2026
720d78b
Share Antigravity session-reader, step and offline-reason test helper…
Finesssee Oct 10, 2026
dce376a
Revert "Delete dead MiniMax localStorage importer"
Finesssee Oct 10, 2026
b0fe165
Pin MiniMax coding-plan page headers and the remains no-plan error
Finesssee Oct 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions rust/src/providers/antigravity/cli_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,15 @@ pub(super) async fn managed_spawn_is_csrf_gated(binary: Option<PathBuf>) -> bool
let Some(binary) = binary else {
return false;
};
let Ok(version) =
run_cli_command(&binary, &VERSION_ARGS, VERSION_TIMEOUT, VERSION_TOO_LARGE).await
else {
return false;
};
let version = String::from_utf8_lossy(&version);
is_csrf_gated_version(version.trim())
agy_version(&binary, VERSION_TIMEOUT)
.await
.is_ok_and(|version| is_csrf_gated_version(&version))
}

/// `agy --version` output, trimmed.
async fn agy_version(binary: &Path, timeout: Duration) -> Result<String, LiveFailure> {
let version = run_cli_command(binary, &VERSION_ARGS, timeout, VERSION_TOO_LARGE).await?;
Ok(String::from_utf8_lossy(&version).trim().to_string())
}

async fn fetch_print_usage(binary: &Path) -> Result<ProviderFetchResult, LiveFailure> {
Expand All @@ -161,10 +163,7 @@ async fn fetch_print_usage_with_version_timeout(
binary: &Path,
version_timeout: Duration,
) -> Result<ProviderFetchResult, LiveFailure> {
let version =
run_cli_command(binary, &VERSION_ARGS, version_timeout, VERSION_TOO_LARGE).await?;
let version = String::from_utf8_lossy(&version);
if !is_supported_version(version.trim()) {
if !is_supported_version(&agy_version(binary, version_timeout).await?) {
return Err(ProviderError::Parse(
"Antigravity CLI usage reports require agy 1.1.11 or later".into(),
)
Expand Down
18 changes: 9 additions & 9 deletions rust/src/providers/antigravity/legacy_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ pub(crate) struct UserStatusResponse {
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct UserStatus {
#[allow(
dead_code,
reason = "field mirrors the Antigravity API user payload; deserialized for round-trip fidelity but not read yet"
)]
email: Option<String>,
plan_status: Option<PlanStatus>,
user_tier: Option<UserTier>,
Expand Down Expand Up @@ -224,9 +220,14 @@ fn model_window_id(config: &ModelConfig) -> String {
.as_deref()
.or(config.id.as_deref())
.unwrap_or_else(|| model_label(config));
let raw = canonical_model_id(raw);
let slug = raw
.chars()
let slug = slug(canonical_model_id(raw));
format!("model-{}", if slug.is_empty() { "unknown" } else { &slug })
}

/// Lowercase ASCII alphanumerics; every other character becomes `-`, and
/// leading or trailing dashes are dropped.
pub(super) fn slug(raw: &str) -> String {
raw.chars()
.map(|ch| {
if ch.is_ascii_alphanumeric() {
ch.to_ascii_lowercase()
Expand All @@ -236,8 +237,7 @@ fn model_window_id(config: &ModelConfig) -> String {
})
.collect::<String>()
.trim_matches('-')
.to_string();
format!("model-{}", if slug.is_empty() { "unknown" } else { &slug })
.to_string()
}

fn rate_window_from_quota(quota: &QuotaInfo) -> RateWindow {
Expand Down
29 changes: 13 additions & 16 deletions rust/src/providers/antigravity/local_bot_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,7 @@ pub(super) fn append_recovered_events(
continue;
}
if bot_id_uses.get(bot_id) == Some(&1) {
let mut turn = pending.turn.clone();
turn.timestamp_ms = Some(exact.timestamp_ms);
events.push(Event {
session: session.to_string(),
row: pending.row,
turn,
total: pending.total,
});
events.push(recovered_event(session, pending, exact.timestamp_ms));
recovered += 1;
continue;
}
Expand All @@ -141,16 +134,20 @@ pub(super) fn append_recovered_events(
let Some(timestamp_ms) = timestamps.get(*offset) else {
continue;
};
let mut turn = pending.turn.clone();
turn.timestamp_ms = Some(*timestamp_ms);
events.push(Event {
session: session.to_string(),
row: pending.row,
turn,
total: pending.total,
});
events.push(recovered_event(session, pending, *timestamp_ms));
recovered += 1;
}
events.sort_by_key(|event| event.row);
recovered
}

fn recovered_event(session: &str, pending: &PendingTimestampRow, timestamp_ms: i64) -> Event {
let mut turn = pending.turn.clone();
turn.timestamp_ms = Some(timestamp_ms);
Event {
session: session.to_string(),
row: pending.row,
turn,
total: pending.total,
}
}
10 changes: 2 additions & 8 deletions rust/src/providers/antigravity/local_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@ use chrono::{DateTime, Utc};

use crate::spend_contract::{LocalHistoryCoverage, LocalTokenHistorySummary};

fn clean_env_path(value: Option<&str>) -> Option<PathBuf> {
value
.map(str::trim)
.filter(|value| !value.is_empty())
.map(PathBuf::from)
}

fn configured_database_roots(home: &Path) -> [PathBuf; 3] {
let gemini_cli_home = std::env::var("GEMINI_CLI_HOME").ok();
configured_database_roots_from_values(home, gemini_cli_home.as_deref())
Expand All @@ -25,7 +18,8 @@ fn configured_database_roots_from_values(
home: &Path,
gemini_cli_home: Option<&str>,
) -> [PathBuf; 3] {
let gemini_base = clean_env_path(gemini_cli_home).unwrap_or_else(|| home.join(".gemini"));
let gemini_base =
local_sessions::clean_env_path(gemini_cli_home).unwrap_or_else(|| home.join(".gemini"));
local_sqlite::database_roots(&gemini_base)
}

Expand Down
71 changes: 34 additions & 37 deletions rust/src/providers/antigravity/local_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,6 @@ fn identity_text(field: Field<'_>) -> Option<Option<String>> {
Some((!value.trim().is_empty()).then(|| value.to_string()))
}

fn auxiliary_text(field: Field<'_>) -> Result<Option<String>, ()> {
let value = std::str::from_utf8(message(field).ok_or(())?).map_err(|_| ())?;
Ok((!value.trim().is_empty()).then(|| value.to_string()))
}

#[derive(Debug, Default)]
struct AuxiliaryIdentifier {
value: Option<String>,
Expand All @@ -150,12 +145,9 @@ impl AuxiliaryIdentifier {
if !self.valid {
return;
}
match auxiliary_text(field) {
Ok(value) => self.value = value,
Err(()) => {
self.value = None;
self.valid = false;
}
match identity_text(field) {
Some(value) => self.value = value,
None => self.invalidate(),
}
}

Expand All @@ -165,11 +157,20 @@ impl AuxiliaryIdentifier {
}
}

/// Positive and no later than 9999-12-31T23:59:59Z.
fn valid_seconds(seconds: u64) -> bool {
seconds != 0 && seconds <= 253_402_300_799
}

fn valid_nanos(nanos: u64) -> bool {
nanos <= 999_999_999
}

fn timestamp_millis(seconds: Option<u64>, nanos: u64) -> Option<Option<i64>> {
let Some(seconds) = seconds else {
return Some(None);
};
if seconds == 0 || seconds > 253_402_300_799 || nanos > 999_999_999 {
if !valid_seconds(seconds) || !valid_nanos(nanos) {
return None;
}
let seconds = i64::try_from(seconds).ok()?;
Expand Down Expand Up @@ -302,29 +303,17 @@ fn parse_generation(bytes: &[u8], seconds: &mut Option<u64>, nanos: &mut u64) ->
fn parse_timestamp_field(bytes: &[u8], seconds: &mut Option<u64>, nanos: &mut u64) -> Option<()> {
fields(bytes, |stamp| {
match stamp.number {
1 => {
let value = integer(stamp)?;
if value == 0 || value > 253_402_300_799 {
return None;
}
*seconds = Some(value);
}
2 => {
let value = integer(stamp)?;
if value > 999_999_999 {
return None;
}
*nanos = value;
}
1 => *seconds = Some(integer(stamp).filter(|value| valid_seconds(*value))?),
2 => *nanos = integer(stamp).filter(|value| valid_nanos(*value))?,
_ => {}
}
Some(())
})
}

/// Protobuf encoders for building test blobs.
#[cfg(test)]
mod tests {
use super::*;
pub(super) mod test_fixtures {
fn varint(mut value: u64) -> Vec<u8> {
let mut bytes = Vec::new();
loop {
Expand All @@ -339,17 +328,25 @@ mod tests {
}
}
}
fn field_varint(number: u64, value: u64) -> Vec<u8> {
let mut b = varint(number << 3);
b.extend(varint(value));
b

pub(crate) fn field_varint(number: u64, value: u64) -> Vec<u8> {
let mut bytes = varint(number << 3);
bytes.extend(varint(value));
bytes
}
fn field_bytes(number: u64, value: &[u8]) -> Vec<u8> {
let mut b = varint((number << 3) | 2);
b.extend(varint(value.len() as u64));
b.extend(value);
b

pub(crate) fn field_bytes(number: u64, value: &[u8]) -> Vec<u8> {
let mut bytes = varint((number << 3) | 2);
bytes.extend(varint(value.len() as u64));
bytes.extend(value);
bytes
}
}

#[cfg(test)]
mod tests {
use super::test_fixtures::{field_bytes, field_varint};
use super::*;
#[test]
fn decodes_generation_usage_and_timestamp() {
let mut usage = Vec::new();
Expand Down
Loading