# 機能設計書 48-設定ファイル管理

## 概要

本ドキュメントは、OpenCodeにおける設定ファイル管理機能の設計を記述する。opencode.json/opencode.jsonc形式の設定ファイルを階層的に読み込み、マージして適用する機能を提供する。

### 本機能の処理概要

設定ファイル管理機能は、複数の設定ソース（リモート、グローバル、プロジェクト、.opcode ディレクトリ、インライン）から設定を読み込み、優先順位に従ってマージする。JSONC（コメント付きJSON）形式をサポートし、環境変数展開やファイル参照機能も提供する。また、カスタムコマンド、エージェント、プラグインの自動検出・読み込みも行う。

**業務上の目的・背景**：OpenCodeは多様な環境（個人開発、チーム開発、エンタープライズ）で使用されるため、柔軟な設定管理が必要となる。階層的な設定システムにより、グローバル設定をベースにプロジェクト固有の設定で上書きでき、開発者ごとのカスタマイズも可能になる。また、設定ファイルをバージョン管理することで、チーム間での設定共有も容易になる。

**機能の利用シーン**：
- プロジェクト固有のモデル・エージェント設定
- カスタムコマンドの定義
- MCP（Model Context Protocol）サーバーの設定
- フォーマッター・LSPの設定
- 権限ルールの設定

**主要な処理内容**：
1. 設定ファイルの検出と読み込み（複数ソース）
2. JSONC形式のパース（コメント、末尾カンマ対応）
3. 環境変数展開（{env:VAR_NAME}形式）
4. ファイル参照展開（{file:path}形式）
5. 設定のマージ（優先順位に従う）
6. カスタムコマンド、エージェント、プラグインの検出

**関連システム・外部連携**：
- jsonc-parser: JSONC形式のパース
- Zod: スキーマ検証
- Filesystem: ファイル検出・読み込み

**権限による制御**：OPENCODE_DISABLE_PROJECT_CONFIG でプロジェクト設定を無効化可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ホーム画面 | 補助機能 | ユーザー設定に基づくホームディレクトリパスの取得 |
| 4 | レイアウト | 補助機能 | 設定ダイアログの表示と管理 |
| 18 | 設定 | 主機能 | ワークスペース設定の管理 |

## 機能種別

設定管理 / データ読み込み

## 入力仕様

### 設定ファイルパス（優先順位：低→高）

1. リモート設定（.well-known/opencode）
2. グローバル設定（~/.config/opencode/opencode.json{,c}）
3. カスタム設定（OPENCODE_CONFIG環境変数）
4. プロジェクト設定（opencode.json{,c} - findUp検索）
5. .opcode ディレクトリ設定
6. インライン設定（OPENCODE_CONFIG_CONTENT環境変数）
7. 管理設定（エンタープライズ用、最高優先度）

### 設定スキーマ（主要項目）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| $schema | string | JSONスキーマ参照 |
| model | string | デフォルトモデル |
| agent | object | エージェント設定 |
| mcp | object | MCPサーバー設定 |
| permission | object | 権限設定 |
| formatter | object/false | フォーマッター設定 |
| lsp | object/false | LSP設定 |
| keybinds | object | キーバインド設定 |

### 入力データソース

- ファイルシステム
- 環境変数
- リモートURL

## 出力仕様

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

マージされた設定オブジェクト。主要フィールドは入力スキーマと同一。

### 出力先

- メモリ（Instance.state経由でキャッシュ）

## 処理フロー

### 処理シーケンス

```
1. 設定読み込み開始（Config.state）
   ├─ リモート設定取得（.well-known/opencode）
   ├─ グローバル設定読み込み
   ├─ カスタム設定読み込み（OPENCODE_CONFIG）
   └─ プロジェクト設定読み込み（findUp）

2. .opencode ディレクトリ処理
   ├─ ディレクトリ一覧構築
   ├─ 依存関係インストール（必要時）
   ├─ コマンド読み込み（commands/*.md）
   ├─ エージェント読み込み（agents/*.md）
   └─ プラグイン読み込み（plugins/*.{ts,js}）

3. インライン設定適用
   └─ OPENCODE_CONFIG_CONTENT のマージ

4. 管理設定適用（エンタープライズ）
   └─ /Library/Application Support/opencode 等

5. 後処理
   ├─ mode → agent へのマイグレーション
   ├─ tools → permission へのマイグレーション
   └─ プラグインの重複排除
```

### フローチャート

