# 機能設計書 11-Read ツール

## 概要

本ドキュメントは、OpenCodeのRead ツール機能の設計仕様を定義する。Read ツールは、ローカルファイルシステムからファイルやディレクトリを読み取り、その内容をエージェントに提供する機能を担う。

### 本機能の処理概要

Read ツールは、指定されたパスのファイルまたはディレクトリの内容を読み取り、エージェントが参照できる形式で返却する機能である。テキストファイル、画像、PDF、バイナリファイルなど多様なファイル形式に対応し、大容量ファイルの部分読み取りやバイナリ検出機能も備える。

**業務上の目的・背景**：AIエージェントがコードベースを理解し、開発支援を行うためには、ソースコードや設定ファイルの内容を読み取る機能が不可欠である。本ツールにより、エージェントはプロジェクト内のあらゆるファイルにアクセスし、コンテキストを把握した上で適切な支援を提供できる。

**機能の利用シーン**：
- ソースコードの内容確認・分析
- 設定ファイルの参照
- ドキュメントの読み取り
- 画像やPDFファイルの取得
- ディレクトリ構造の確認

**主要な処理内容**：
1. パスの正規化（相対パス→絶対パス変換）
2. 外部ディレクトリアクセスの権限確認
3. ファイル/ディレクトリの存在確認
4. ファイル種別の判定（ディレクトリ/画像/PDF/バイナリ/テキスト）
5. 内容の読み取りとフォーマット
6. 行番号付きでの出力生成

**関連システム・外部連携**：
- LSP（Language Server Protocol）：ファイル読み取り時にLSPサーバーに通知
- FileTime：読み取り時刻の記録
- InstructionPrompt：ファイルに関連する指示プロンプトの解決

**権限による制御**：
- `read`権限が必要
- 外部ディレクトリ（プロジェクト外）へのアクセスは`external_directory`権限が必要
- `bypassCwdCheck`フラグで権限チェックをスキップ可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | セッション | 補助機能 | Readコンポーネントによるファイル読み取り表示 |

## 機能種別

データ読み取り / ファイル操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filePath | string | Yes | 読み取り対象のファイルまたはディレクトリの絶対パス | 絶対パスであること（相対パスの場合は自動変換） |
| offset | number | No | 読み取り開始行番号（1-indexed） | 1以上の整数 |
| limit | number | No | 読み取る最大行数（デフォルト: 2000） | 正の整数 |

### 入力データソース

- ローカルファイルシステム
- 実行コンテキスト（セッションID、メッセージID等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| title | string | ファイルの相対パス |
| output | string | ファイル内容（行番号付き）またはディレクトリエントリ一覧 |
| metadata.preview | string | 最初の20行のプレビュー |
| metadata.truncated | boolean | 内容が切り詰められたかどうか |
| metadata.loaded | string[] | 読み込まれた指示プロンプトファイルのパス |
| attachments | array | 画像/PDFの場合のBase64エンコードデータ |

### 出力先

- エージェントへのレスポンス（ツール実行結果）
- 画像/PDFの場合はattachmentsとしてBase64エンコードで返却

## 処理フロー

### 処理シーケンス

