Skip to content

Gemini account switching, Antigravity approvals, and other main updates#3145

Closed
ru-aish wants to merge 14 commits into
pingdotgg:mainfrom
ru-aish:main-update
Closed

Gemini account switching, Antigravity approvals, and other main updates#3145
ru-aish wants to merge 14 commits into
pingdotgg:mainfrom
ru-aish:main-update

Conversation

@ru-aish

@ru-aish ru-aish commented Jun 18, 2026

Copy link
Copy Markdown

This PR merges local main branch updates into origin main.


Open in Devin Review

Note

High Risk
Large surface area: new external provider integration with credential copying on disk, orchestration compaction wiring, and Groq API key handling—any bug could affect auth, conversation state, or secrets.

Overview
Adds a full Antigravity provider path: driver, daemon discovery, transcript streaming with full-access auto-approval, text generation, and an account store that snapshots and restores ~/.gemini auth material for save/switch/remove flows.

Introduces thread context compaction end-to-end (thread.compactcompactConversation / compactThread). Codex delegates to thread/compact/start; Antigravity runs a handoff prompt and spins a new conversation from the summary. Other adapters stub or error until supported.

Claude now treats rejected rate-limit events as turn-failing runtime errors. Checkpoints skip baseline work when the resolved cwd is not a git repo. Desktop persists optional SSH identityFile on saved environments. Static app responses get Permissions-Policy: microphone=(self). Groq speech-to-text transcribes uploaded audio with API key stored via the server secret store (redacted in settings views).

Reviewed by Cursor Bugbot for commit 4064b3a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Antigravity provider, Gemini account switching, voice input, and SSH identity file support

  • Introduces the Antigravity provider driver with a full adapter, text generation backend, settings schema, and UI (icon, settings form, provider card section) for Gemini-based AI sessions.
  • Adds Gemini account management: users can detect, save, switch, remove, and dismiss Antigravity accounts via a new AntigravityAccountSection settings UI and supporting WebSocket RPCs.
  • Adds voice input to the chat composer: records audio via MediaRecorder, transcribes via Groq's Whisper API (configured in general settings), and appends the transcript to the prompt.
  • Adds identityFile support to SSH targets: ssh -G output is parsed for the identity file, -i is passed to SSH commands, targets are distinguished by identity file in connection keys, and a validator fails fast when the file is missing.
  • Adds a compactThread/compactConversation operation across the provider adapter interface, orchestration decider, and ProviderService, with Codex implementing it and Claude/Cursor/OpenCode returning explicit unsupported errors.
  • Increases SSH tunnel ready timeouts (15 s → 180 s, reuse 2 s → 20 s) and adds an extended SSH launch command timeout.
  • Risk: CheckpointReactor now no-ops for non-Git working directories, and SshEnvironmentManager skips interactive auth entirely when an identity file is configured.
📊 Macroscope summarized 4064b3a. 42 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

kiro and others added 14 commits May 30, 2026 14:56
- Detect real pending approvals via GetCascadeTrajectory waiting steps
- Respond via HandleCascadeUserInteraction (allow/deny + scope)
- Two-option approval UI for Antigravity command/file gates
- Stop cancels the cascade (CancelCascadeInvocation) and clears T3 turn state
…ixes

- Antigravity: reopen turn when resumed output arrives after turn.completed
  - Added reopenTurn() helper to mint fresh turn, emit turn.started, set activeTurnId
  - Poll loop now re-maps resumed events with reopened turnId instead of undefined
  - Resumed output now properly framed and session returns to running state
  - Added integration test for resume-only session with reopened turn

- STT: fixed boot crash and typecheck errors
  - GroqSpeechToText: Schema.decodeUnknown → Schema.decodeUnknownEffect (effect 4 beta API)
  - GroqSpeechToText: yield errors directly instead of Effect.fail (effect language service)
  - ws.ts: map ServerSettingsError to SpeechToTextError for RPC error channel match
  - Clears cascade of type inference failures in bin/server/cli tests

All tests pass, typecheck clean, lint 0 errors in changed files.
- Let full-access Antigravity sessions auto-accept permission gates
- Surface clearer microphone errors and require HTTPS for voice input
- Keep stop-generation control visible while running
Add an optional SSH private key path to saved desktop SSH environments so
hosts like Oracle Cloud instances can authenticate without passwords. Pass -i
through ssh commands, skip password prompts for key auth, and persist the key
path across reconnects.

Also extend remote launch readiness timeouts so first-time npx installs on slow
VPS hosts can finish before the launcher gives up.
Copy staged artifacts to a pid-suffixed temp path and rename into place so
rebuilds succeed while a previous AppImage is still running.
Let users save Antigravity credential snapshots from ~/.gemini, switch
between saved accounts, and get prompted when a new authenticated session
is detected. Credential blobs live in T3 state; the UI is in provider
settings for Antigravity instances.
User-facing copy referred to "Gemini accounts" but this feature manages
Antigravity provider credentials under ~/.gemini, not a separate Gemini product.
# Conflicts:
#	apps/server/src/ws.ts
#	apps/web/src/components/chat/ChatComposer.tsx
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dc10d14c-88b1-4e83-8543-e82b81e506f3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jun 18, 2026

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 5 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4064b3a. Configure here.

}
startTranscriptPoller(context);
startGatePoller(context);
emitThreadCompacted(context, updatedAt, { conversationId });

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.

