Skip to content

feat(agy): replace deprecated gemini CLI runtime with Google Antigravity (agy)#278

Open
ProfSynapse wants to merge 9 commits into
mainfrom
feat/agy-cli-reroute
Open

feat(agy): replace deprecated gemini CLI runtime with Google Antigravity (agy)#278
ProfSynapse wants to merge 9 commits into
mainfrom
feat/agy-cli-reroute

Conversation

@ProfSynapse

Copy link
Copy Markdown
Owner

Summary

Replaces the deprecated gemini CLI runtime with Google Antigravity (agy, v1.0.10) in the google-gemini-cli provider. Provider id google-gemini-cli is preserved for settings compatibility; only the runtime binary, output parsing, model normalization, invocation, and user-facing labels change.

Related to #271 (does not close it — see Verification below).

Approach — Scenario A (zero-footprint, security-first)

  • Binary swap geminiagy (slice a)
  • Plain-text output (slice b): agy --print emits plain text, not JSON. Deleted the --output-format json parse pipeline (~120 LoC) → parseAgyOutput = stdout.trim(); empty stdout → PROVIDER_ERROR; supportsJSON:false. No token-usage available (degrades gracefully).
  • Fail-closed model normalization (slice c): agy --model fails open on an unknown slug (silently substitutes a default), so Nexus validates against a live-anchored allowlist and rejects unknown slugs with CONFIGURATION_ERROR before spawn. gemini-3-flash-previewGemini 3.5 Flash (Medium), gemini-3.1-flash-lite-previewGemini 3.5 Flash (Low).
  • Invocation + security (slice d): agy --print --model <label> --print-timeout 60s [--sandbox].
    • No --dangerously-skip-permissions — live-verified that without it, a built-in tool call hangs on an un-answerable headless permission prompt and is killed (fail-safe; tool never executes).
    • --print-timeout 60s (Go-duration string) is the bounded security kill-switch for that hang (this branch has no idle watchdog yet).
    • Zero config write — deleted the vestigial buildGeminiCliSystemSettings MCP/temp-settings block (agy ignores GEMINI_CLI_SYSTEM_SETTINGS_PATH and the prompt→text path never needed it). No ~/.gemini writes.
    • --sandbox platform-guarded to macOS (verified Seatbelt, Docker-free); off-darwin falls back to the no-MCP + no-skip-perms floor.
    • Env-strip extended with ANTHROPIC_API_KEY + OPENAI_API_KEY (agy fronts Claude/GPT too).
  • Auth probe hardening (R7): tolerant presence-only check on oauth_creds.json — boolean only, token value never read/logged/returned.
  • UI relabel (slice e): "Antigravity CLI / Google (Antigravity)". Provider id unchanged.

Testing

  • Full suite: 3717 passed / 21 skipped / 1 failed. The single failure (TaskBoardEditCoordinator.test.ts, obsidian-mock Modal export gap) is pre-existing and unrelated — proven via stash-and-retest, zero agy references.
  • Build (lint + tsc + esbuild + connector): green.
  • +16 net-new tests: fail-closed normalize allowlist, a live agy models anchor test (pins the two label mappings so catalog drift fails at unit-test time), env-strip (Google + Anthropic + OpenAI), and a Scenario-A "no temp-settings file written" assertion.

Verification — NOT yet manually tested

⚠️ Implemented, pending manual Obsidian test. Verified by unit tests + build + live agy smoke only. Before merge, a manual round-trip in Obsidian is needed (provider selection, a real completion via agy, auth flow). Issue #271 stays open until that manual verification passes.

Manual-test residuals

  • Cross-platform --sandbox: verified darwin-only; Linux/Windows need a per-platform live-verify before --sandbox is ever enabled off-darwin (guarded off there today).
  • Auth: agy has no auth subcommand — first run is bare agy → browser Google sign-in (writes ~/.gemini/oauth_creds.json).

Notes

  • src/utils/connectorContent.ts is intentionally not committed (generated artifact; regenerated locally/CI).

🤖 Generated with Claude Code

