# 機能設計書 47-PTY管理

## 概要

本ドキュメントは、OpenCodeにおけるPTY（Pseudo-Terminal/疑似ターミナル）管理機能の設計を記述する。Web UIやデスクトップアプリでターミナルセッションを作成・管理するための機能を提供する。

### 本機能の処理概要

PTY管理機能は、bun-ptyライブラリを使用して疑似ターミナルの作成・管理・終了を行う。各PTYセッションは独立したシェルプロセスを持ち、複数のクライアントからの同時接続をサポートする。ターミナル出力のバッファリング、リサイズ処理、プロセス終了検知など、ターミナルエミュレーターとして必要な機能を提供する。

**業務上の目的・背景**：AIエージェントがBashコマンドを実行する際、その結果を確認したり、対話的なコマンドを実行したりするためにターミナルが必要となる。PTY管理により、Web UIやデスクトップアプリ内で完全なターミナル体験を提供でき、ローカル開発環境と同等の操作性を実現する。また、複数のターミナルセッションを並行して管理することで、マルチタスクの開発作業をサポートする。

**機能の利用シーン**：
- セッション画面でのターミナルパネル表示
- Bashコマンドの対話的実行（vi、less、top等）
- 長時間実行コマンドの監視
- 複数ターミナルの並行利用

**主要な処理内容**：
1. PTYセッションの作成（シェルプロセスの起動）
2. セッション情報の管理（ID、タイトル、状態等）
3. ターミナル出力のバッファリングと配信
4. ターミナルリサイズ処理
5. プロセス終了検知とクリーンアップ

**関連システム・外部連携**：
- bun-pty: PTY実装ライブラリ
- Shell: ユーザーの優先シェル検出
- Plugin: シェル環境変数のカスタマイズ

**権限による制御**：APIエンドポイントはHTTP APIサーバーの認証設定に従う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | セッション画面 | 補助機能 | TerminalPanelコンポーネントによるターミナル表示 |

## 機能種別

プロセス管理 / リアルタイム通信

## 入力仕様

### 作成パラメータ（CreateInput）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| command | string | No | 実行コマンド（デフォルト: 優先シェル） | - |
| args | string[] | No | コマンド引数 | - |
| cwd | string | No | 作業ディレクトリ（デフォルト: Instance.directory） | 有効なパス |
| title | string | No | セッションタイトル | - |
| env | Record<string, string> | No | 追加環境変数 | - |

### 更新パラメータ（UpdateInput）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| title | string | No | 新しいタイトル | - |
| size | {rows: number, cols: number} | No | ターミナルサイズ | 正の整数 |

### 入力データソース

- HTTPリクエスト（POST /pty, PUT /pty/:ptyID）
- WebSocketメッセージ（文字入力）

## 出力仕様

### 出力データ（Info型）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | PTYセッションID（pty_プレフィックス） |
| title | string | セッションタイトル |
| command | string | 実行コマンド |
| args | string[] | コマンド引数 |
| cwd | string | 作業ディレクトリ |
| status | "running" \| "exited" | セッション状態 |
| pid | number | プロセスID |

### イベント

| イベント種別 | 説明 |
|-------------|------|
| pty.created | セッション作成時 |
| pty.updated | セッション更新時 |
| pty.exited | プロセス終了時 |
| pty.deleted | セッション削除時 |

### 出力先

- HTTPレスポンス（JSON形式）
- Busイベント

## 処理フロー

### 処理シーケンス

```
1. セッション作成（create）
   ├─ ID生成（Identifier.create）
   ├─ シェルコマンド決定
   ├─ 環境変数構築（Plugin.trigger経由）
   ├─ bun-pty spawn 実行
   ├─ onData コールバック設定
   ├─ onExit コールバック設定
   └─ イベント発行（pty.created）

2. データ受信（onData）
   ├─ カーソル位置更新
   ├─ 全購読者にデータ送信
   └─ バッファに追加（2MB制限）

3. プロセス終了（onExit）
   ├─ ステータス更新（exited）
   ├─ 全購読者のWebSocket切断
   ├─ イベント発行（pty.exited）
   └─ セッションマップから削除
```

### フローチャート

