Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ struct AntigravityCLIHTTPSFetchStrategy: ProviderFetchStrategy {
try await self.fetchBySpawning(
binary: binary,
idleWindow: idleWindow,
resetAfterFetch: resetAfterFetch)
resetAfterFetch: resetAfterFetch,
expectedAccountEmail: expectedAccountEmail)
})
}

Expand Down Expand Up @@ -448,17 +449,23 @@ struct AntigravityCLIHTTPSFetchStrategy: ProviderFetchStrategy {
private func fetchBySpawning(
binary: String,
idleWindow: TimeInterval?,
resetAfterFetch: Bool) async throws -> ProviderFetchResult
resetAfterFetch: Bool,
expectedAccountEmail: String?) async throws -> ProviderFetchResult
{
let session = AntigravityCLISession.shared
let pid = try await session.beginProbe(binary: binary, idleWindow: idleWindow)
let deadline = Date().addingTimeInterval(5.0)
// Fresh `agy` processes take a few seconds to complete macOS keyring
// authentication, then more time before quota endpoints answer. A 5s
// window reliably missed that cold-start window in live tests, so keep
// the readiness deadline long enough for a cold spawn.
let deadline = Date().addingTimeInterval(15.0)
let snap: AntigravityStatusSnapshot
let usage: UsageSnapshot
do {
snap = try await Self.waitForSnapshot(
pid: pid,
deadline: deadline,
expectedAccountEmail: expectedAccountEmail,
dependencies: SnapshotWaitDependencies(
pollIntervalNanoseconds: 200_000_000,
listeningPorts: { pid, timeout in
Expand Down Expand Up @@ -500,6 +507,7 @@ struct AntigravityCLIHTTPSFetchStrategy: ProviderFetchStrategy {
static func waitForSnapshot(
pid: pid_t,
deadline: Date,
expectedAccountEmail: String? = nil,
dependencies: SnapshotWaitDependencies) async throws -> AntigravityStatusSnapshot
{
var lastFetchError: Error?
Expand Down Expand Up @@ -534,7 +542,24 @@ struct AntigravityCLIHTTPSFetchStrategy: ProviderFetchStrategy {
}
if let readySnapshot {
try await Self.checkAuthenticationPrompt(dependencies)
return readySnapshot
if AntigravitySelectedAccountGuard.matches(
snapshotAccountEmail: readySnapshot.accountEmail,
expectedAccountEmail: expectedAccountEmail)
Comment on lines +545 to +547

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 Don't keep polling after a known account mismatch

When auto mode has a selected Antigravity account and the spawned agy session is already returning a different non-empty email, this matches failure is not a readiness condition that polling can fix. The loop now waits until the full 15s deadline before throwing accountMismatch and letting the pipeline fall through to OAuth, whereas before the ready snapshot was returned and the selected-account validation triggered fallback immediately. This makes every refresh stall for users whose local agy is signed into a different account than the selected OAuth account; only the missing-email case should keep waiting.

Useful? React with 👍 / 👎.

{
return readySnapshot
}
// Fresh `agy` processes can answer quota endpoints before the
// signed-in account email is available; keep polling so the
// account guard does not reject the cold-start snapshot.
lastFetchError = AntigravityStatusProbeError.accountMismatch(
expected: expectedAccountEmail,
found: readySnapshot.accountEmail)
Self.log.debug(
"Antigravity CLI HTTPS snapshot account not ready yet",
metadata: [
"pid": "\(pid)",
"ports": ports.map(String.init).joined(separator: ","),
])
}
}

Expand Down
45 changes: 45 additions & 0 deletions Tests/CodexBarTests/AntigravityCLIHTTPSFetchStrategyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,51 @@ struct AntigravityCLIHTTPSFetchStrategyTests {
#expect(snapshot.modelQuotas.first?.modelId == "claude-sonnet")
}

@Test
func `cli HTTPS keeps waiting while snapshot account is not ready yet`() async throws {
let fetchAttempts = AntigravityCLICounter()

let snapshot = try await AntigravityCLIHTTPSFetchStrategy.waitForSnapshot(
pid: 123,
deadline: Date().addingTimeInterval(5),
expectedAccountEmail: "user@example.com",
dependencies: AntigravityCLIHTTPSFetchStrategy.SnapshotWaitDependencies(
pollIntervalNanoseconds: 0,
listeningPorts: { _, _ in [50080] },
drainOutput: { Data() },
fetchSnapshot: { _ in
if fetchAttempts.increment() == 1 {
return AntigravityStatusSnapshot(
modelQuotas: [
AntigravityModelQuota(
label: "Claude Sonnet",
modelId: "claude-sonnet",
remainingFraction: 0.5,
resetTime: nil,
resetDescription: nil),
],
accountEmail: nil,
accountPlan: "Pro",
source: .local)
}
return AntigravityStatusSnapshot(
modelQuotas: [
AntigravityModelQuota(
label: "Claude Sonnet",
modelId: "claude-sonnet",
remainingFraction: 0.5,
resetTime: nil,
resetDescription: nil),
],
accountEmail: "user@example.com",
accountPlan: "Pro",
source: .local)
}))

#expect(fetchAttempts.value == 2)
#expect(snapshot.accountEmail == "user@example.com")
}

@Test
func `cli HTTPS drains output before ports appear`() async throws {
let portPolls = AntigravityCLICounter()
Expand Down