ProfSynapse and others added 9 commits June 22, 2026 12:14
UI-only brand relabel of the google-gemini-cli provider from Gemini to
Antigravity across 3 display surfaces. Provider id 'google-gemini-cli'
unchanged byte-for-byte (settings compat). Runtime-coupled strings
(command tokens, signupUrl, auth-flow) deferred to slice d.

- ProviderUtils.ts: 'Google (Gemini CLI)' -> 'Google (Antigravity)'
- ProvidersTab.ts: name/keyFormat/providerLabel -> 'Antigravity CLI'
- ModelDropdownRenderer.ts: label-map + per-model suffix '(Antigravity CLI)'

Part of #271 AGY CLI re-route.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
…fail-closed model normalize, tolerant auth probe (slices a/b/c + R7)

Replaces the deprecated gemini CLI runtime with Antigravity CLI (agy) in
the google-gemini-cli provider. Check-independent slices only; slice d
(invocation flags / temp-settings-MCP / env-strip / skip-permissions)
remains gated on a user verification.

- (a) binary swap: resolveDesktopBinaryPath('gemini') -> 'agy' (geminiCli.ts:49)
- (b) delete the gemini --output-format json parse pipeline (JSON type + 7
  extract helpers) -> thin parseAgyOutput seam (stdout.trim); remove the now-
  unsupported --output-format json arg; usage degrades to zero (agy reports
  none); empty stdout -> PROVIDER_ERROR; supportsJSON:false correctness fix
- (c) new geminiCliModelNormalize.ts: fail-CLOSED allowlist mapping legacy
  specs -> agy human labels; reject unknown slugs with CONFIGURATION_ERROR
  before spawn (agy --model fails OPEN, so Nexus must validate)
- (R7) GeminiCliAuthService: strict whole-file JSON.parse -> tolerant
  access_token-presence scan (whole-parse / NDJSON / structural regex).
  Security invariant: boolean-only, token value never read/logged/returned

Adapter test rewritten to the agy plain-text contract (6/6). Build green.
Part of #271 AGY CLI re-route.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
…strip, drop vestigial MCP/temp-settings (Scenario A)

Invocation now: agy --print --model <normalized-label> --print-timeout 60s [--sandbox]
with the prompt on stdin. --print-timeout is a named const (Go-duration string)
and the bounded security kill-switch for a hung headless tool-permission block
(no skip-perms, no idle watchdog on this branch). --sandbox is additive
defense-in-depth, platform-guarded to darwin (macOS Seatbelt, Docker-free);
non-darwin falls back to the no-MCP + no-skip-perms floor.

Deletes the vestigial buildGeminiCliSystemSettings MCP/temp-settings block, the
temp-settings file write, and the GEMINI_CLI_SYSTEM_SETTINGS_PATH env pointing
(agy ignores it and the completion path is pure prompt->text). No config write,
no --dangerously-skip-permissions. env-strip extended with ANTHROPIC_API_KEY +
OPENAI_API_KEY. Prunes now-dead connectorPath/serverKey from GeminiCliRuntime.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
…models anchor + env-strip (Anthropic/OpenAI) + Scenario A no-config

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
Peer-review blocking findings (B1-B4): user-facing copy slice-e's 3-file
relabel didn't reach. All misdirected users to the deprecated/nonexistent
gemini binary.

- ProvidersTab: statusHint no longer says 'run gemini auth' (agy has no auth
  subcommand); description -> Antigravity/agy framing; signupUrl dropped to ''
  with TODO (authoritative Antigravity docs URL TBD; not fabricated)
- ProviderManager:327-328: provider name 'Gemini CLI' -> 'Antigravity CLI'
- GeminiCliAuthService:35/46/58: auth-error guidance -> canonical agy flow
  (run agy once -> browser sign-in); R7 presence-only probe invariant untouched
- GoogleGeminiCliAdapter:213/220 + OAuthBannerComponent + types.ts: stale
  'Gemini CLI' error/JSDoc copy aligned to agy