```mermaid
flowchart TD
    A[Config.state開始] --> B[リモート設定取得]
    B --> C[グローバル設定読み込み]
    C --> D{OPENCODE_CONFIG設定?}
    D -->|Yes| E[カスタム設定読み込み]
    D -->|No| F[プロジェクト設定読み込み]
    E --> F
    F --> G[.opcode ディレクトリ処理]
    G --> H[コマンド/エージェント/プラグイン読み込み]
    H --> I{OPENCODE_CONFIG_CONTENT設定?}
    I -->|Yes| J[インライン設定マージ]
    I -->|No| K[管理設定読み込み]
    J --> K
    K --> L[マイグレーション処理]
    L --> M[プラグイン重複排除]
    M --> N[設定返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-48-01 | 優先順位 | 後から読み込まれた設定が優先 | 全マージ時 |
| BR-48-02 | 配列連結 | plugin, instructions は連結（置換ではない） | マージ時 |
| BR-48-03 | スキーマ自動追加 | $schema がない場合は自動追加 | ファイル読み込み時 |
| BR-48-04 | 環境変数展開 | {env:VAR_NAME} を展開 | パース時 |
| BR-48-05 | ファイル参照展開 | {file:path} を内容に展開 | パース時 |
| BR-48-06 | プロジェクト設定無効化 | OPENCODE_DISABLE_PROJECT_CONFIG で無効 | 読み込み時 |

### 計算ロジック

管理設定ディレクトリ：
```typescript
switch (process.platform) {
  case "darwin": return "/Library/Application Support/opencode"
  case "win32": return path.join(process.env.ProgramData || "C:\\ProgramData", "opencode")
  default: return "/etc/opencode"
}
```

プラグイン名抽出：
```typescript
function getPluginName(plugin: string): string {
  if (plugin.startsWith("file://")) {
    return path.parse(new URL(plugin).pathname).name
  }
  const lastAt = plugin.lastIndexOf("@")
  if (lastAt > 0) return plugin.substring(0, lastAt)
  return plugin
}
```

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

本機能はデータベースを操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ConfigJsonError | JSONパースエラー | JSONC構文エラー | 詳細なエラーメッセージ表示 |
| ConfigInvalidError | スキーマエラー | Zod検証失敗 | issuesを含むエラー返却 |
| - | ファイル参照エラー | {file:path} のファイル不在 | InvalidError スロー |

### リトライ仕様

リトライは実装されていない。エラー発生時は例外をスロー。

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

トランザクション管理なし。設定はInstance.stateでキャッシュされ、Instance.dispose時にリセット。

## パフォーマンス要件

- 設定はインスタンス初期化時に1回だけ読み込み
- Instance.stateでキャッシュしてアクセス高速化
- 依存関係インストールは非同期で実行

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

- ファイル参照は設定ファイルからの相対パスまたは絶対パス
- 環境変数はプロセス環境から取得
- 管理設定ディレクトリはシステム管理者権限が必要

## 備考

設定ファイル検索パターン：
- opencode.json
- opencode.jsonc
- .opencode/opencode.json
- .opencode/opencode.jsonc

---

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

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

### 推奨読解順序

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

設定スキーマの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | config.ts | `packages/opencode/src/config/config.ts` | Info スキーマ（1017-1210行目）で全設定項目を確認 |
| 1-2 | config.ts | `packages/opencode/src/config/config.ts` | Agent スキーマ（685-772行目）、Permission スキーマ（634-665行目） |

**読解のコツ**: Zodスキーマのチェーンメソッド（.optional(), .describe()）と .meta({ ref: "..." }) でOpenAPI用の参照名を定義。

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

設定読み込みのメインフローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | config.ts | `packages/opencode/src/config/config.ts` | state関数（69-260行目）が設定読み込みのエントリーポイント |

**主要処理フロー**:
1. **70-102行目**: リモート設定（.well-known/opencode）の取得
2. **108-109行目**: グローバル設定のマージ
3. **111-125行目**: カスタム設定とプロジェクト設定の読み込み
4. **131-184行目**: .opencodeディレクトリの処理
5. **186-196行目**: インライン設定のマージ
6. **198-206行目**: 管理設定の読み込み

#### Step 3: ファイル読み込みを理解する

個別ファイルの読み込みとパースを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | config.ts | `packages/opencode/src/config/config.ts` | loadFile関数（1243-1251行目） |
| 3-2 | config.ts | `packages/opencode/src/config/config.ts` | load関数（1253-1345行目）- 環境変数展開、ファイル参照展開 |

**主要処理フロー**:
- **1259-1261行目**: 環境変数展開（{env:VAR_NAME}）
- **1263-1294行目**: ファイル参照展開（{file:path}）
- **1298-1320行目**: JSONC パースとエラー処理
- **1322-1338行目**: Zodスキーマ検証

#### Step 4: コマンド・エージェント読み込みを理解する

カスタムコマンドとエージェントの検出を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | config.ts | `packages/opencode/src/config/config.ts` | loadCommand関数（357-393行目） |
| 4-2 | config.ts | `packages/opencode/src/config/config.ts` | loadAgent関数（395-432行目） |
| 4-3 | config.ts | `packages/opencode/src/config/config.ts` | loadPlugin関数（470-482行目） |

**主要処理フロー**:
- **357-393行目**: commands/**/*.md からコマンド読み込み
- **395-432行目**: agents/**/*.md からエージェント読み込み
- **470-482行目**: plugins/*.{ts,js} からプラグイン読み込み

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

```
Config.get()
    │
    └─ Config.state()
           │
           ├─ Auth.all() - 認証情報取得
           │
           ├─ fetch(.well-known/opencode) - リモート設定
           │
           ├─ global() - グローバル設定
           │
           ├─ loadFile() - 各種設定ファイル
           │      │
           │      └─ load() - パースと検証
           │             ├─ 環境変数展開
           │             ├─ ファイル参照展開
           │             ├─ parseJsonc()
           │             └─ Info.safeParse()
           │
           ├─ loadCommand() - コマンド読み込み
           ├─ loadAgent() - エージェント読み込み
           └─ loadPlugin() - プラグイン読み込み
```

### データフロー図

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

リモート設定
グローバル設定
カスタム設定
プロジェクト設定
.opencode設定
インライン設定
管理設定
       │
       ▼
merge() ───▶ マージ済み設定
       │
       ▼
マイグレーション
       │
       ▼
Config.Info ───▶ キャッシュ（Instance.state）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| config.ts | `packages/opencode/src/config/config.ts` | ソース | 設定管理のメインモジュール |
| markdown.ts | `packages/opencode/src/config/markdown.ts` | ソース | Markdownフロントマターパース |
| filesystem.ts | `packages/opencode/src/util/filesystem.ts` | ソース | ファイル操作ユーティリティ |
| global.ts | `packages/opencode/src/global.ts` | ソース | グローバルパス情報 |
| instance.ts | `packages/opencode/src/project/instance.ts` | ソース | インスタンス状態管理 |
