<!-- task=m-codex-app-server-streaming-migration/01_appserver_rpc_client plan=0 tag=API -->
# Codex App Server RPC Client Plan

## 이 파일을 읽는 구현 에이전트에게
이 PLAN을 끝까지 읽은 뒤 구현한다. 범위 밖 리팩터링, archive 읽기, 사용자 변경 되돌리기는 금지한다. 코드 변경 전 관련 domain rule과 local test rule을 확인하고, 구현 완료 전 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운다.

## 배경
현재 CLI adapter는 `codex exec --json`을 `modeCodexExec`로 실행한다. 이번 작업은 기본 프로필 전환의 선행 작업으로, `codex app-server --stdio`를 별도 mode로 라우팅하고 프로세스 생명주기 및 newline JSON RPC 초기화까지 안전하게 붙이는 단계다. 실제 turn 이벤트 매핑과 세션 노출은 후속 `02+01_session_events`가 맡는다.

임시 프로토콜 확인 결과, Codex CLI `0.139.0`의 app-server는 `--stdio`를 지원하고 `Content-Length` 프레이밍이 아니라 newline-delimited JSON을 받는다. 요청은 `jsonrpc` 필드 없이 `{id, method, params}` 형태이며, `initialize`, `initialized`, `thread/start`까지 확인됐다.

