<!-- task=02_antigravity_usage_status plan=0 tag=ANTIGRAVITY -->

# Antigravity Usage Status 전환

## 이 파일을 읽는 구현 에이전트에게

> **구현의 마지막 단계는 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용으로 채우는 것입니다.**
> 이 파일의 구현 체크리스트와 리뷰 스텁의 구현 체크리스트를 모두 완료하고, 중간/최종 검증을 실행한 뒤, 실제 구현 내용과 명령 출력(stdout/stderr)을 리뷰 파일에 기록하세요.
> 리뷰 파일의 `이 파일을 읽는 리뷰 에이전트에게` 섹션에 있는 아카이브 지시는 실행하지 말고, `코드리뷰 전용 체크리스트`도 수정하거나 체크하지 마세요.

## 배경

현재 `/status` 경로는 `gemini` target 또는 `gemini` command base를 만나면 `GeminiChecker`를 생성하고 Gemini TUI에 `/stats model`과 `/model`을 보낸다. Antigravity CLI의 공개 docs와 local `agy --help`는 command 이름과 권한 flag가 다르며, `agy` TUI/PTY를 대상으로 다시 정의해야 한다. 이 작업은 status checker, parser, edge formatter의 Gemini 명명과 target selection을 Antigravity로 전환한다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/project/domain/node/rules.md`
- `agent-ops/rules/project/domain/edge/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `apps/node/internal/adapters/cli/status/status.go`
- `apps/node/internal/adapters/cli/status/gemini.go`
- `apps/node/internal/adapters/cli/status/parser.go`
- `apps/node/internal/adapters/cli/status/status_test.go`
- `apps/node/internal/adapters/cli/status/gemini_test.go`
- `apps/node/internal/adapters/cli/status/parser_test.go`
- `apps/edge/internal/opsconsole/status.go`
- `apps/edge/internal/opsconsole/events_test.go`
- `scripts/e2e-smoke.sh`
- `configs/edge.yaml`

### 테스트 커버리지 공백

- Checker selection: `TestNewChecker_GeminiUsesProfileCommand`와 `TestNewChecker_GeminiEmptyCommandDefaultsToGemini`가 Gemini만 검증한다. Antigravity target=`antigravity`, command base=`agy`, empty default=`agy` 테스트로 바꿔야 한다.
- PTY command sequence: `gemini_test.go`는 `/stats model`과 `/model`을 fake Gemini script로 검증한다. Antigravity command sequence는 fake `agy` script로 새로 검증해야 한다.
- Parser: `parser_test.go`의 Gemini quota/model usage fixture는 parser 동작을 검증하지만 Antigravity 실제 출력은 아직 저장소에 없다. Antigravity output fixture를 새로 정의하고, 실제 CLI output이 다르면 task 04에서 보정한다.
- Edge formatter: `formatGeminiModelUsage`는 metadata key가 generic인데 함수명과 테스트명이 Gemini로 남아 있다. rename 후 기존 model usage 출력 회귀를 유지해야 한다.

### 심볼 참조

- `NewGeminiChecker`: `apps/node/internal/adapters/cli/status/status.go:61`, `apps/node/internal/adapters/cli/status/gemini.go:20`, `apps/node/internal/adapters/cli/status/gemini_test.go:56,139,200,263`
- `GeminiChecker`: `apps/node/internal/adapters/cli/status/gemini.go:16,20,27`, `apps/node/internal/adapters/cli/status/status_test.go:93,111`
- `parseGeminiQuota`: `apps/node/internal/adapters/cli/status/parser.go:60,78`
- `parseGeminiModelUsage`: `apps/node/internal/adapters/cli/status/parser.go:61,62,115`
- `gemini*Regex`: `apps/node/internal/adapters/cli/status/parser.go:26-30,81,84,87,92,142`
- `geminiModelNameFromUsagePrefix`: `apps/node/internal/adapters/cli/status/parser.go:147,189`
- `formatGeminiModelUsage`: `apps/edge/internal/opsconsole/status.go:130,195`
- Gemini parser/checker tests: `apps/node/internal/adapters/cli/status/gemini_test.go`, `apps/node/internal/adapters/cli/status/parser_test.go:326-463`, `apps/edge/internal/opsconsole/events_test.go:309-352`

### 분할 판단

분할 정책을 먼저 평가했다. 이 task는 PTY/status/parser/formatter만 담당하며 execution args task와 config/docs rollout task에서 분리한다. Sibling 관계:

- `01_antigravity_cli_execution`: 독립, one-shot execution 전제.
- `02_antigravity_usage_status`: 이 파일, 독립.
- `03+01,02_antigravity_config_docs_smoke`: 01/02 완료 후 rollout.
- `04+01,02,03_antigravity_full_verification`: 전체 완료 후 실제 검증.

### 범위 결정 근거