```mermaid
flowchart TD
    A[POST /pty] --> B[ID生成]
    B --> C[シェルコマンド決定]
    C --> D[環境変数構築]
    D --> E[bun-pty spawn]
    E --> F[セッションマップに登録]
    F --> G[onData コールバック設定]
    G --> H[onExit コールバック設定]
    H --> I[pty.created イベント発行]
    I --> J{データ受信?}
    J -->|Yes| K[カーソル更新]
    K --> L[購読者に配信]
    L --> M[バッファ追加]
    M --> J
    J -->|プロセス終了| N[status = exited]
    N --> O[購読者切断]
    O --> P[pty.exited イベント発行]
    P --> Q[セッション削除]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-01 | デフォルトシェル | command未指定時は Shell.preferred() を使用 | 作成時 |
| BR-47-02 | ログインシェル | シェルコマンドの場合 -l オプションを追加 | 作成時（shで終わる場合） |
| BR-47-03 | バッファ制限 | 出力バッファは2MBを超えない | データ受信時 |
| BR-47-04 | 環境変数 | TERM=xterm-256color, OPENCODE_TERMINAL=1 を設定 | 作成時 |
| BR-47-05 | 自動クリーンアップ | Instance終了時に全セッションをkill | インスタンス破棄時 |

### 計算ロジック

タイトル自動生成：
```typescript
title = input.title || `Terminal ${id.slice(-4)}`
```

Windows環境設定：
```typescript
if (process.platform === "win32") {
  env.LC_ALL = "C.UTF-8"
  env.LC_CTYPE = "C.UTF-8"
  env.LANG = "C.UTF-8"
}
```

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

本機能はデータベースを操作しない。セッション情報はメモリ上のMapで管理。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFoundError | 存在しないセッションへのアクセス | エラーレスポンス返却 |
| - | spawn失敗 | PTYプロセス起動失敗 | 例外スロー |
| - | kill失敗 | プロセス終了失敗 | catchで無視 |

### リトライ仕様

リトライは実装されていない。

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

トランザクション管理なし。各操作は独立して処理される。

## パフォーマンス要件

- PTY出力は即座に配信（低遅延）
- バッファサイズ2MBで履歴保持
- 複数セッションの並行管理

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

- シェルプロセスはサーバーの権限で実行
- 環境変数は信頼できるソースからのみ設定
- Instance.directory 内での実行を推奨

## 備考

APIエンドポイント：
- GET /pty - セッション一覧取得
- POST /pty - セッション作成
- GET /pty/:ptyID - セッション情報取得
- PUT /pty/:ptyID - セッション更新
- DELETE /pty/:ptyID - セッション削除
- GET /pty/:ptyID/connect - WebSocket接続

---

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

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

### 推奨読解順序

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

PTYセッションの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/opencode/src/pty/index.ts` | Info型（95-106行目）、CreateInput型（109-117行目）、UpdateInput型（119-129行目） |
| 1-2 | index.ts | `packages/opencode/src/pty/index.ts` | ActiveSession型（138-145行目）、Event定義（131-136行目） |

**読解のコツ**: Info型は外部公開される情報、ActiveSession型は内部管理用の拡張情報。

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

PTY作成の実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/opencode/src/pty/index.ts` | create関数（174-272行目） |

**主要処理フロー**:
1. **175行目**: ID生成
2. **176-180行目**: コマンドと引数の決定
3. **182-196行目**: 環境変数の構築
4. **199-204行目**: bun-pty spawn 実行
5. **206-222行目**: セッション情報とActiveSession構築
6. **224-255行目**: onData コールバック設定
7. **256-269行目**: onExit コールバック設定

#### Step 3: 更新・削除処理を理解する

その他のCRUD操作を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/opencode/src/pty/index.ts` | update関数（274-285行目） |
| 3-2 | index.ts | `packages/opencode/src/pty/index.ts` | remove関数（287-304行目） |
| 3-3 | index.ts | `packages/opencode/src/pty/index.ts` | resize関数（306-311行目）、write関数（313-318行目） |

**主要処理フロー**:
- **274-285行目（update）**: タイトル変更、リサイズ
- **287-304行目（remove）**: kill、購読者切断、削除
- **306-311行目（resize）**: ptyProcess.resize 呼び出し

#### Step 4: APIルートを理解する

HTTPエンドポイントの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pty.ts | `packages/opencode/src/server/routes/pty.ts` | 全ルート定義（10-200行目） |

**主要処理フロー**:
- **12-31行目**: GET /pty - list
- **33-56行目**: POST /pty - create
- **57-83行目**: GET /pty/:ptyID - get
- **84-108行目**: PUT /pty/:ptyID - update
- **109-132行目**: DELETE /pty/:ptyID - remove

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

```
POST /pty
    │
    └─ Pty.create(input)
           │
           ├─ Identifier.create("pty")
           ├─ Shell.preferred()
           ├─ Plugin.trigger("shell.env")
           │
           └─ pty.spawn(command, args, options)
                  │
                  ├─ onData(chunk)
                  │      ├─ cursor更新
                  │      ├─ 購読者配信
                  │      └─ バッファ追加
                  │
                  └─ onExit({exitCode})
                         ├─ status更新
                         ├─ 購読者切断
                         └─ Bus.publish(pty.exited)
```

### データフロー図

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

CreateInput
       │
       ▼
Pty.create()
       │
       ▼
bun-pty spawn ───▶ シェルプロセス
       │                  │
       ▼                  ▼
セッションマップ      ptyProcess.onData
       │                  │
       ▼                  ▼
pty.created        購読者配信 + バッファ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/opencode/src/pty/index.ts` | ソース | PTY管理のメインモジュール |
| pty.ts | `packages/opencode/src/server/routes/pty.ts` | ソース | APIルート定義 |
| shell.ts | `packages/opencode/src/shell/shell.ts` | ソース | 優先シェル検出 |
| index.ts | `packages/opencode/src/plugin/index.ts` | ソース | shell.env プラグイントリガー |
| instance.ts | `packages/opencode/src/project/instance.ts` | ソース | 状態管理とクリーンアップ |