```
1. パラメータ検証
   └─ offsetが1未満の場合はエラー

2. パス正規化
   └─ 相対パスの場合、Instance.directoryを基準に絶対パスに変換

3. ファイル状態取得
   └─ Filesystem.statでファイル/ディレクトリの存在と種別を確認

4. 外部ディレクトリチェック
   └─ プロジェクト外へのアクセス時は権限確認

5. 読み取り権限確認
   └─ ctx.askで権限を要求

6. ファイル存在確認
   └─ 存在しない場合、類似ファイル名を提案してエラー

7. ファイル種別による分岐処理
   ├─ ディレクトリ: エントリ一覧を返却
   ├─ 画像/PDF: Base64エンコードで返却
   ├─ バイナリ: エラーを返却
   └─ テキスト: 行番号付きで内容を返却

8. LSP通知・時刻記録
   └─ LSPへのファイルタッチ、FileTimeへの記録
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{offsetパラメータ検証}
    B -->|無効| ERROR1[エラー: offset must be >= 1]
    B -->|有効| C[パス正規化]
    C --> D[ファイル状態取得]
    D --> E{外部ディレクトリ?}
    E -->|Yes| F[外部ディレクトリ権限確認]
    E -->|No| G[読み取り権限確認]
    F --> G
    G --> H{ファイル存在?}
    H -->|No| I[類似ファイル検索]
    I --> ERROR2[エラー: File not found]
    H -->|Yes| J{ディレクトリ?}
    J -->|Yes| K[ディレクトリエントリ一覧取得]
    K --> OUTPUT[結果返却]
    J -->|No| L{画像/PDF?}
    L -->|Yes| M[Base64エンコード]
    M --> OUTPUT
    L -->|No| N{バイナリ?}
    N -->|Yes| ERROR3[エラー: Cannot read binary file]
    N -->|No| O[テキスト読み取り]
    O --> P[行番号付与]
    P --> Q[LSP通知]
    Q --> OUTPUT
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルト行数制限 | 1回の読み取りで最大2000行まで | limit未指定時 |
| BR-02 | 行長制限 | 1行あたり最大2000文字で切り詰め | 全テキストファイル |
| BR-03 | バイト制限 | 1回の読み取りで最大50KB | 全テキストファイル |
| BR-04 | バイナリ判定 | 非印字文字が30%以上でバイナリと判定 | 拡張子で判定できない場合 |
| BR-05 | 画像除外 | SVGとFastBidSheetは画像として扱わない | image/で始まるMIMEタイプ |

### 計算ロジック

**バイナリ判定ロジック**：
1. 拡張子による即時判定（.zip, .exe等は即バイナリ）
2. ファイル先頭4096バイトをサンプリング
3. NULLバイト（0x00）が存在すればバイナリ
4. 非印字文字（0x00-0x08, 0x0E-0x1F）が30%以上ならバイナリ

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

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

本機能はファイルシステムのみを操作し、データベースへの直接的な操作は行わない。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | offsetが1未満 | 正しいoffset値を指定 |
| - | FileNotFoundError | ファイルが存在しない | パスを確認、類似ファイル提案を参照 |
| - | BinaryFileError | バイナリファイルを読み取ろうとした | テキストファイルを指定 |
| - | OutOfRangeError | offsetがファイル行数を超過 | 適切なoffsetを指定 |

### リトライ仕様

本機能はリトライ処理を行わない。エラー発生時は即座にエラーを返却する。

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

ファイルシステム操作のため、トランザクション管理は行わない。

## パフォーマンス要件

- 読み取り行数制限: 2000行/回
- 読み取りバイト制限: 50KB/回
- ストリーミング読み取りによるメモリ効率化

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

- 外部ディレクトリへのアクセスは明示的な権限確認が必要
- バイナリファイルの読み取りは拒否
- ファイルパスのサニタイゼーション（相対パス→絶対パス変換）

## 備考

- 画像ファイルはBase64エンコードされてattachmentsとして返却される
- PDFファイルも同様にBase64エンコードで返却される
- 指示プロンプト（InstructionPrompt）がある場合、出力に`<system-reminder>`として追加される

---

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

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

### 推奨読解順序

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

ツールの入出力パラメータとコンテキスト構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | tool.ts | `packages/opencode/src/tool/tool.ts` | Tool.Context型定義、Tool.Info型定義を確認 |

**読解のコツ**: `Tool.define`関数がツール定義のエントリーポイント。パラメータのZodスキーマ、execute関数のシグネチャを確認する。

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

Read ツールの本体実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | read.ts | `packages/opencode/src/tool/read.ts` | ツール定義とexecute関数の全体フロー |

**主要処理フロー**:
1. **21-27行目**: ツール定義とパラメータスキーマ
2. **29-36行目**: パラメータ検証とパス正規化
3. **40-50行目**: 外部ディレクトリチェックと権限確認
4. **52-74行目**: ファイル存在確認と類似ファイル提案
5. **76-116行目**: ディレクトリ読み取り処理
6. **121-142行目**: 画像/PDF読み取り処理
7. **144-145行目**: バイナリファイル判定とエラー
8. **147-231行目**: テキストファイル読み取り処理

#### Step 3: バイナリ判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | read.ts | `packages/opencode/src/tool/read.ts` | isBinaryFile関数（235-293行目） |

**主要処理フロー**:
- **238-270行目**: 拡張子による即時判定
- **274-289行目**: バイトサンプリングによる判定

#### Step 4: 依存モジュールを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | external-directory.ts | `packages/opencode/src/tool/external-directory.ts` | 外部ディレクトリアクセス制御 |
| 4-2 | filesystem.ts | `packages/opencode/src/util/filesystem.ts` | ファイルシステムユーティリティ |

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

```
ReadTool.execute
    │
    ├─ assertExternalDirectory (権限チェック)
    │      └─ ctx.ask (権限要求)
    │
    ├─ ctx.ask (読み取り権限要求)
    │
    ├─ Filesystem.stat (ファイル状態取得)
    │
    ├─ Filesystem.mimeType (MIME判定)
    │
    ├─ isBinaryFile (バイナリ判定)
    │
    ├─ InstructionPrompt.resolve (指示プロンプト解決)
    │
    ├─ LSP.touchFile (LSP通知)
    │
    └─ FileTime.read (読み取り時刻記録)
```

### データフロー図

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

filePath ─────────────────▶ パス正規化
                                │
offset/limit ─────────────────▶│
                                ▼
                           ファイル種別判定
                                │
                    ┌───────────┼───────────┐
                    ▼           ▼           ▼
               ディレクトリ   画像/PDF    テキスト
                    │           │           │
                    ▼           ▼           ▼
               エントリ    Base64エン    行番号付き
               一覧取得    コード        読み取り
                    │           │           │
                    └───────────┼───────────┘
                                ▼
                           結果返却 ─────────▶ title
                                              output
                                              metadata
                                              attachments
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| read.ts | `packages/opencode/src/tool/read.ts` | ソース | Read ツール本体 |
| read.txt | `packages/opencode/src/tool/read.txt` | テンプレート | ツール説明文 |
| tool.ts | `packages/opencode/src/tool/tool.ts` | ソース | ツール基盤定義 |
| external-directory.ts | `packages/opencode/src/tool/external-directory.ts` | ソース | 外部ディレクトリアクセス制御 |
| truncation.ts | `packages/opencode/src/tool/truncation.ts` | ソース | 出力切り詰め処理 |
| filesystem.ts | `packages/opencode/src/util/filesystem.ts` | ソース | ファイルシステムユーティリティ |
| index.ts | `packages/opencode/src/lsp/index.ts` | ソース | LSP連携 |
| time.ts | `packages/opencode/src/file/time.ts` | ソース | ファイル時刻管理 |
| instruction.ts | `packages/opencode/src/session/instruction.ts` | ソース | 指示プロンプト管理 |
