<!-- task=01_antigravity_cli_execution plan=0 tag=ANTIGRAVITY -->

# Antigravity CLI Execution 전환

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

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

## 배경

Google 공지(2026-05-19)는 Gemini CLI consumer/free 흐름이 2026-06-18부터 Antigravity CLI로 전환된다고 안내한다. 공식 Antigravity CLI 문서는 `agy --print`, `--dangerously-skip-permissions`, `agy plugin import gemini`, `AGENTS.md`/`GEMINI.md` 호환, `~/.gemini/antigravity-cli/settings.json` 경로를 기준으로 설명한다. 이 작업은 코드의 CLI execution 계층에서 Gemini one-shot/JSONL 전제를 Antigravity `agy` one-shot 실행 전제로 바꾸는 첫 단계다.

## 분석 결과

### 읽은 파일

- `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/roadmap/current.md`
- `agent-ops/roadmap/milestones/M01-edge-node-execution-skeleton.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `apps/node/internal/adapters/cli/cli.go`
- `apps/node/internal/adapters/cli/oneshot.go`
- `apps/node/internal/adapters/cli/emitters.go`
- `apps/node/internal/adapters/cli/cli_internal_test.go`
- `apps/node/internal/adapters/cli/oneshot_blackbox_test.go`
- `apps/node/internal/adapters/factory.go`
- `apps/node/internal/adapters/factory_internal_test.go`
- `configs/edge.yaml`
- `scripts/e2e-smoke.sh`
- `README.md`
- `apps/node/README.md`
- `apps/edge/README.md`

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

- Antigravity one-shot args: 기존 테스트는 `TestCLIExecuteOneShotPassesPromptAsArg`로 prompt append만 검증한다. `agy --dangerously-skip-permissions --print <prompt>` 모양은 미검증이다. 새 blackbox 테스트가 필요하다.
- Gemini stream-json helper 이름 제거: 기존 `streamJSONEmitter` 테스트가 동작은 검증하지만 `geminiTool*` 심볼 제거는 검색 검증 외에는 보지 않는다. 테스트명/동작은 유지하고 심볼 검색을 최종 검증에 둔다.
- Proto/struct 변환 profile 예시: `TestCLIConfFromProto_GeminiHeadlessYoloProfile`가 Gemini yolo args를 고정한다. Antigravity profile args로 교체해야 한다.

### 심볼 참조

- `geminiToolUseDelta`: `apps/node/internal/adapters/cli/emitters.go:119,167`
- `geminiToolParamSummary`: `apps/node/internal/adapters/cli/emitters.go:171,178`
- `geminiToolResultDelta`: `apps/node/internal/adapters/cli/emitters.go:132,190`
- `geminiErrorString`: `apps/node/internal/adapters/cli/emitters.go:147,161,205`
- `truncateGeminiToolText`: `apps/node/internal/adapters/cli/emitters.go:184,202,225`
- `TestCLIConfFromProto_GeminiHeadlessYoloProfile`: `apps/node/internal/adapters/factory_internal_test.go:61`
- Gemini profile comment: `apps/node/internal/adapters/cli/cli.go:2`

### 분할 판단

분할 정책을 먼저 평가했다. 전체 Gemini -> Antigravity 전환은 execution args, PTY/status parser, config/docs/smoke, real verification의 위험과 검증 방식이 다르므로 다중 plan으로 나눈다.

- `01_antigravity_cli_execution`: 이 파일. node CLI one-shot execution과 generic stream-json naming만 담당한다. 독립 시작 가능.
- `02_antigravity_usage_status`: PTY/status checker와 parser 전환. 독립 시작 가능.
- `03+01,02_antigravity_config_docs_smoke`: 01, 02의 `complete.log` 이후 config/docs/smoke와 call-site rollout을 수행한다.
- `04+01,02,03_antigravity_full_verification`: 전체 구현 이후 실제 `agy`/bin/e2e 검증을 수행한다.

### 범위 결정 근거

- `configs/edge.yaml`의 실제 profile 교체, README/smoke 전체 문구 교체는 task 03에서 처리한다.
- `apps/node/internal/adapters/cli/status/**`와 `apps/edge/internal/opsconsole/status.go`는 task 02에서 처리한다.
- `agent-ops/skills/common/**`, `agent-ops/bin/entry-files.sh`, `GEMINI.md`, `.geminiignore`는 이 전환에서 제외한다. Antigravity 문서가 `GEMINI.md`와 기존 global Gemini context 호환을 명시하므로 common agent-ops entry-file 정책까지 제거하면 별도 정책 변경이 된다.
- 새 Go dependency는 추가하지 않는다.

### 빌드 등급

build=`cloud-G07`, review=`cloud-G07`. CLI execution/stdio parsing과 외부 CLI args 전환이 포함되어 terminal-agent 작업이고, 이후 task와 결합될 때 실제 bin smoke까지 이어진다.

## 구현 체크리스트

- [ ] [ANTIGRAVITY-1] CLI execution 레이어의 Gemini profile 전제를 Antigravity one-shot profile 전제로 바꾸고 관련 테스트를 갱신한다.
- [ ] [ANTIGRAVITY-2] generic `stream-json` emitter에 남은 Gemini 전용 helper 이름을 제거하고 동작 회귀 테스트를 유지한다.
- [ ] 중간 검증과 최종 검증 명령을 실행하고 결과를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [ANTIGRAVITY-1] CLI one-shot profile 전제 교체

### 문제

`apps/node/internal/adapters/cli/cli.go:2`는 CLI profile 예시에 `gemini`를 포함하고, `apps/node/internal/adapters/factory_internal_test.go:61`는 Gemini yolo profile을 고정한다. `executeOneShot`은 profile args 뒤에 prompt를 append하므로 Antigravity는 `agy --dangerously-skip-permissions --print <prompt>` 형태로 테스트해야 한다.

현재:

```go
// apps/node/internal/adapters/cli/cli.go:1
// Package cli provides an Adapter that runs external CLI tools as an execution
// adapter. Profiles (claude, gemini, codex, opencode, cline) are defined by
```

```go
// apps/node/internal/adapters/factory_internal_test.go:61
func TestCLIConfFromProto_GeminiHeadlessYoloProfile(t *testing.T) {
	m := &iop.CLIAdapterConfig{
		Profiles: map[string]*iop.CLIProfileConfig{
			"gemini": {
				Command: "gemini",
				Args:    []string{"-p", "--approval-mode", "yolo"},
			},
		},
	}
```

### 해결 방법

`gemini` 예시를 `antigravity`로 바꾸고, `agy` command와 `--dangerously-skip-permissions --print` args를 고정한다. `executeOneShot`의 prompt append 방식은 유지한다.

예상:

```go
// Package cli provides an Adapter that runs external CLI tools as an execution
// adapter. Profiles (claude, antigravity, codex, opencode, cline) are defined by
```

```go
func TestCLIConfFromProto_AntigravityHeadlessProfile(t *testing.T) {
	m := &iop.CLIAdapterConfig{
		Profiles: map[string]*iop.CLIProfileConfig{
			"antigravity": {
				Command: "agy",
				Args:    []string{"--dangerously-skip-permissions", "--print"},
			},
		},
	}
```

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

- [ ] `apps/node/internal/adapters/cli/cli.go` package comment의 profile 목록을 `antigravity` 기준으로 수정한다.
- [ ] `apps/node/internal/adapters/factory_internal_test.go`의 Gemini profile test를 Antigravity profile test로 교체한다.
- [ ] `apps/node/internal/adapters/cli/oneshot_blackbox_test.go`에 fake shell command가 `--dangerously-skip-permissions`, `--print`, `<prompt>` 순서를 받는지 검증하는 테스트를 추가한다.

### 테스트 작성

- 작성: `apps/node/internal/adapters/cli/oneshot_blackbox_test.go`, `TestCLIExecuteOneShotAntigravityPrintProfilePassesPrompt`
  - fake `sh` script가 `$1`, `$2`, `$3`을 검사하고 prompt를 출력한다.
  - assertion: delta에 prompt 기반 응답이 있고 command args가 Antigravity shape와 일치한다.
- 수정: `apps/node/internal/adapters/factory_internal_test.go`, 기존 Gemini profile test를 Antigravity profile test로 변경한다.

### 중간 검증

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

기대: 관련 패키지 fresh test 통과. Go test cache output은 허용하지 않는다.

### [ANTIGRAVITY-2] stream-json Gemini helper 이름 제거

### 문제

`stream-json` emitter는 generic JSONL parser로 남길 수 있지만 helper 심볼이 Gemini 이름을 갖고 있다.

현재:

```go
// apps/node/internal/adapters/cli/emitters.go:119
if delta := geminiToolUseDelta(ev.ToolName, ev.Parameters); delta != "" {
```

```go
// apps/node/internal/adapters/cli/emitters.go:167
func geminiToolUseDelta(toolName string, params map[string]any) string {
```

### 해결 방법

`streamJSON*` 또는 `genericTool*` 이름으로 helper를 rename한다. `jsonEmitters["stream-json"]` key와 `streamJSONEmitter`는 유지한다. 이 key는 기존 structured JSONL fallback으로 남기되 Antigravity profile에서는 사용하지 않는다.

예상:

```go
if delta := streamToolUseDelta(ev.ToolName, ev.Parameters); delta != "" {
```

```go
func streamToolUseDelta(toolName string, params map[string]any) string {
```

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

- [ ] `apps/node/internal/adapters/cli/emitters.go`의 `geminiToolUseDelta`, `geminiToolParamSummary`, `geminiToolResultDelta`, `geminiErrorString`, `truncateGeminiToolText`를 generic 이름으로 바꾼다.
- [ ] 같은 파일의 call site를 모두 새 이름으로 갱신한다.
- [ ] `apps/node/internal/adapters/cli/cli_internal_test.go`의 stream-json 테스트명/fixture가 Gemini 전용 의미를 암시하지 않는지 확인하고 필요한 경우 이름만 갱신한다.

### 테스트 작성

- 신규 테스트는 추가하지 않는다. 기존 `TestStreamJSONEmitter_*`, `TestCLIExecuteOneShotStreamJSONParsesAssistantContent`, `TestJsonEmitters_RegistryMatchesImpls`가 동작 회귀를 검증한다.
- 대신 최종 검증에 `geminiTool|GeminiHeadless|--approval-mode` 검색을 포함한다.

### 중간 검증

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

기대: stream-json, one-shot, emitter registry 테스트 통과.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `apps/node/internal/adapters/cli/cli.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/factory_internal_test.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/cli/oneshot_blackbox_test.go` | ANTIGRAVITY-1 |
| `apps/node/internal/adapters/cli/emitters.go` | ANTIGRAVITY-2 |
| `apps/node/internal/adapters/cli/cli_internal_test.go` | ANTIGRAVITY-2 |

## 최종 검증

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

```bash
rg --sort path -n "geminiTool|GeminiHeadless|--approval-mode" apps/node/internal/adapters
```

기대: 첫 명령은 fresh test 통과. 둘째 명령은 결과가 없어야 한다. `stream-json` 자체는 intentionally retained.

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