- `configs/edge.yaml` profile key 변경은 task 03에서 한다. 이 task의 tests는 target string을 Antigravity로 바꿀 수 있지만 config rollout은 하지 않는다.
- 실제 `agy` 계정 로그인/원격 요청 성공 여부는 task 04에서 검증한다. 이 task는 fake PTY와 parser fixture로 deterministic coverage를 만든다.
- Antigravity docs가 quota command의 exact output schema를 명시하지 않으므로 parser는 기존 metadata contract(`daily_label`, `used_percent`, `usage_limit`, `model_usage_*`)를 유지하고, raw fallback을 깨지 않게 한다.
- 새 dependency는 추가하지 않는다. 기존 `github.com/creack/pty`를 계속 사용한다.

### 빌드 등급

build=`cloud-G08`, review=`cloud-G08`. PTY/TUI command automation, parser fallback, edge 출력까지 걸쳐 있으며 실제 Antigravity output schema 불확실성이 있다.

## 구현 체크리스트

- [ ] [ANTIGRAVITY-1] Gemini checker를 Antigravity checker로 교체하고 checker selection을 `antigravity`/`agy` 기준으로 바꾼다.
- [ ] [ANTIGRAVITY-2] status parser의 Gemini 명명과 fixture를 Antigravity 명명/fixture로 바꾸고 metadata contract를 유지한다.
- [ ] [ANTIGRAVITY-3] edge usage formatter의 Gemini 명명을 generic model usage formatter로 바꾸고 테스트명을 갱신한다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 결과를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [ANTIGRAVITY-1] Checker 교체

### 문제

`apps/node/internal/adapters/cli/status/status.go:60`은 target/command base가 `gemini`일 때만 Google 계열 checker를 선택한다.

현재:

```go
// apps/node/internal/adapters/cli/status/status.go:56
case target == "codex" || cmdBase == "codex":
	return NewCodexChecker(profile.Command), nil
case target == "claude" || target == "claude-tui" || cmdBase == "claude":
	return NewClaudeChecker(profile.Command), nil
case target == "gemini" || cmdBase == "gemini":
	return NewGeminiChecker(profile.Command), nil
```

`apps/node/internal/adapters/cli/status/gemini.go:27`는 `gemini --skip-trust --screen-reader`를 실행하고 `/stats model`을 보낸다.

### 해결 방법

`gemini.go`를 `antigravity.go`로 대체하거나 rename한다. `NewChecker`는 `target == "antigravity"` 또는 `cmdBase == "agy"` 또는 `cmdBase == "antigravity"`를 `NewAntigravityChecker`로 라우팅한다. 기본 command는 `agy`다. PTY 시작은 `agy --dangerously-skip-permissions`를 기본으로 하고, status probing command는 Antigravity docs/local help 기준으로 `/usage`와 `/model`을 사용한다. 실제 output이 quota를 포함하지 않아도 `ParseStatusOutput` raw fallback이 동작해야 한다.

예상:

```go
case target == "antigravity" || cmdBase == "agy" || cmdBase == "antigravity":
	return NewAntigravityChecker(profile.Command), nil
```

```go
func NewAntigravityChecker(command string) *AntigravityChecker {
	if command == "" {
		command = "agy"
	}
	return &AntigravityChecker{command: command}
}
```

### 수정 파일 및 체크리스트

- [ ] `apps/node/internal/adapters/cli/status/gemini.go`를 `antigravity.go`로 교체한다.
- [ ] `apps/node/internal/adapters/cli/status/status.go`의 selection을 `antigravity`/`agy`로 바꾼다.
- [ ] `apps/node/internal/adapters/cli/status/status_test.go`의 Gemini checker tests를 Antigravity checker tests로 바꾼다.
- [ ] `apps/node/internal/adapters/cli/status/gemini_test.go`를 `antigravity_test.go`로 바꾸고 fake `agy` command sequence를 검증한다.
- [ ] 에러 메시지에서 `gemini` 문자열을 `antigravity`로 바꾼다.

### 테스트 작성

- 작성/수정: `TestAntigravityCheckerRequestsUsageAndModel`
- 작성/수정: `TestAntigravityCheckerWaitsForInputReady`
- 작성/수정: `TestAntigravityCheckerNoUsageReturnsRawUnparsed`
- 작성/수정: `TestNewChecker_AntigravityUsesProfileCommand`, `TestNewChecker_AgyCommandBaseUsesAntigravityChecker`, `TestNewChecker_AntigravityEmptyCommandDefaultsToAgy`

### 중간 검증

```bash
go test -count=1 ./apps/node/internal/adapters/cli/status
```

기대: status package fresh test 통과.

### [ANTIGRAVITY-2] Parser 명명과 fixture 전환

### 문제

`ParseStatusOutput`는 Claude 실패 후 Gemini parser를 시도한다. 함수명과 regex명이 모두 Gemini에 묶여 있어 Antigravity로 전환한 후에도 런타임 코드에 Gemini 이름이 남는다.

현재:

