# 機能設計書 54-TUI

## 概要

本ドキュメントは、OpenCodeのTUI（Terminal User Interface）について、その設計仕様を記述するものである。

### 本機能の処理概要

TUI機能は、ターミナル上で動作するテキストベースのユーザーインターフェースを提供する機能である。@opentui/solidフレームワークを使用し、SolidJSのリアクティブ性をターミナル環境で実現している。コマンドラインからOpenCodeを起動し、AIアシスタントとの対話、セッション管理、ファイル編集などの操作をターミナル内で完結できる。

**業務上の目的・背景**：GUIを持たないサーバー環境やSSH接続環境でも、OpenCodeの全機能を利用できるようにする必要がある。TUIはマウス不要でキーボードのみで操作可能であり、開発者にとって効率的なワークフローを提供する。

**機能の利用シーン**：
- リモートサーバーへのSSH接続時のAIアシスタント利用
- ターミナルを離れずに開発作業を行う場合
- コマンドラインツールとしてのOpenCode利用
- CI/CD環境での自動化スクリプト内での利用

**主要な処理内容**：
1. ターミナル描画エンジン（@opentui/core）による画面レンダリング
2. キーボード入力のハンドリング（useKeyboard）
3. SolidJSベースのリアクティブUIコンポーネント
4. ワーカースレッドによるバックグラウンドサーバー処理
5. RPC通信によるメインスレッド-ワーカー間の連携
6. ターミナル背景色の自動検出によるテーマ切り替え

**関連システム・外部連携**：OpenCode HTTPサーバー（ワーカー経由またはリモート）、ターミナルエミュレータ

**権限による制御**：Basic認証によるサーバー接続

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | ホーム | 主機能 | MCPサーバー接続状態表示、コマンドダイアログ |
| 26 | セッション | 主機能 | エージェント実行、ツール結果表示、メッセージ管理 |

## 機能種別

ターミナルUI / CLI

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| project | string | No | プロジェクトディレクトリパス | 有効なパス |
| model | string | No | 使用するモデル（provider/model形式） | - |
| continue | boolean | No | 最後のセッションを継続 | - |
| session | string | No | 継続するセッションID | ses*形式 |
| fork | boolean | No | セッションをフォーク | --continueまたは--sessionと併用 |
| prompt | string | No | 初期プロンプト | - |
| agent | string | No | 使用するエージェント | - |

### 入力データソース

- コマンドライン引数
- 標準入力（パイプ入力）
- キーボード入力
- マウス入力（対応ターミナル）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| terminal | ANSI出力 | ターミナル画面への描画 |
| clipboard | string | コピー内容 |

### 出力先

- 標準出力（ターミナル描画）
- システムクリップボード

## 処理フロー

### 処理シーケンス

```
1. CLIコマンド解析
   └─ TuiThreadCommand: yargsによるオプション解析

2. ワーカー起動
   └─ Worker(worker.ts): バックグラウンドサーバー/RPC処理

3. サーバー接続
   └─ RPC経由またはHTTPサーバー直接接続

4. ターミナル初期化
   └─ getTerminalBackgroundColor(): 背景色検出

5. UIレンダリング開始
   └─ render(): SolidJSコンポーネントツリーマウント

6. イベントループ
   └─ キーボード/マウス入力 → 状態更新 → 再描画
```

### フローチャート

