Skip to content

fix(antigravity): WSL transcript lookup and command approvals in Chat - #24141

Closed
sojiro-o wants to merge 3 commits into
stablyai:nwparker/agy-chat-permissionfrom
sojiro-o:sojiro-o/agy-wsl-chat
Closed

sojiro-o wants to merge 3 commits into
stablyai:nwparker/agy-chat-permissionfrom
sojiro-o:sojiro-o/agy-wsl-chat

Conversation

@sojiro-o

@sojiro-o sojiro-o commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

When Antigravity (agy) runs inside WSL on Windows, the Chat view could lose track of the conversation file, and it never showed the Allow/Deny card when agy asked to run a command — the chat just looked busy while the terminal waited. Both now work for WSL panes.

What Changed

Two small WSL-only fixes on top of the Antigravity Chat stack (#21660, #21776):

  1. Finding the transcript by conversation id. Before: when the hook-reported transcript path was absent, the id lookup only searched the Windows home (C:\Users\…\.gemini\antigravity-cli\brain), so a WSL session was never found. After: it tries the Windows brain first, then each running distro's home (\\wsl.localhost\<distro>\home\…\.gemini\…), mirroring the existing Codex WSL fallback (wslCodexSessionsDirs). Existing exact-path rules are unchanged: an attested distro or a guest hook path never falls back to an id match elsewhere, and a stalled distro still reports "unavailable", not "missing".
  2. Command approvals from WSL panes. Before: status rows delivered through the WSL hook relay carry a wsl:<distro> connection id, and the screen-approval publisher/ingest rejected any connection id as a direct-SSH mirror, so the card was never raised. After: wsl: ids are accepted (the pty is on this host), direct SSH stays excluded, and the runtime binds a wsl: row only to a WSL pty of the same distro (antigravityHookRowMatchesPty). No screen-matching rule changed — the captured approval screen on WSL agy 1.2.14 matches the existing rule line for line.

Why

  • Other readers already treat relay rows as local via isWslHookRelayConnectionId (e.g. runtime-worktree-pty-agent-sources.ts); the approval path was the one place that did not.
  • Reusing the Codex WSL home enumeration keeps the WSL cost (spawning wsl.exe) behind a host miss and inherits the existing stalled-distro gate, instead of adding a new scan.

Linked Issue

Refs #20157 (WSL item). Follow-up to #21660 and #21776.

Visual Proof

Before: agy asks Run this command? in the terminal while Chat shows only the pending run_command.
1-before-terminal-asks
2-before-chat-no-card

After: the same request raises the Allow/Deny card in Chat; Allow runs it and Deny stops it.
3-after-chat-approval-card

Testing

Platform: Windows 11 (build 26200) + WSL2 Ubuntu 26.04, agy 1.2.14.

  • I manually tested these changes locally
    • Ran the resolver on real Windows Node against a real WSL transcript. Before: id-only lookup returned null. After: \\wsl.localhost\Ubuntu-26.04\home\…\transcript.jsonl in ~300 ms. Guest-hook-path, missing-id and wrong-distro cases were unchanged.
    • Dev build, WSL agy pane, permission mode set to Manual: the approval card appeared, Allow ran sleep 8 && echo ok and the reply rendered, and Deny stopped a second request. Chat rendering and Japanese/multi-line input also worked.
  • Automated tests added/updated
    • session-file-resolver-antigravity-wsl.test.ts (9 cases); 3 fail on the parent commit.
    • WSL relay cases in server-ingest-antigravity-screen.test.ts and antigravity-screen-permission-publisher.test.ts, plus a pty-matching table; 2 fail on the parent commit.
    • Neighbouring suites pass (resolver, host-readable path, WSL relay, approval screen, readiness).
    • Per-file oxlint/oxfmt pass. Changed-code quality has 0 new findings. A typecheck scoped to the changed files is clean; full pnpm tc is left to CI (the local machine has 8 GB of RAM).

Not verified: WSL paired/mobile runtime, and a hook-less Orca restart restoring a WSL Antigravity tab (the id-only path is covered by the live resolver run above, not through the UI).

Note for testers: Orca launches agy with --dangerously-skip-permissions by default (DEFAULT_TUI_AGENT_ARGS), so switch Antigravity to Manual to see approvals. On a Windows dev checkout, run pnpm run build:relay before pnpm dev; otherwise WSL panes get no hook relay and Chat never binds to the transcript.

AI Disclosure

Claude Opus 5.5 (Claude Code) investigated, implemented and ran the verification with me; I reviewed the changes and did the manual UI testing.

Review

Direct SSH behaviour is unchanged and still covered by the existing tests. No wire, opcode or status-store shape changes.

Agent skill upstream boundary

  • Not applicable.

Notes

Security: no new paths are opened beyond \\wsl.localhost homes of running distros, and conversation ids are still restricted to one path segment. Cross-platform: the fallback runs only on win32. SSH: unchanged. Mobile: no change. Performance: the WSL enumeration runs only after a Windows-home miss.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred) — focused checks local, full suite via CI