## 사용자 리뷰 요청 흐름
구현 중 사용자 소유 인증, 외부 계정 상태, 또는 범위 변경 없이는 안전하게 진행할 수 없을 때만 `CODE_REVIEW-cloud-G07.md`의 사용자 리뷰 요청 섹션을 실제 내용으로 교체하고 중단한다. 단순 검증 로그 부족은 구현 에이전트가 재실행으로 해소한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/codex-app-server-streaming-migration.md`
- Task ids:
  - `mode-router`: CLI adapter에 `codex-app-server` mode를 추가하고 executor/session reporter 라우팅을 분리한다.
  - `rpc-lifecycle`: `codex app-server --stdio` 프로세스를 시작한 뒤 `initialize`, `initialized`, `thread/start`, `turn/start` 흐름을 안정적으로 처리한다.
- Completion mode: check-on-pass

## 분석 결과
### 읽은 파일
- Agent-Ops: `agent-ops/rules/project/rules.md`, `agent-ops/rules/common/rules-roadmap.md`, `agent-ops/skills/common/router.md`, `agent-ops/skills/common/plan/SKILL.md`
- Roadmap: `agent-roadmap/current.md`, `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`, `agent-roadmap/phase/automation-runtime-bridge/milestones/codex-app-server-streaming-migration.md`
- Domain/test rules: `agent-ops/rules/project/domain/node/rules.md`, `agent-ops/rules/project/domain/platform-common/rules.md`, `agent-ops/rules/project/domain/testing/rules.md`, `agent-test/local/rules.md`, `agent-test/local/node-smoke.md`, `agent-test/local/platform-common-smoke.md`, `agent-test/local/testing-smoke.md`
- 코드: `apps/node/internal/adapters/cli/cli.go`, `apps/node/internal/adapters/cli/codex_exec.go`, `apps/node/internal/adapters/cli/opencode_sse.go`, `apps/node/internal/adapters/cli/oneshot.go`, `apps/node/internal/adapters/cli/emitters.go`, `apps/node/internal/runtime/types.go`, `apps/node/internal/adapters/cli/internal/testutil/testutil.go`
- 테스트: `apps/node/internal/adapters/cli/cli_internal_test.go`, `apps/node/internal/adapters/cli/codex_exec_blackbox_test.go`, `apps/node/internal/adapters/cli/opencode_sse_internal_test.go`, `apps/node/internal/adapters/cli/opencode_sse_blackbox_test.go`
- 임시 생성 타입: `/tmp/iop-codex-appserver-ts/ClientRequest.ts`, `/tmp/iop-codex-appserver-ts/ServerNotification.ts`, `/tmp/iop-codex-appserver-ts/v2/*`

### 테스트 환경 규칙
- 환경 미지정은 local로 본다.
- 신선한 Go 검증은 필요한 경우 `-count=1`을 사용한다.
- 기본 검증 후보: `go test ./apps/node/internal/adapters/cli -count=1`, `go test ./apps/node/... -count=1`
- 외부 Codex CLI와 계정 상태가 필요한 검증은 local runner에서 실행하고, 사용자 소유 계정 문제일 때만 사용자 리뷰 요청으로 남긴다.

### 테스트 커버리지 공백
- 현재 app-server RPC client가 없으므로 mode routing, 초기화 request shape, stdin/stdout newline framing, 프로세스 종료/중복 종료 테스트가 없다.
- `Content-Length`와 JSON-RPC envelope를 쓰지 않는다는 회귀 테스트가 필요하다.

### 심볼 참조
- 기존 심볼명 변경 없음.
- 추가 예정: `modeCodexAppServer`, `codexAppServerExecutor`, `codexAppServerSession`, app-server request/notification helper.
- 호출 지점: `CLI.New`, `CLI.Start`, `shouldAutostartPersistentProfile`, `executorFor`, `sessionReporterFor`, `Stop`.

### 분할 판단
분할 정책을 평가했고 공유 task group은 `agent-task/m-codex-app-server-streaming-migration/`이다. sibling subtask는 `01_appserver_rpc_client`(선행 없음), `02+01_session_events`(`01` 의존), `03+02_default_profile`(`02` 의존), `04+03_stream_smoke`(`03` 의존)이다. 현재 작업은 `mode-router`와 `rpc-lifecycle`만 닫으며, 후속 작업은 각 선행 `complete.log`가 없으면 구현하지 않는다.

### 범위 결정 근거
새 mode와 프로세스/RPC lifecycle은 모든 후속 작업의 기반이다. event map까지 동시에 넣으면 adapter 내부 상태와 runtime 이벤트 계약이 섞여 리뷰 단위가 커지므로 분리한다.

### 빌드 등급
`cloud-G07`: 외부 Codex CLI protocol과 프로세스 lifecycle을 다루므로 단위 테스트만으로는 부족하고, CLI가 설치된 local/cloud runner 검증이 필요하다.

## 구현 체크리스트
- [ ] `codex app-server --stdio`용 mode 상수와 executor/session 타입을 추가한다.
- [ ] `CLI.New`, `executorFor`, `sessionReporterFor`, `shouldAutostartPersistentProfile`, `Stop`에 새 executor를 연결한다.
- [ ] newline JSON RPC request writer와 response/notification reader를 구현한다.
- [ ] `initialize` request와 `initialized` notification을 startup sequence로 검증한다.
- [ ] process close가 중복 호출과 context cancel에서 안전하게 동작하게 한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] 새 mode를 CLI adapter 라우터에 연결
문제: `apps/node/internal/adapters/cli/cli.go:31`의 mode 목록에는 app-server mode가 없고, `executorFor`는 `codex-exec`만 Codex 전용 executor로 라우팅한다.

해결 방법: `modeCodexAppServer = "codex-app-server"`를 추가하고 `codexAppServerExecutor`를 `CLI` 필드, 생성자, reporter 목록에 연결한다. `shouldAutostartPersistentProfile`에서 persistent auto-start 대상에서 제외한다.

수정 파일 및 체크리스트:
- [ ] `apps/node/internal/adapters/cli/cli.go`
- [ ] `apps/node/internal/adapters/cli/cli_internal_test.go`

테스트 작성:
- [ ] app-server profile이 새 executor로 라우팅되는 단위 테스트
- [ ] persistent=true인 app-server profile이 legacy persistent startup으로 들어가지 않는 테스트

중간 검증:
```bash
go test ./apps/node/internal/adapters/cli -run 'TestExecutorForMode|TestCLIStartSkipsCodexAppServerPersistentStartup' -count=1
```

### [API-2] app-server stdio 프로세스와 RPC lifecycle 구현
문제: `opencode_sse.go`는 HTTP/SSE lifecycle을, `codex_exec.go`는 one-shot exec resume을 다룬다. app-server는 stdio process와 request id 기반 response matching이 필요하다.

해결 방법: 새 파일 `codex_app_server.go`를 추가해 profile command/args에서 `codex app-server --stdio`를 실행한다. stdout은 line scanner로 읽고, request id별 response channel과 notification channel을 분리한다. startup은 `initialize` response 수신 후 `initialized` notification 전송까지 완료해야 성공으로 본다.

수정 파일 및 체크리스트:
- [ ] `apps/node/internal/adapters/cli/codex_app_server.go`
- [ ] `apps/node/internal/adapters/cli/codex_app_server_internal_test.go`

테스트 작성:
- [ ] fake process pipe로 `initialize` request shape 검증
- [ ] `jsonrpc` 필드가 붙지 않는지 검증
- [ ] server stderr/process exit가 adapter error로 surfaced 되는지 검증

중간 검증:
```bash
go test ./apps/node/internal/adapters/cli -run 'TestCodexAppServerRPC|TestCodexAppServerProcessLifecycle' -count=1
```

### [API-3] 세션 시작의 최소 골격까지 연결
문제: 후속 작업이 turn/event mapping을 붙이려면 app-server process가 논리 session key에 묶여 있어야 한다.

해결 방법: `resolveCodexAppServerSession`을 구현해 `sessionKey{target, sessionID}` 단위로 process를 재사용한다. 최초 생성 시 `thread/start`까지 호출해 Codex thread id를 session에 저장하되, turn 실행과 event mapping은 후속 plan에서 구현한다.

수정 파일 및 체크리스트:
- [ ] `apps/node/internal/adapters/cli/codex_app_server.go`
- [ ] `apps/node/internal/adapters/cli/codex_app_server_internal_test.go`

테스트 작성:
- [ ] 같은 target/sessionID가 같은 app-server session을 재사용하는 테스트
- [ ] `SessionModeRequireExisting`에서 없으면 에러가 나는 테스트

중간 검증:
```bash
go test ./apps/node/internal/adapters/cli -run 'TestCodexAppServerSessionResolve|TestCodexAppServerRequireExisting' -count=1
```

## 수정 파일 요약
| 파일 | 항목 |
| --- | --- |
| `apps/node/internal/adapters/cli/cli.go` | API-1 |
| `apps/node/internal/adapters/cli/codex_app_server.go` | API-2, API-3 |
| `apps/node/internal/adapters/cli/codex_app_server_internal_test.go` | API-2, API-3 |
| `apps/node/internal/adapters/cli/cli_internal_test.go` | API-1 |

## 최종 검증
```bash
go test ./apps/node/internal/adapters/cli -count=1
go test ./apps/node/... -count=1
```

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