```mermaid
flowchart TD
    A[opencode コマンド] --> B[TuiThreadCommand.handler]
    B --> C{--port/--hostname指定?}
    C -->|Yes| D[HTTPサーバー起動]
    C -->|No| E[RPC直接通信モード]
    D --> F[サーバーURL取得]
    E --> G[createWorkerFetch]
    F --> H[tui関数呼び出し]
    G --> H
    H --> I[getTerminalBackgroundColor]
    I --> J[render]
    J --> K[プロバイダー階層構築]
    K --> L[Home/Session表示]
    L --> M[イベントループ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 背景色自動検出 | ターミナル背景色をOSC 11で取得し、ダーク/ライトモード自動切替 | 起動時 |
| BR-02 | パイプ入力対応 | process.stdin.isTTY === falseの場合、標準入力をプロンプトに追加 | パイプ入力時 |
| BR-03 | フォーク制限 | --forkは--continueまたは--sessionと併用必須 | 引数解析時 |
| BR-04 | Ctrl+Cハンドリング | Windows上でのCtrl+Cを適切に処理 | Windows環境 |
| BR-05 | セッション選択 | ses*形式のIDでセッション指定 | TuiEvent.SessionSelect |

### 計算ロジック

- 背景色輝度計算: `luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255`
- ダーク/ライト判定: `luminance > 0.5 ? "light" : "dark"`

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | TUI自体はDB操作なし（ワーカー/サーバー経由） |

### テーブル別操作詳細

KVストレージ（ファイルベース）を使用してTUI固有の設定を永続化。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ディレクトリ変更失敗 | 指定パスが存在しない | エラー表示、終了 |
| - | ワーカーエラー | ワーカースレッドでの例外 | ログ出力、継続 |
| - | レンダリングエラー | コンポーネントエラー | ErrorBoundaryで捕捉 |

### リトライ仕様

- サーバー接続: RPCエラー時は自動的に再試行
- イベントストリーム: 切断時250ms後に再接続

## トランザクション仕様

該当なし（ターミナルUI）

## パフォーマンス要件

- 起動時間: ワーカー起動含め数秒以内
- 入力応答: 60FPSターゲット（約16ms以内）

## セキュリティ考慮事項

- Basic認証対応（OPENCODE_SERVER_PASSWORD）
- stdin rawモード時のセキュリティ考慮

## 備考

- フレームワーク: @opentui/solid + @opentui/core
- Windows特別対応: win32.ts（Ctrl+C、rawモード）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

TUIのイベント定義とコンテキスト構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.ts | `packages/opencode/src/cli/cmd/tui/event.ts` | TuiEventの定義 |
| 1-2 | args.ts | `packages/opencode/src/cli/cmd/tui/context/args.ts` | Args型定義 |

**読解のコツ**:
- **5-48行目（event.ts）**: `TuiEvent`でプロンプト追加、コマンド実行、Toast表示、セッション選択のイベントを定義
- BusEventパターンでイベント駆動アーキテクチャを実現

#### Step 2: エントリーポイントを理解する

TUIの起動フローを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | thread.ts | `packages/opencode/src/cli/cmd/tui/thread.ts` | CLIコマンド定義、ワーカー起動 |
| 2-2 | app.tsx | `packages/opencode/src/cli/cmd/tui/app.tsx` | tui()関数、プロバイダー階層 |

**主要処理フロー（thread.ts）**:
1. **82-96行目**: yargsオプション解析、--forkの検証
2. **98-113行目**: 作業ディレクトリ設定、ワーカーパス解決
3. **114-128行目**: Worker起動、エラーハンドラ設定
4. **140-162行目**: サーバー接続モード判定（HTTP or RPC直接）
5. **164-179行目**: tui()呼び出し

**主要処理フロー（app.tsx）**:
- **42-100行目**: `getTerminalBackgroundColor()` - ターミナル背景色検出
- **104-112行目**: `tui`関数のシグネチャ
- **130-150行目**: プロバイダー階層構築（ArgsProvider→ExitProvider→SDKProvider等）

#### Step 3: ワーカー処理を理解する

バックグラウンドワーカーの処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | worker.ts | `packages/opencode/src/cli/cmd/tui/worker.ts` | RPC定義、サーバー起動 |

**主要処理フロー**:
- **36-38行目**: GlobalBusイベントをRPC経由で転送
- **46-95行目**: イベントストリームの購読と転送
- **99-147行目**: `rpc`オブジェクト - fetch, server, reload, shutdown等のRPCメソッド

#### Step 4: Windows固有処理を理解する

Windows環境での特別処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | win32.ts | `packages/opencode/src/cli/cmd/tui/win32.ts` | Ctrl+Cガード、rawモード制御 |

**読解のコツ**:
- `win32DisableProcessedInput()`: ENABLE_PROCESSED_INPUTを無効化してCtrl+Cを自前で処理
- `win32InstallCtrlCGuard()`: Ctrl+Cシグナルのガード

### プログラム呼び出し階層図

```
TuiThreadCommand (thread.ts)
    │
    ├─ Worker(worker.ts)
    │      │
    │      ├─ Server.listen() / Server.App().fetch()
    │      │
    │      ├─ GlobalBus.on("event") → Rpc.emit
    │      │
    │      └─ rpc.fetch / rpc.server / rpc.shutdown
    │
    └─ tui() (app.tsx)
           │
           ├─ getTerminalBackgroundColor()
           │
           └─ render()
                  │
                  └─ プロバイダー階層
                         ├─ ArgsProvider
                         ├─ ExitProvider
                         ├─ KVProvider
                         ├─ ToastProvider
                         ├─ RouteProvider
                         ├─ SDKProvider
                         ├─ SyncProvider
                         ├─ ThemeProvider
                         ├─ LocalProvider
                         └─ ...
                              │
                              └─ Home / Session
```

### データフロー図

```
[入力]                   [処理]                         [出力]

CLI引数
  --model等 ────────────▶ TuiThreadCommand ────────────▶ Args
     │
パイプ入力
  stdin ────────────────▶ Bun.stdin.text() ────────────▶ prompt追加
     │
キーボード入力
  keypress ─────────────▶ useKeyboard ─────────────────▶ 状態更新
     │                                                      │
     │                                                      ▼
     │                   @opentui/solid
     │                   render() ─────────────────────▶ ANSI出力
     │
ワーカー
  RPC ──────────────────▶ rpc.fetch/event ─────────────▶ SDKProvider
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| thread.ts | `packages/opencode/src/cli/cmd/tui/thread.ts` | ソース | TUIコマンドエントリー |
| app.tsx | `packages/opencode/src/cli/cmd/tui/app.tsx` | ソース | TUIアプリケーション本体 |
| worker.ts | `packages/opencode/src/cli/cmd/tui/worker.ts` | ソース | ワーカースレッド処理 |
| attach.ts | `packages/opencode/src/cli/cmd/tui/attach.ts` | ソース | リモートサーバー接続 |
| event.ts | `packages/opencode/src/cli/cmd/tui/event.ts` | ソース | TUIイベント定義 |
| win32.ts | `packages/opencode/src/cli/cmd/tui/win32.ts` | ソース | Windows固有処理 |
| ui/spinner.ts | `packages/opencode/src/cli/cmd/tui/ui/spinner.ts` | ソース | スピナーコンポーネント |
| context/directory.ts | `packages/opencode/src/cli/cmd/tui/context/directory.ts` | ソース | ディレクトリコンテキスト |
| util/clipboard.ts | `packages/opencode/src/cli/cmd/tui/util/clipboard.ts` | ソース | クリップボード操作 |
| util/terminal.ts | `packages/opencode/src/cli/cmd/tui/util/terminal.ts` | ソース | ターミナルユーティリティ |