…ation id

On Windows, agy started in a WSL pane writes its transcript under the
guest home, but the id-based lookup only searched the Windows home. When
the hook-reported path is absent, Chat now tries the host brain first and
then each running distro's home, reusing the Codex WSL fallback shape.
Attested distros, guest hook paths and stalled-distro refusals keep their
existing exact-path rules.
Status rows delivered through the WSL hook relay carry a `wsl:<distro>`
connection id, so the screen-approval publisher and ingest treated them
as direct-SSH mirrors and never raised the Allow/Deny card. WSL relay ids
are now accepted, while the runtime only binds such a row to a WSL pty of
the same distro. Direct SSH stays excluded.
@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Adds WSL relay support to command approval flow.

The PR is not yet safe to merge because a WSL discovery failure can still make an unexamined transcript appear missing.

Findings

  1. P1 Failed discovery looks like absence ▶
  2. P2 Repeated WSL home probes ▶

Summary

The PR adds a Windows-host fallback for finding Antigravity transcripts in running WSL distributions and allows WSL relay status rows to produce command-approval cards when bound to a matching WSL PTY.

  • The changes since the previous review share one running-distro snapshot across each fallback attempt and check cancellation around its creation.
  • No new actionable issue was established by those changes.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Antigravity conversation ID] --> B{Windows-home transcript exists?}
  B -->|Yes| C[Use host transcript]
  B -->|No, on Windows| D[Snapshot running WSL distros and homes]
  D --> E[Check guest transcript candidates]
  E --> F[Use first readable transcript]
  G[WSL relay status row] --> H{Matches owning WSL PTY?}
  H -->|Yes| I[Read approval screen]
  I --> J[Publish Allow/Deny card]
Loading

