<!-- task=01_command_runtime_api plan=0 tag=REFACTOR -->

# Command Runtime API Plan

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

**구현 마지막 단계에서 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 반드시 채워야 한다. 해당 파일의 모든 구현 소유 섹션을 채우기 전까지 작업은 완료가 아니다.** 구현 체크리스트를 따라 작업하고, 중간/최종 검증 출력은 review stub에 실제 stdout/stderr로 기록한다. review 파일의 아카이브 지시와 `코드리뷰 전용 체크리스트`는 코드리뷰 에이전트 전용이므로 실행하거나 수정하지 않는다.

## 배경

`CommandRuntime`는 생겼지만 현재 API가 `ProcessExecutor.start/run`의 사용 옵션을 모두 담지 못한다. 그래서 command 파일을 포트 뒤로 옮기기 전에 runtime 계약을 먼저 넓혀야 한다. 이 작업은 후속 command 이전 작업의 기반이다.

## 분석 결과

### 읽은 파일

- `lib/oto/commands/command_runtime.dart`
- `test/oto_command_runtime_test.dart`

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

- 기존 fake runtime은 `start` shell, `run` shell, detached 호출만 확인한다.
- `workspace`, `decoder`, `printStdout`, `printStderr`, executable/arguments 전달 검증이 없다.

### 심볼 참조

- 제거/이름 변경 없음.
- 확장 대상: `CommandRuntime.start`, `CommandRuntime.run`, 새 `CommandRuntime.runExecutable`.

### 범위 결정 근거

- 이 plan은 runtime 인터페이스와 fake runtime 테스트 기반만 수정한다.
- command 구현 이전은 `02+01_process_executor_commands`, SFTP/SMB 이전은 `03+01_sftp_smb_runtime`에서 처리한다.

### 빌드 등급

- build=`cloud-G07`, review=`cloud-G07`: 프로세스 실행 포트와 stdout/stderr/exit-code 계약을 바꾸는 터미널 에이전트 기반 작업이다.

## 구현 체크리스트

- [ ] `CommandRuntime` API를 command 도메인 잔여 호출 옵션을 표현할 수 있게 확장한다.
- [ ] `DefaultCommandRuntime`가 확장된 옵션을 기존 `ProcessExecutor`/`Process.run` 의미와 동일하게 위임하게 한다.
- [ ] fake runtime 테스트 기반을 옵션과 executable 호출을 캡처하도록 갱신한다.
- [ ] 중간 검증과 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] CommandRuntime API 확장

#### 문제

`CommandRuntime.start`는 `printStderr`, `logHandler`만 받아서 `workspace`, `decoder`, `printStdout` 사용 command를 이전할 수 없다.

Before:

```dart
// lib/oto/commands/command_runtime.dart:9
abstract class CommandRuntime {
  Future<ProcessData> start(StringBuffer shell,
      {bool printStderr = true, LogHandler? logHandler});

  Future<ProcessResult> run(StringBuffer shell);
}
```

#### 해결 방법

`start`와 `run` 옵션을 확장하고, `Process.run(executable,args)` 계열을 위한 `runExecutable`을 추가한다. `DefaultCommandRuntime`는 기존 구현체로 그대로 위임한다.

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

- [ ] `lib/oto/commands/command_runtime.dart`: `dart:convert` import, start/run 옵션, `runExecutable` 추가.
- [ ] `test/oto_command_runtime_test.dart`: fake runtime이 start/run/executable 옵션을 기록하도록 변경.

#### 테스트 작성

작성한다. `runtime captures start options`, `runtime captures run workspace`, `runtime captures executable arguments` 테스트를 추가한다.

#### 중간 검증

```bash
dart test test/oto_command_runtime_test.dart
```

예상: runtime 테스트 통과.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `lib/oto/commands/command_runtime.dart` | REFACTOR-1 |
| `test/oto_command_runtime_test.dart` | REFACTOR-1 |

## 최종 검증

```bash
dart format lib/oto/commands/command_runtime.dart test/oto_command_runtime_test.dart
dart analyze
dart test test/oto_command_runtime_test.dart
```

예상: format 정상, analyze 통과, runtime 테스트 통과. Dart test는 캐시가 없으므로 fresh 실행만 인정한다.

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