```go
// apps/node/internal/adapters/cli/status/parser.go:59
// Neither input produced Claude data — try Gemini, then Codex.
parsedGemini := rawStatus.parseGeminiQuota(cleanRaw)
if !rawStatus.parseGeminiModelUsage(cleanRaw) {
	rawStatus.parseGeminiModelUsage(visible)
}
```

### 해결 방법

함수명과 regex명을 `parseAntigravityQuota`, `parseAntigravityModelUsage`, `antigravity*Regex`로 바꾼다. Metadata key는 edge formatter와 proto contract가 이미 generic이므로 그대로 둔다. Fixture text는 `Antigravity` banner/model wording으로 바꿔 Gemini CLI 문구를 제거한다. 단, 모델 이름이 실제 provider model id로 `gemini-*`를 포함하는 경우는 fixture에서 쓰지 않는다.

예상:

```go
// Neither input produced Claude data — try Antigravity, then Codex.
parsedAntigravity := rawStatus.parseAntigravityQuota(cleanRaw)
if !rawStatus.parseAntigravityModelUsage(cleanRaw) {
	rawStatus.parseAntigravityModelUsage(visible)
}
```

### 수정 파일 및 체크리스트

- [ ] `apps/node/internal/adapters/cli/status/parser.go`의 Gemini parser 함수/regex/comment를 Antigravity로 rename한다.
- [ ] `apps/node/internal/adapters/cli/status/parser_test.go`의 Gemini test names와 fixtures를 Antigravity로 바꾼다.
- [ ] `ParseStatusOutput` fallback 순서가 Claude -> Antigravity -> Codex임을 주석과 테스트명에 반영한다.
- [ ] parser behavior는 기존 remaining percent, reset, usage limit, model usage metadata semantics를 유지한다.

### 테스트 작성

- 수정: `TestParseStatusOutput_AntigravityUsageQuota`
- 수정: `TestParseStatusOutput_AntigravityLimitReached`
- 수정: `TestParseStatusOutput_AntigravityScreenReaderQuotaWithoutReset`
- 수정: `TestParseStatusOutput_AntigravityModelUsage`
- 수정: `TestParseStatusOutput_AntigravityNoUsageLeavesRawOnly`

### 중간 검증

```bash
go test -count=1 ./apps/node/internal/adapters/cli/status
```

기대: parser tests 포함 status package 통과.

### [ANTIGRAVITY-3] Edge formatter generic rename

### 문제

`apps/edge/internal/opsconsole/status.go:130`은 generic metadata를 출력하면서 `formatGeminiModelUsage` 함수명을 사용한다.

현재:

```go
// apps/edge/internal/opsconsole/status.go:130
if formatGeminiModelUsage(out, metadata) {
	hasParsedLimits = true
}
```

### 해결 방법

함수명을 `formatModelUsage`로 바꾸고 테스트명을 Antigravity/generic 기준으로 바꾼다. 출력 문자열 `Model usage:`와 metadata key는 유지한다.

예상:

```go
if formatModelUsage(out, metadata) {
	hasParsedLimits = true
}
```

### 수정 파일 및 체크리스트

- [ ] `apps/edge/internal/opsconsole/status.go`의 `formatGeminiModelUsage`를 `formatModelUsage`로 rename한다.
- [ ] `apps/edge/internal/opsconsole/events_test.go`의 Gemini quota/model usage 테스트명을 Antigravity 또는 generic 이름으로 바꾼다.
- [ ] 테스트 fixture target을 `antigravity`로 바꾼다.

### 테스트 작성

- 수정: `TestFormatUsageStatus_PrintsAntigravityQuotaMetadata`
- 수정: `TestFormatUsageStatus_PrintsModelUsage`

### 중간 검증

```bash
go test -count=1 ./apps/edge/internal/opsconsole
```

기대: formatter tests 통과.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `apps/node/internal/adapters/cli/status/status.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/cli/status/gemini.go` -> `apps/node/internal/adapters/cli/status/antigravity.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/cli/status/status_test.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/cli/status/gemini_test.go` -> `apps/node/internal/adapters/cli/status/antigravity_test.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/cli/status/parser.go` | ANTIGRAVITY-2 |
| `apps/node/internal/adapters/cli/status/parser_test.go` | ANTIGRAVITY-2 |
| `apps/edge/internal/opsconsole/status.go` | ANTIGRAVITY-3 |
| `apps/edge/internal/opsconsole/events_test.go` | ANTIGRAVITY-3 |

## 최종 검증

```bash
go test -count=1 ./apps/node/internal/adapters/cli/status ./apps/edge/internal/opsconsole
```

```bash
rg --sort path -n "GeminiChecker|NewGeminiChecker|parseGemini|gemini[A-Z]|formatGemini|failed waiting for gemini|gemini startup" apps/node/internal/adapters/cli/status apps/edge/internal/opsconsole
```

기대: 첫 명령은 fresh test 통과. 둘째 명령은 결과가 없어야 한다. Go test cache output은 허용하지 않는다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
