diff --git a/docs/reference/antigravity-readiness-evidence.md b/docs/reference/antigravity-readiness-evidence.md index 0010fa76ded..a93421392a0 100644 --- a/docs/reference/antigravity-readiness-evidence.md +++ b/docs/reference/antigravity-readiness-evidence.md @@ -1,5 +1,37 @@ # Antigravity readiness: what the transcripts show +## 2026-09-19: live 1.2.7 mode captures and visible-screen fallback + +New recordings under `src/main/runtime/__fixtures__/`: + +- `antigravity-ready-default-127.txt`: empty default-mode composer. +- `antigravity-ready-plan-127.txt`: empty composer displaying + `> Plan mode: research & plan only (shift+tab to cycle)`. +- `antigravity-ready-accept-edits-127.txt`: empty composer displaying + `> Accept-edits mode: file edits auto-approved (shift+tab to cycle)`. +- `antigravity-plan-hint-as-draft-127.txt`: the exact plan placeholder text typed + as a real, unsubmitted draft. + +The ready and typed plan rows have identical text and styling. Their footers differ: +the empty composer shows `? for shortcuts`; a typed draft removes it. The captured +working screen instead shows `esc to cancel`. A bare-caret requirement alone would +reject both empty mode composers. Matching the placeholder text alone would accept +the user's draft. The installed binary reports version `1.2.1`, but its banner is +`1.2.7`; these recordings identify the banner version. + +`terminal-screen-readiness.ts` now checks the complete visible composer frame and +shortcut footer, and rejects separately projected draft text. The adopted-terminal +visible-screen fallback uses it. Captured-screen tests and runtime fallback tests +cover ready, working, dialog, and draft cases, including mocked SSH snapshots. + +**This is not a complete readiness fix.** The regular retained-output matcher still +has the defects below. Narrow wrapping, a scrolled-away banner, and older layouts +without the shortcut footer require further evidence and integration. The older +`antigravity-composer-multiline-unsent.txt` recording was reused from PR #20027 with +its original metadata; it was not recaptured on 1.2.7. + +## Earlier investigation (1.2.0) + `findAntigravityReadyPromptIndex` in `src/main/runtime/terminal-wait-detection.ts` decides whether an Antigravity pane is ready for a prompt. It has been written five times, each version tuned against a five-line screen typed from memory into a `.spec.ts` fixture. Three of the first four diff --git a/src/main/runtime/__fixtures__/antigravity-composer-multiline-unsent.meta.json b/src/main/runtime/__fixtures__/antigravity-composer-multiline-unsent.meta.json new file mode 100644 index 00000000000..9f36c82689c --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-composer-multiline-unsent.meta.json @@ -0,0 +1,9 @@ +{ + "capturedAt": "2026-09-11T08:13:59.393Z", + "platform": "darwin", + "command": ["agy"], + "cols": 120, + "rows": 40, + "note": "agy TUI 1.2.1 with 'abc' typed into the composer, then shift+enter (ESC[13;2u), leaving an empty second composer row. The tail's last content line is a bare '>' whose line above is '> abc', not the composer rule. Ground truth: not ready \u2014 a prompt sent here is appended to the operator's unsubmitted text. This is the only capture that separates the rule clause from the caret clause.", + "exitCode": 0 +} diff --git a/src/main/runtime/__fixtures__/antigravity-composer-multiline-unsent.txt b/src/main/runtime/__fixtures__/antigravity-composer-multiline-unsent.txt new file mode 100644 index 00000000000..54c7ff4d025 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-composer-multiline-unsent.txt @@ -0,0 +1,25 @@ +[?2026$p[?2027$p[>4m[=0;1u[?1049h[?25l[?5W[?2004h[>4;2m[=1;1u[?u +โ–„โ–€โ–€โ–„ +โ–€โ–€โ–€โ–€โ–€โ–€ +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ + โ–„โ–€โ–€ โ–€โ–€โ–„ + โ–„โ–€โ–€ โ–€โ–€โ–„ + + Welcome to the Antigravity CLI. You are currently not signed in. + + โฃพ Signing in... โฃท [>4m[=0;1u[?1049l[>4;2m[=1;1u[?u[0 q  +โ–„โ–€โ–€โ–„ Antigravity CLI 1.2.1 +โ–€โ–€โ–€โ–€โ–€โ–€ Gemini API key +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ Gemini 3.7 Flash (Low) + โ–„โ–€โ–€ โ–€โ–€โ–„ /tmp/agycap/w1 + โ–„โ–€โ–€ โ–€โ–€โ–„ + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +> +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +? for shortcutsGemini 3.7 Flash ยท low [?25h[?25lab[?25h[?25lc[?25h[?25l + + G[?25h[?25l + > +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + Gemini 3.7 Flash ยท low [?25h \ No newline at end of file diff --git a/src/main/runtime/__fixtures__/antigravity-plan-hint-as-draft-127.meta.json b/src/main/runtime/__fixtures__/antigravity-plan-hint-as-draft-127.meta.json new file mode 100644 index 00000000000..ad47541763a --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-plan-hint-as-draft-127.meta.json @@ -0,0 +1,9 @@ +{ + "capturedAt": "2026-09-19T07:34:50.080Z", + "platform": "darwin", + "command": ["agy", "--mode", "plan"], + "cols": 120, + "rows": 40, + "note": "Plan mode; exact placeholder wording typed as an unsent draft at 12 seconds", + "exitCode": 0 +} diff --git a/src/main/runtime/__fixtures__/antigravity-plan-hint-as-draft-127.txt b/src/main/runtime/__fixtures__/antigravity-plan-hint-as-draft-127.txt new file mode 100644 index 00000000000..3a80b194cb3 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-plan-hint-as-draft-127.txt @@ -0,0 +1,13 @@ +_Ga=q,f=32,s=1,v=1,i=31;AAAAAA==\[?2026$p[?2027$p[?5W[?2004h[>4;2m[>1u[?u[0 q  +โ–„โ–€โ–€โ–„ Antigravity CLI 1.2.7 +โ–€โ–€โ–€โ–€โ–€โ–€ Gemini API key +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ Gemini 3.7 Flash (Low) + โ–„โ–€โ–€ โ–€โ–€โ–„ ~/orca/workspaces/orca/agy-gemini-issues + โ–„โ–€โ–€ โ–€โ–€โ–„ + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +> Plan mode: research & plan only (shift+tab to cycle) +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +? for shortcutsplan ยท Gemini 3.7 Flash ยท low [?25h[?25lPlan + + p[?25h[?25lmode: re[?25h[?25lsearch[?25h[?25l& plan[?25h[?25l only (s[?25h[?25lhift+ta[?25h[?25lb to cy[?25h[?25lcle)[?25h \ No newline at end of file diff --git a/src/main/runtime/__fixtures__/antigravity-ready-accept-edits-127.meta.json b/src/main/runtime/__fixtures__/antigravity-ready-accept-edits-127.meta.json new file mode 100644 index 00000000000..ca5f64aece3 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-ready-accept-edits-127.meta.json @@ -0,0 +1,9 @@ +{ + "capturedAt": "2026-09-19T07:31:16.912Z", + "platform": "darwin", + "command": ["agy", "--mode", "accept-edits"], + "cols": 120, + "rows": 40, + "note": "Live installed CLI banner 1.2.7; accept-edits mode startup; no prompt submitted", + "exitCode": 0 +} diff --git a/src/main/runtime/__fixtures__/antigravity-ready-accept-edits-127.txt b/src/main/runtime/__fixtures__/antigravity-ready-accept-edits-127.txt new file mode 100644 index 00000000000..29b023b170e --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-ready-accept-edits-127.txt @@ -0,0 +1,22 @@ +_Ga=q,f=32,s=1,v=1,i=31;AAAAAA==\[?2026$p[?2027$p[>4m[?1049h[?25l[?5W[?2004h[>4;2m[>1u[?u +โ–„โ–€โ–€โ–„ +โ–€โ–€โ–€โ–€โ–€โ–€ +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ + โ–„โ–€โ–€ โ–€โ–€โ–„ + โ–„โ–€โ–€ โ–€โ–€โ–„ + + Welcome to the Antigravity CLI. You are currently not signed in. + + No authentication methods available. + + Press ctrl+c or ctrl+d twice to exit.[>4m[<1u[?1049l[>4;2m[>1u[?u[0 q  +โ–„โ–€โ–€โ–„ Antigravity CLI 1.2.7 +โ–€โ–€โ–€โ–€โ–€โ–€ Gemini API key +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ Gemini 3.7 Flash (Low) + โ–„โ–€โ–€ โ–€โ–€โ–„ ~/orca/workspaces/orca/agy-gemini-issues + โ–„โ–€โ–€ โ–€โ–€โ–„ + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +> Accept-edits mode: file edits auto-approved (shift+tab to cycle) +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +? for shortcutsaccept-edits ยท Gemini 3.7 Flash ยท low [?25h \ No newline at end of file diff --git a/src/main/runtime/__fixtures__/antigravity-ready-default-127.meta.json b/src/main/runtime/__fixtures__/antigravity-ready-default-127.meta.json new file mode 100644 index 00000000000..f1f686b0138 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-ready-default-127.meta.json @@ -0,0 +1,9 @@ +{ + "capturedAt": "2026-09-19T07:34:15.459Z", + "platform": "darwin", + "command": ["agy"], + "cols": 120, + "rows": 40, + "note": "Live installed CLI banner 1.2.7; default mode startup; no prompt submitted", + "exitCode": 0 +} diff --git a/src/main/runtime/__fixtures__/antigravity-ready-default-127.txt b/src/main/runtime/__fixtures__/antigravity-ready-default-127.txt new file mode 100644 index 00000000000..cdf2fcb9f74 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-ready-default-127.txt @@ -0,0 +1,11 @@ +_Ga=q,f=32,s=1,v=1,i=31;AAAAAA==\[?2026$p[?2027$p[?5W[?2004h[>4;2m[>1u[?u[0 q  +โ–„โ–€โ–€โ–„ Antigravity CLI 1.2.7 +โ–€โ–€โ–€โ–€โ–€โ–€ Gemini API key +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ Gemini 3.7 Flash (Low) + โ–„โ–€โ–€ โ–€โ–€โ–„ ~/orca/workspaces/orca/agy-gemini-issues + โ–„โ–€โ–€ โ–€โ–€โ–„ + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +> +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +? for shortcutsGemini 3.7 Flash ยท low [?25h \ No newline at end of file diff --git a/src/main/runtime/__fixtures__/antigravity-ready-plan-127.meta.json b/src/main/runtime/__fixtures__/antigravity-ready-plan-127.meta.json new file mode 100644 index 00000000000..b107eebc5b7 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-ready-plan-127.meta.json @@ -0,0 +1,9 @@ +{ + "capturedAt": "2026-09-19T07:31:17.722Z", + "platform": "darwin", + "command": ["agy", "--mode", "plan"], + "cols": 120, + "rows": 40, + "note": "Live installed CLI banner 1.2.7; plan mode startup; no prompt submitted", + "exitCode": 0 +} diff --git a/src/main/runtime/__fixtures__/antigravity-ready-plan-127.txt b/src/main/runtime/__fixtures__/antigravity-ready-plan-127.txt new file mode 100644 index 00000000000..9eef9b57682 --- /dev/null +++ b/src/main/runtime/__fixtures__/antigravity-ready-plan-127.txt @@ -0,0 +1,11 @@ +_Ga=q,f=32,s=1,v=1,i=31;AAAAAA==\[?2026$p[?2027$p[?5W[?2004h[>4;2m[>1u[?u[0 q  +โ–„โ–€โ–€โ–„ Antigravity CLI 1.2.7 +โ–€โ–€โ–€โ–€โ–€โ–€ Gemini API key +โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€ Gemini 3.7 Flash (Low) + โ–„โ–€โ–€ โ–€โ–€โ–„ ~/orca/workspaces/orca/agy-gemini-issues + โ–„โ–€โ–€ โ–€โ–€โ–„ + +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +> Plan mode: research & plan only (shift+tab to cycle) +โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +? for shortcutsplan ยท Gemini 3.7 Flash ยท low [?25h \ No newline at end of file diff --git a/src/main/runtime/antigravity-visible-composer.test.ts b/src/main/runtime/antigravity-visible-composer.test.ts new file mode 100644 index 00000000000..a18cf637e92 --- /dev/null +++ b/src/main/runtime/antigravity-visible-composer.test.ts @@ -0,0 +1,53 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { Terminal } from '@xterm/headless' +import { describe, expect, it } from 'vitest' +import { isKnownReadyTerminalScreen } from './terminal-screen-readiness' + +async function capturedScreen(name: string): Promise { + const terminal = new Terminal({ cols: 120, rows: 40, allowProposedApi: true }) + try { + const transcript = readFileSync(join(__dirname, '__fixtures__', `${name}.txt`), 'utf8') + await new Promise((resolve) => terminal.write(transcript, resolve)) + const buffer = terminal.buffer.active + return Array.from( + { length: terminal.rows }, + (_, row) => buffer.getLine(buffer.baseY + row)?.translateToString(true) ?? '' + ) + } finally { + terminal.dispose() + } +} + +describe('Antigravity visible-screen readiness from real PTY captures', () => { + it.each([ + ['antigravity-ready-default-127', true], + ['antigravity-ready-plan-127', true], + ['antigravity-ready-accept-edits-127', true], + ['antigravity-plan-hint-as-draft-127', false], + ['antigravity-composer-multiline-unsent', false], + ['antigravity-dialog-model-picker', false], + ['antigravity-dialog-command-palette', false], + ['antigravity-dialog-trust-workspace', false], + ['antigravity-busy-mid-turn', false], + ['antigravity-busy-turn-ended', true] + ] as const)('%s is ready: %s', async (name, ready) => { + expect(isKnownReadyTerminalScreen({ tail: await capturedScreen(name) })).toBe(ready) + }) + + it('refuses a draft extracted separately by the terminal projection', async () => { + const tail = await capturedScreen('antigravity-ready-default-127') + expect(isKnownReadyTerminalScreen({ tail })).toBe(true) + expect(isKnownReadyTerminalScreen({ tail, draft: 'unfinished user message' })).toBe(false) + }) + + it('distinguishes the real mode placeholder from the same words typed by the user', async () => { + const ready = await capturedScreen('antigravity-ready-plan-127') + const draft = await capturedScreen('antigravity-plan-hint-as-draft-127') + const prompt = '> Plan mode: research & plan only (shift+tab to cycle)' + expect(ready.map((row) => row.trim())).toContain(prompt) + expect(draft.map((row) => row.trim())).toContain(prompt) + expect(isKnownReadyTerminalScreen({ tail: ready })).toBe(true) + expect(isKnownReadyTerminalScreen({ tail: draft })).toBe(false) + }) +}) diff --git a/src/main/runtime/antigravity-visible-wait.test.ts b/src/main/runtime/antigravity-visible-wait.test.ts new file mode 100644 index 00000000000..dfe6f7c8a26 --- /dev/null +++ b/src/main/runtime/antigravity-visible-wait.test.ts @@ -0,0 +1,61 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, it, vi } from 'vitest' +import { HeadlessEmulator } from '../daemon/headless-emulator' +import { createTranscriptPane } from './agent-transcript-pane-test-harness' +import { projectTerminalVisibleLines } from './orca-runtime-terminal-projection' + +vi.mock('electron', () => ({ + BrowserWindow: { fromId: vi.fn(() => null) }, + webContents: { fromId: vi.fn(() => null) }, + ipcMain: { on: vi.fn(), removeListener: vi.fn() }, + app: { getPath: vi.fn(() => '/tmp') } +})) + +describe('Antigravity adopted-terminal visible readiness probe', () => { + for (const connectionId of [undefined, 'ssh-host']) { + it.each([ + ['antigravity-ready-default-127', true], + ['antigravity-ready-plan-127', true], + ['antigravity-composer-multiline-unsent', false], + ['antigravity-dialog-model-picker', false], + ['antigravity-busy-mid-turn', false] + ] as const)(`${connectionId ?? 'local'}: %s ready=%s`, async (name, ready) => { + const emulator = new HeadlessEmulator({ cols: 120, rows: 40, scrollback: 0 }) + try { + await emulator.write(readFileSync(join(__dirname, '__fixtures__', `${name}.txt`), 'utf8')) + const screen = projectTerminalVisibleLines(emulator) + const { runtime, handle } = await createTranscriptPane({ + paneTitle: 'agy', + foregroundProcess: 'agy', + data: '', + connectionId + }) + const read = vi.spyOn(runtime, 'readTerminal').mockResolvedValue({ + handle, + status: 'running', + tail: screen.lines, + draft: screen.draft, + source: 'screen', + truncated: false, + limited: false, + oldestCursor: '0', + nextCursor: '0', + latestCursor: '0', + returnedLineCount: screen.lines.length + }) + const waiting = runtime.waitForTerminal(handle, { condition: 'tui-idle', timeoutMs: 600 }) + await (ready + ? expect(waiting).resolves.toMatchObject({ satisfied: true }) + : expect(waiting).rejects.toThrow('timeout')) + expect(read).toHaveBeenCalledWith( + handle, + {}, + expect.objectContaining({ visibleScreenOnly: true }) + ) + } finally { + emulator.dispose() + } + }) + } +}) diff --git a/src/main/runtime/orca-runtime-start-tui-idle-visible-read-probe.ts b/src/main/runtime/orca-runtime-start-tui-idle-visible-read-probe.ts index aa630277078..c53584f1b7e 100644 --- a/src/main/runtime/orca-runtime-start-tui-idle-visible-read-probe.ts +++ b/src/main/runtime/orca-runtime-start-tui-idle-visible-read-probe.ts @@ -9,10 +9,8 @@ import { VISIBLE_TERMINAL_SNAPSHOT_TIMEOUT_MS } from './orca-runtime-postlude' import { withTimeout } from './runtime-async-boundaries' -import { - detectTerminalWaitBlockedReason, - isKnownReadyPromptPreview -} from './terminal-wait-detection' +import { detectTerminalWaitBlockedReason } from './terminal-wait-detection' +import { isKnownReadyTerminalScreen } from './terminal-screen-readiness' import type { RuntimeTerminalWait, RuntimeTerminalWaitBlockedReason @@ -68,7 +66,7 @@ export class OrcaRuntimeWithStartTuiIdleVisibleReadProbe extends OrcaRuntimeWith } const snapshotText = projection.tail.join('\n') const blockedReason = detectTerminalWaitBlockedReason(snapshotText) - if (!blockedReason && !isKnownReadyPromptPreview(snapshotText)) { + if (!blockedReason && !isKnownReadyTerminalScreen(projection)) { return } const result = this.buildTuiIdleProbeResult(waiter.handle, blockedReason) diff --git a/src/main/runtime/terminal-screen-readiness.ts b/src/main/runtime/terminal-screen-readiness.ts new file mode 100644 index 00000000000..2a21b2aa2f5 --- /dev/null +++ b/src/main/runtime/terminal-screen-readiness.ts @@ -0,0 +1,27 @@ +import { isKnownReadyPromptPreview } from './terminal-wait-detection' + +const ANTIGRAVITY_FRAME = /^โ”€{8,}$/ +const ANTIGRAVITY_EMPTY_COMPOSERS = new Set([ + '>', + '> Plan mode: research & plan only (shift+tab to cycle)', + '> Accept-edits mode: file edits auto-approved (shift+tab to cycle)' +]) + +export function isKnownReadyTerminalScreen(screen: { tail: string[]; draft?: string }): boolean { + if (screen.draft?.trim()) { + return false + } + const text = screen.tail.join('\n') + if (!text.toLowerCase().includes('antigravity cli')) { + return isKnownReadyPromptPreview(text) + } + const rows = screen.tail.map((row) => row.trim()).filter(Boolean) + const footer = rows.at(-1) ?? '' + // The shortcut footer disappears for typed drafts and changes to cancel while working. + return ( + footer.startsWith('? for shortcuts') && + ANTIGRAVITY_FRAME.test(rows.at(-2) ?? '') && + ANTIGRAVITY_EMPTY_COMPOSERS.has(rows.at(-3) ?? '') && + ANTIGRAVITY_FRAME.test(rows.at(-4) ?? '') + ) +}