feat: make Antigravity a first-class CLI across docs, installer and UI

Antigravity (agy) was wired into the session layer but never propagated to
the surfaces around it, while Gemini CLI stayed documented as a consumer
product despite being enterprise-only since Google's cutover. Gemini keeps
full support; Antigravity now sits beside it everywhere.

Functional fixes:
- docker/agent.Dockerfile never installed agy, so a docker case with
  mode 'antigravity' died on command-not-found. agy is not on npm, so it
  gets its own installer step. --dir /usr/local/bin is load-bearing: the
  default $HOME/.local/bin resolves to root's home at build time and is
  unreachable by the `agent` user the container runs as. Verified inside
  codeman/agent:base (v1.1.10, reachable as `agent`). Note the binary is
  ~190MB, the largest layer in the image.
- Welcome screen gained a Run Antigravity action, gated on agy being
  present like the other CLI buttons, with a cyan identity matching the
  toolbar run button and run-mode dot.
- install.sh now detects agy (search paths mirroring the resolver), counts
  it as a satisfying AI CLI, and recommends it over Gemini in the install
  hints. Detection only, no new auto-install path.

Docs corrected where they were factually wrong:
- architecture-invariants documented isExternalCliMode() as
  opencode/codex/gemini when the code has included antigravity for a
  while, said "all three modes", and omitted ANTIGRAVITY_ from the env
  prefix allowlist row.
- cron-guide's agentType enum, cron-discovery's SessionMode, and
  remote-sessions' RemoteCommandMode were all stale.

Also: README + README.zh-CN (five CLIs, Gemini marked enterprise-only),
package.json keyword, and comment drift in 8 places.

test/run-mode-ui.test.ts now covers the new welcome button; verified it
fails without the settings-ui wiring.

Antigravity nests its whole state under ~/.gemini/antigravity-cli/, not
~/.antigravity, so the existing .gemini docker credential seed already
covers it. Recorded as a comment so nobody adds dead config later.

isAltScreenStripMode() deliberately still excludes antigravity: whether
its TUI needs the alt-screen strip is a behavioural question that needs a
real agy session, not a guess.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-08-06 07:22:29 +02:00
parent bfff20a093
commit 0d0b772619
26 changed files with 149 additions and 59 deletions
+14 -1
View File
@@ -351,7 +351,13 @@ describe('Codex quick start settings', () => {
function loadUi(flags: Record<string, boolean> | undefined) {
const CodemanApp = function CodemanApp(this: any) {};
const welcomeBtns: Record<string, { style: { display: string } }> = {};
for (const id of ['welcomeClaudeBtn', 'welcomeOpencodeBtn', 'welcomeGeminiBtn', 'welcomeTunnelBtn']) {
for (const id of [
'welcomeClaudeBtn',
'welcomeOpencodeBtn',
'welcomeAntigravityBtn',
'welcomeGeminiBtn',
'welcomeTunnelBtn',
]) {
welcomeBtns[id] = { style: { display: 'PRISTINE' } };
}
const modeBtns: Record<string, { style: { display: string } }> = {};
@@ -394,6 +400,7 @@ describe('Codex quick start settings', () => {
app.applyWelcomeCliVisibility();
expect(welcomeBtns.welcomeClaudeBtn.style.display).toBe('flex');
expect(welcomeBtns.welcomeOpencodeBtn.style.display).toBe('none');
expect(welcomeBtns.welcomeAntigravityBtn.style.display).toBe('none');
expect(welcomeBtns.welcomeGeminiBtn.style.display).toBe('none');
// #200 originally DELETED the tunnel button and its QR outright; it is gated
// on cloudflared instead, so a box that has cloudflared keeps the feature.
@@ -402,6 +409,12 @@ describe('Codex quick start settings', () => {
const withTunnel = loadUi({ ...ALL_OFF, cloudflared: true });
withTunnel.app.applyWelcomeCliVisibility();
expect(withTunnel.welcomeBtns.welcomeTunnelBtn.style.display).toBe('flex');
// Antigravity is a first-class welcome action, gated on `agy` like the rest.
const withAgy = loadUi({ ...ALL_OFF, antigravity: true });
withAgy.app.applyWelcomeCliVisibility();
expect(withAgy.welcomeBtns.welcomeAntigravityBtn.style.display).toBe('flex');
expect(withAgy.welcomeBtns.welcomeClaudeBtn.style.display).toBe('none');
});
it('gates every run mode in the dropdown, antigravity included, and never shell', () => {