<!-- task=oto_agent_registration/01_agent_cli_config plan=1 tag=REVIEW_AGENT_CLI -->

# Plan - REVIEW_AGENT_CLI

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

이 plan은 `code_review_local_G06_0.log`의 `FAIL` Required 항목만 해결한다. 구현 완료 전 `CODE_REVIEW-local-G06.md`의 구현 에이전트 소유 섹션을 반드시 채우고, 검증 명령의 실제 stdout/stderr를 붙인다. active 파일은 그대로 둔 채 review 준비 상태를 보고한다.

## 배경

첫 리뷰에서 `dart analyze` 재실행이 실패했고, `AgentConfig` parser가 계획의 alias 보존 및 잘못된 타입 오류 계약을 지키지 못했다. 이 follow-up은 정적 분석 실패와 config parser 계약만 수정한다.

## 구현 체크리스트

- [ ] REVIEW_AGENT_CLI-1 `dart analyze` 실패를 유발하는 unused import를 제거한다.
- [ ] REVIEW_AGENT_CLI-2 `agent.alias`의 null/empty 보존 계약을 복구한다.
- [ ] REVIEW_AGENT_CLI-3 `AgentConfig` 문자열 타입 검증과 invalid type 테스트를 추가한다.
- [ ] 모든 중간 검증과 최종 검증을 실행하고 실제 stdout/stderr를 `CODE_REVIEW-local-G06.md`에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_AGENT_CLI-1] analyzer 실패 수정

#### 문제

- `test/oto_agent_cli_test.dart:1`의 `dart:convert` import가 사용되지 않아 `dart analyze`가 exit code 2로 실패한다.
- 이전 리뷰 파일의 최종 검증 기록은 `No issues found!`였지만 실제 재실행 결과와 불일치했다.

#### 해결 방법

- `test/oto_agent_cli_test.dart`에서 unused import를 제거한다.
- 검증 결과는 새 `CODE_REVIEW-local-G06.md`에 실제 재실행 출력으로 기록한다.

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

- [ ] `test/oto_agent_cli_test.dart`: unused `dart:convert` import 제거.

#### 테스트 작성

- 새 테스트 없음. 정적 분석 실패 수정이다.

#### 중간 검증

```bash
dart analyze
```

예상 결과: analyzer issue 없음.

### [REVIEW_AGENT_CLI-2] alias null/empty 보존

#### 문제

- `PLAN-local-G06.md` 원 계획은 `agent.alias`를 optional string으로 두고 null/empty를 그대로 보존하라고 했다.
- 현재 구현은 `alias: ""`를 `null`로 변환하고 테스트도 이를 기대한다.

#### 해결 방법

Before:

```dart
final String? alias = (aliasVal == null || aliasVal.toString().trim().isEmpty) ? null : aliasVal.toString();
```

After:

```dart
final alias = _optionalString(agentMap, 'agent.alias', 'alias');
```

`_optionalString`은 키가 없거나 값이 null이면 null, 값이 String이면 empty 포함 원문을 반환한다. String이 아닌 값은 `AgentConfigException`으로 거부한다.

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

- [ ] `lib/oto/agent/agent_config.dart`: alias parsing에서 empty string을 null로 접지 않는다.
- [ ] `test/oto_agent_config_test.dart`: empty alias는 `''`, 누락 alias는 `null`임을 검증한다.

#### 테스트 작성

- 작성/수정: `test/oto_agent_config_test.dart`
- 테스트 이름:
  - `AgentConfig preserves empty alias`
  - `AgentConfig parses missing alias as null`

#### 중간 검증

```bash
dart test test/oto_agent_config_test.dart
```

예상 결과: 모든 테스트 통과.

### [REVIEW_AGENT_CLI-3] 문자열 타입 검증

#### 문제

- 현재 parser는 필수 값과 URL/path 값을 `toString()`으로 변환해 list/int/bool 같은 잘못된 YAML 타입도 통과시킨다.
- 원 계획은 누락/잘못된 타입 오류를 command layer에서 노출 가능한 `AgentConfigException`으로 정리하라고 했다.

#### 해결 방법

- `AgentConfig.fromYamlContent`에 string field 추출 helper를 둔다.
- 필수 필드는 값이 String이고 `trim().isNotEmpty`일 때만 허용한다.
- optional alias는 null 또는 String만 허용한다.
- 오류 메시지에는 `agent.id`, `agent.enrollment_token`, `edge.url`, `runtime.install_dir`, `runtime.workspace_root`, `runtime.log_dir`, `agent.alias` 중 어느 필드가 문제인지 포함한다.

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

- [ ] `lib/oto/agent/agent_config.dart`: 필수 string helper와 optional string helper 추가.
- [ ] `lib/oto/agent/agent_config.dart`: 모든 config field에서 임의 `toString()` coercion 제거.
- [ ] `test/oto_agent_config_test.dart`: required field와 alias의 invalid type 거부 테스트 추가.

#### 테스트 작성

- 작성: `test/oto_agent_config_test.dart`
- 테스트 이름:
  - `AgentConfig rejects invalid field types`

#### 중간 검증

```bash
dart test test/oto_agent_config_test.dart
```

예상 결과: 모든 테스트 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/oto/agent/agent_config.dart` | REVIEW_AGENT_CLI-2, REVIEW_AGENT_CLI-3 |
| `test/oto_agent_config_test.dart` | REVIEW_AGENT_CLI-2, REVIEW_AGENT_CLI-3 |
| `test/oto_agent_cli_test.dart` | REVIEW_AGENT_CLI-1 |

## 최종 검증

```bash
dart analyze
dart test test/oto_agent_config_test.dart test/oto_agent_cli_test.dart
dart run bin/main.dart agent -h
dart run bin/main.dart agent run -h
```

예상 결과: `dart analyze` 경고/오류 없음, 테스트 통과, help command exit code 0.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