Old poller during compaction

Medium Severity

When finalizing Antigravity compaction, startCompactedConversation awaits new-conversation before stopping the transcript poller or switching conversationId. The old poller can keep emitting events from the pre-compaction conversation during that window, causing stray output or duplicate turn lifecycle events.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4064b3a. Configure here.

activeTurnId: undefined,
updatedAt: context.session.updatedAt,
};
if (shouldFinalizeCompaction) {

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.

Empty compaction not cleared

Medium Severity

If a compaction turn completes without any collected assistant_text, shouldFinalizeCompaction stays false and pendingCompaction is never cleared or reported as failed. The session can remain tied to the old conversation with compaction state stuck indefinitely.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4064b3a. Configure here.

account.id === target.id ? { ...account, lastUsedAt } : account,
),
};
yield* writeRegistry(serverConfig.stateDir, registry);

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.

Auth cleared before restore

High Severity

switchAntigravityAccount calls clearAuthPaths on the live Gemini home before restoreAuthPaths finishes. If restore or snapshot copy fails, the Effect errors out but local Antigravity credentials may already be deleted, leaving the user logged out with a registry that was not updated.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4064b3a. Configure here.

const hasGit = yield* checkpointStore.isGitRepository(checkpointCwd);
if (!hasGit) {
return;
}

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.

Git check mismatch skips baseline

Medium Severity

New early returns use checkpointStore.isGitRepository, while resolveCheckpointCwd already accepted the path via a separate .git existence check. When those disagree, pre-turn baseline capture is skipped silently even though a checkpoint cwd was resolved.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4064b3a. Configure here.

hostname: Schema.String,
username: Schema.NullOr(Schema.String),
port: Schema.NullOr(Schema.Number),
identityFile: Schema.NullOr(Schema.String),

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.

Missing identityFile breaks load

Medium Severity

DesktopSshTargetSchema now requires identityFile, but existing saved-environment records with desktopSsh and no identityFile field will fail registry decode after upgrade, blocking load of previously saved remote environments.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4064b3a. Configure here.

Comment on lines +560 to +578
case "thread.compact": {
yield* requireThread({
readModel,
command,
threadId: command.threadId,
});
return {
...withEventBase({
aggregateKind: "thread",
aggregateId: command.threadId,
occurredAt: command.createdAt,
commandId: command.commandId,
}),
type: "thread.compact-requested",
payload: {
threadId: command.threadId,
createdAt: command.createdAt,
},
};

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.

🟠 High orchestration/decider.ts:560

In the thread.compact case, withEventBase(...) is spread directly without yield*, so the raw Effect object is spread instead of its resolved value. This produces an invalid event object containing Effect internals rather than eventId, aggregateKind, etc. Consider adding yield* to match all other cases in this switch.

      return {
-        ...withEventBase({
+        ...(yield* withEventBase({
           aggregateKind: "thread",
           aggregateId: command.threadId,
           occurredAt: command.createdAt,
           commandId: command.commandId,
-        }),
+        })),
         type: "thread.compact-requested",
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/orchestration/decider.ts around lines 560-578:

In the `thread.compact` case, `withEventBase(...)` is spread directly without `yield*`, so the raw Effect object is spread instead of its resolved value. This produces an invalid event object containing Effect internals rather than `eventId`, `aggregateKind`, etc. Consider adding `yield*` to match all other cases in this switch.

Evidence trail:
apps/server/src/orchestration/decider.ts lines 26-51 (withEventBase returns Effect.Effect<...>), line 567 (missing yield*), git_grep results showing all other 24 call sites use `yield* withEventBase(...)` pattern. Commit: REVIEWED_COMMIT.

});
}