- tests: +1 multiline parseAgyOutput fixture (trim preserves internal newlines)

provider-id google-gemini-cli byte-preserved. connectorContent.ts excluded.
…agy models

Replace the stale 2-entry '*-preview' catalog with the 5 Gemini variants agy
actually serves (Gemini 3.5 Flash Low/Medium/High, Gemini 3.1 Pro Low/High),
labels copied verbatim from live `agy models`. Drop 'Preview' names; default
model gemini-3-flash-preview -> gemini-3.5-flash-medium.

Normalize allowlist kept in lockstep (closes review Future-finding F2): all 5
new slugs map to exact agy labels; both legacy *-preview slugs retained as
aliases for settings-compat; unknown slugs still fail-closed. Provider-id
google-gemini-cli byte-preserved; R7 auth probe + invocation/sandbox/env-strip
untouched. Catalog + normalize test pins updated to the 5-slug list.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
agy (Antigravity CLI) supports no tool/function calling and no streaming via
its headless --print surface (proven NOT-FEASIBLE across native-execute,
MCP-only, and emit-don't-execute spikes; memory 95feb811). The model catalog
was lying about this with supportsFunctions:true.

- Flip supportsFunctions:true->false on all 5 agy ModelSpecs as the honest
  capability SSOT (supportsStreaming already false)
- Generalize the proven Perplexity text-only seam into isTextOnlyProvider()
  over a TEXT_ONLY_PROVIDERS set {perplexity, google-gemini-cli}; add
  google-gemini-cli to PROVIDERS_WITHOUT_EXPLICIT_TOOL_SCHEMAS so tool schemas
  are no longer silently sent to a provider that can't use them
- Settings notice: generalize renderPerplexityWarning ->
  renderTextOnlyProviderWarning with Antigravity copy covering BOTH limits
  (no tools/agents, no streaming); chat + agent variants
- Runtime guard: non-silent Notice in ChatSendCoordinator when a text-only
  provider is active AND the user invoked tools/prompts for that send
- SubagentExecutor: isPerplexityProvider -> isTextOnlyProvider for the
  text-only subagent prompt branch
- Add TextOnlyProviderSeam.test.ts (8 cases: SSOT, seam classification,
  schema suppression, webllm exclusion)

Warning/UX only -- does NOT re-enable agy tool-use (closed; memory 95feb811).
Part of PR #278 (issue #271). Pending manual Obsidian verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
Deeper coverage for the Antigravity text-completion-only warning (3e91675),
beyond the existing TextOnlyProviderSeam.test.ts (8 cases).

- ChatSettingsRendererTextOnlyWarning.test.ts (NEW, 10 cases): Antigravity
  warning copy renders and names BOTH limits (no tools/agents, no streaming)
  for chat + agent variants; Perplexity copy pinned unchanged; tool-capable
  providers render nothing. Invokes the real copy methods (coupled to source
  SSOT, not a re-typed fixture).
- ChatSendCoordinator.test.ts (+5 cases): runtime guard through the real
  handleSendMessage — Notice fires exactly once (6000ms) for text-only+tools
  and text-only+prompts; silent on plain-text send, empty arrays, and a normal
  tool-capable provider with tools. Paired fire-vs-silence cases falsify an
  inert always-fire/never-fire guard.

Full suite 3747 passed / 0 failed. Part of PR #278 (issue #271).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
Hygiene follow-up to the text-only warning (architect verify #71).

- GoogleGeminiCliAdapter.getCapabilities() now returns supportsFunctions:false,
  matching the ModelSpecs SSOT (was still true). Provably non-functional —
  nothing tool-gates on provider-level getCapabilities; dispatch gating is
  100% via the provider seam — pure honesty/consistency.
- isPerplexityProvider: JSDoc note marking it a deliberate narrow predicate
  (do-not-broaden / do-not-delete) now that isTextOnlyProvider is the general
  seam. Fn + test untouched.

Full suite 3747 passed. Part of PR #278 (issue #271).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01NxKeRz1gihguL9wcidm78m
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.

1 participant