Reviews (2) · Last reviewed commit: "fix(antigravity): share one WSL snapshot..."

}
// Why: enumerating WSL homes spawns wsl.exe, so only pay it after the host misses.
let unavailable: WslTranscriptFsError | undefined
for (const candidate of await wslAntigravityTranscriptPaths(conversationId)) {

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 Failed discovery looks like absence If the first running-distro probe fails and there is no cached result, WSL discovery returns no homes. This loop then returns null, treating the Antigravity transcript as missing even though it was never checked. A WSL conversation can appear absent during a discovery outage instead of being reported as temporarily unavailable.

Knowledge Base Used:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed that a failed running-distro probe looks like "no homes". This comes from the shared probe: resolveRunningWslDistros swallows the failure and returns the last known list, or [], and the existing Codex WSL fallback inherits the same behaviour. For Chat this means a pending transcript rather than a terminal "missing": transcript-watch keeps re-resolving every 0.5–5 s and binds once the probe recovers. Reporting it as unavailable would mean changing that shared probe for every WSL reader, so I'd prefer to handle it as a separate change. I'm happy to add it here if maintainers want it in this PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That’s a fair clarification. Given resolveRunningWslDistros deliberately converts discovery failures into the cached list (or []), this resolver cannot distinguish “no running WSL homes” from “discovery failed” without changing the shared probe contract. Here, null means the transcript remains unresolved: transcript-watch keeps retrying and can bind once discovery recovers, rather than surfacing a terminal missing state.

I’ll withdraw this finding; preserving unavailable-vs-missing semantics across all WSL readers is better handled as a separate change.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

Comment on lines +308 to +310
const homeDirs = deps.wslSnapshot
? await snapshotHomeDirs(deps.wslSnapshot)
: await resolveWslHomeDirs(deps.listWslHomeDirs)

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 Repeated WSL home probes When an id-only Antigravity transcript has not been written yet, Chat retries the lookup. This default home loader bypasses the existing home-directory cache, so each host miss can repeat running-distro and home probes, adding avoidable wsl.exe work while Chat waits.

Knowledge Base Used: Limit WSL session scans to running distros

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 1c94a41. Home dirs were already cached by getWslHomeAsync, but the running-distro list was being fetched for home discovery and again for every candidate path. The fallback now builds one createWslTranscriptResolutionSnapshot per attempt and passes it to both, which is how the Codex path works. A new test asserts one running-distro probe per attempt.

Chat re-resolves an unwritten transcript every few seconds, and the WSL
fallback listed running distros once for home discovery and again for
every candidate path. One resolution snapshot now serves the whole
attempt, as the Codex path does, and a cancelled lookup no longer starts
WSL discovery.

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

✅ No new issues found.

Reviewed changes

Two WSL-only follow-ups on the Antigravity Chat stack. I read the full diff, traced the affected call paths, and reran the focused and neighboring suites (all green).

  • Id-based transcript lookup falls back to WSL guests — resolveAntigravitySessionFile now tries the host brain first, then each running distro's guest brain via the new wslAntigravityTranscriptPaths, mirroring the Codex fallback. Host hits and explicit antigravityBrainDir overrides still short-circuit, and an attested distro or guest hook path still never falls back to an id match (the outer gates in resolveSessionFilePath are intact).
  • Stalled-distro handling — the WSL loop defers a stalled distro as unavailable without hiding a later distro's hit, and throws WslTranscriptFsError when no hit was found but a distro never answered, so a stall reads as "unavailable", not "missing". Non-refusal errors are rethrown rather than swallowed.
  • WSL command approvals — the screen ingest and publisher now accept wsl: relay connection ids while still rejecting SSH mirrors, and the runtime binds a row to a pty only through antigravityHookRowMatchesPty (same distro, WSL pty). I verified the isWsl === true guard holds in production: the renderer spawn path and controller inventory both set isWsl: true for WSL panes, so it will not false-negative normal WSL use.

The new tests are behavioral, not tautological — the resolver, ingest, and publisher cases each fail on the parent commit as the author states. oxlint is clean over the changed files.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

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

✅ No new issues found.

Reviewed changes

Delta since the prior pullfrog review (e0a3931): one commit, 1c94a41 ("share one WSL snapshot per transcript lookup"), plus its test updates. All other files are unchanged.

  • One WSL snapshot per attempt — resolveAntigravitySessionFile now builds a single createWslTranscriptResolutionSnapshot() after the host miss and threads it through both wslAntigravityTranscriptPaths and each toHostReadableTranscriptPath probe, so listRunningWslDistrosAsync / getWslHomeAsync run once per resolve instead of once per candidate.
  • Explicit Windows gate and abort checks — an early process.platform !== 'win32' return now precedes the snapshot, and signal?.throwIfAborted() brackets it so a cancelled Chat lookup never starts WSL discovery.
  • Tests — the resolver suite is now 11 cases: the existing host/override/attested-path cases assert against listRunningWslDistrosAsync (the probe the snapshot now uses), and two new cases pin "probes distros once per attempt" and "does not start WSL discovery for a cancelled lookup". I reran it: 11 pass.

The single-snapshot change is a correctness-neutral performance fix; the wslSnapshot is only used to short-circuit the running-distro filter, and the existence probe still runs per candidate, so the stalled-distro semantics from the prior review are unchanged.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pullfrog

pullfrog Bot commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

This run hit its time limit while still working, so it stopped before finishing.

Give runs longer with --timeout=2h (or --notimeout) in this repo's instructions — or raise the workflow's timeout input if it sets one, since that input wins. A smaller PR or a lower effort also finishes sooner.

Repo settings → · Flags →

agent run timed out after 1h

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

nwparker added a commit that referenced this pull request Oct 2, 2026
Recover scoped transcript, terminal approvals, and WSL support on current main.
Keep hook-server authority, captured-grid rules, quiescence, and current journals.
Negotiate Antigravity reads and subscriptions on desktop, web, and mobile.

Credits #15773, #21660, #21776, and #24141.

Co-authored-by: haoliangli <haoliangli@users.noreply.github.com>
Co-authored-by: sojiro-o <53679703+sojiro-o@users.noreply.github.com>
nwparker added a commit that referenced this pull request Oct 4, 2026
Preserves accepted Antigravity Chat source from @haoliangli (#15773) and @sojiro-o (#24141).
Carries runtime-owned Chat association and authoritative ruled-screen publication onto fixed main 752871b.
nwparker added a commit that referenced this pull request Oct 4, 2026
Antigravity records first turns at whole seconds, leaving a millisecond
composer echo visible below later turns. Publish optional source precision
and use it when matching local sends and seeded launch prompts; retain strict
transcript boundaries and exact matching when precision is absent.

Credits @sojiro-o/#25117 for the first-send diagnosis and proposed regression.
Retains the Antigravity Chat contributions from @haoliangli/#15773 and
@sojiro-o/#24141 without changing accepted readiness or capture assets.

Co-authored-by: sojiro-o <53679703+sojiro-o@users.noreply.github.com>
nwparker added a commit that referenced this pull request Oct 4, 2026
Compose main 2b3b692 with the
complete Chat feature and ed05 source-clock repair. Preserve provider step
order and incoming split-reasoning order; remove a duplicated import
introduced by the automatic merge and test the combined ordering contract.

Retains credits for @sojiro-o/#25117 and #24141 and @haoliangli/#15773;
original author objects and measured coauthor trailers remain unchanged.
@sojiro-o

Copy link
Copy Markdown
Contributor Author

Closing. This PR was stacked on #24627, which has been idle since October 4. Meanwhile, Antigravity Chat landed on main through its ACP server (#28595), so the transcript lookup and approval wiring this PR fixed for WSL is no longer how Chat talks to Antigravity. Also, on v1.4.230 a WSL workspace starts agents as a terminal instead of Chat ("this workspace runs under WSL"), so there is no WSL Chat path left for this PR to fix.

@sojiro-o sojiro-o closed this Oct 19, 2026
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