if (registry.activeAccountId) {

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.

🟡 Medium provider/AntigravityAccountStore.ts:571

When registry.activeAccountId is set, switchAntigravityAccount snapshots whatever credentials happen to be in geminiHome without first verifying they belong to the active account. If the user logged into a different Antigravity account externally before calling this function, the code silently overwrites the previously active account's snapshot with the wrong credentials, causing permanent data loss. Consider checking the current fingerprint against active.fingerprint before snapshotting, or document that this function assumes no external credential changes occurred.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/AntigravityAccountStore.ts around line 571:

When `registry.activeAccountId` is set, `switchAntigravityAccount` snapshots whatever credentials happen to be in `geminiHome` without first verifying they belong to the active account. If the user logged into a different Antigravity account externally before calling this function, the code silently overwrites the previously active account's snapshot with the wrong credentials, causing permanent data loss. Consider checking the current fingerprint against `active.fingerprint` before snapshotting, or document that this function assumes no external credential changes occurred.

Evidence trail:
apps/server/src/provider/AntigravityAccountStore.ts lines 553-597 (switchAntigravityAccount function), lines 571-578 (snapshot without fingerprint check), lines 269-283 (snapshotAuthPaths - no identity verification), lines 493-498 (addAntigravityAccount DOES read and verify fingerprint), lines 428-429 (detectAntigravityAccount DOES read and match fingerprint), line 44 (fingerprint field on account schema)

Comment on lines +1461 to +1466
rollbackThread: (threadId) =>
getContext(threadId, "rollbackThread").pipe(
Effect.map((context) => ({
threadId,
turns: context.turns,
})),

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.

🟢 Low Layers/AntigravityAdapter.ts:1461

rollbackThread ignores the numTurns parameter and returns the current thread state without actually rolling back any turns. The interface contract promises to "Roll back a provider thread by N turns", but the implementation only accepts threadId and returns context.turns unchanged.

-    rollbackThread: (threadId) =>
-      getContext(threadId, "rollbackThread").pipe(
-        Effect.map((context) => ({
-          threadId,
-          turns: context.turns,
-        })),
-      ),
+    rollbackThread: (threadId, numTurns) =>
+      getContext(threadId, "rollbackThread").pipe(
+        Effect.map((context) => {
+          const newTurns = context.turns.slice(0, Math.max(0, context.turns.length - numTurns));
+          context.turns = newTurns;
+          return {
+            threadId,
+            turns: newTurns,
+          };
+        }),
+      ),
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/AntigravityAdapter.ts around lines 1461-1466:

`rollbackThread` ignores the `numTurns` parameter and returns the current thread state without actually rolling back any turns. The interface contract promises to "Roll back a provider thread by N turns", but the implementation only accepts `threadId` and returns `context.turns` unchanged.

Evidence trail:
apps/server/src/provider/Layers/AntigravityAdapter.ts lines 1461-1467 (rollbackThread implementation), apps/server/src/provider/Services/ProviderAdapter.ts lines 109-115 (interface definition), apps/server/src/provider/Services/AntigravityAdapter.ts line 4 (AntigravityAdapterShape extends ProviderAdapterShape), apps/server/src/provider/Layers/ProviderService.ts line 990 (caller passing numTurns), apps/server/src/provider/Layers/ClaudeAdapter.ts lines 3820-3824 (reference correct implementation with splice), apps/server/src/provider/Layers/CursorAdapter.ts lines 1113-1124 (reference correct implementation with splice)

return undefined;
}

async function waitForStructuredOutput(input: {

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.

🟡 Medium textGeneration/AntigravityTextGeneration.ts:91

When reading the transcript file incrementally, a partial final line is discarded if stat.size falls mid-line. On the next read, offset advances past the line start, so the continuation is also treated as a new (malformed) line. This can permanently drop a MODEL record containing the JSON output, causing a spurious timeout even though the data was written. Consider buffering any trailing text after the last newline and prepending it to the next read.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/textGeneration/AntigravityTextGeneration.ts around line 91:

When reading the transcript file incrementally, a partial final line is discarded if `stat.size` falls mid-line. On the next read, `offset` advances past the line start, so the continuation is also treated as a new (malformed) line. This can permanently drop a MODEL record containing the JSON output, causing a spurious timeout even though the data was written. Consider buffering any trailing text after the last newline and prepending it to the next read.

Evidence trail:
apps/server/src/textGeneration/AntigravityTextGeneration.ts lines 91-134 (REVIEWED_COMMIT): waitForStructuredOutput function — offset advanced at line 108 before partial-line check, no leftover buffer. apps/server/src/provider/Layers/AntigravityAdapter.ts lines 330-342 (REVIEWED_COMMIT): parseAntigravityTranscriptLine silently returns undefined on JSON.parse failure (catch at line 339-340).

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.

🟢 Low

In the remote backend success path (around line 2317), setSavedBackendSshIdentityFile("") is not called while the other SSH form fields are reset. If a user enters an SSH identity file, switches to remote mode, successfully adds a remote backend, then later reopens the dialog in SSH mode, the identity file field still contains the stale value.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 2314:

In the remote backend success path (around line 2317), `setSavedBackendSshIdentityFile("")` is not called while the other SSH form fields are reset. If a user enters an SSH identity file, switches to remote mode, successfully adds a remote backend, then later reopens the dialog in SSH mode, the identity file field still contains the stale value.

Evidence trail:
apps/web/src/components/settings/ConnectionsSettings.tsx lines 2267-2298 (SSH success path with full reset including setSavedBackendSshIdentityFile at line 2284); lines 2300-2336 (remote success path missing setSavedBackendSshIdentityFile but resetting other SSH fields at lines 2314-2316); line 2026 (state declaration); line 2341 (savedBackendSshIdentityFile in dependency array); line 2782 (identity file form field binding).

@macroscopeapp

macroscopeapp Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

3 blocking correctness issues found. Diff is too large for automated approval analysis. A human reviewer should evaluate this PR.

You can customize Macroscope's approvability policy. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants