# 機能設計書 52-デスクトップアプリ

## 概要

本ドキュメントは、OpenCodeのデスクトップアプリケーション機能について、その設計仕様を記述するものである。

### 本機能の処理概要

デスクトップアプリ機能は、Tauriフレームワークを使用したネイティブデスクトップアプリケーションを提供する機能である。macOS、Windows、Linuxの3つのプラットフォームで動作し、Web UIをネイティブウィンドウ内で実行しながら、OSネイティブの機能（ファイルダイアログ、通知、クリップボード、自動更新等）を統合する。

**業務上の目的・背景**：Webブラウザでの実行では得られないネイティブ機能へのアクセスが必要な開発者向けに、デスクトップアプリケーションを提供する。これにより、ファイルシステムへの直接アクセス、OSネイティブ通知、自動更新機能、ディープリンク対応など、より高度な統合が可能となる。

**機能の利用シーン**：
- ローカル開発環境でのAIコーディングアシスタントの利用
- プロジェクトフォルダの直接オープン
- ファイル選択ダイアログを使用したファイル添付
- macOSメニューバーからの操作
- アプリケーションの自動更新

**主要な処理内容**：
1. Tauriランタイムの初期化とWebViewの起動
2. サイドカー（OpenCode CLI）の起動とHTTPサーバーへの接続待機
3. プラットフォーム固有のAPI提供（ファイルダイアログ、通知、クリップボード等）
4. ディープリンク（opencode://）の処理
5. macOSアプリケーションメニューの構築
6. 自動更新チェックとインストール
7. WSL（Windows Subsystem for Linux）サポート

**関連システム・外部連携**：Tauri API、OS通知システム、ファイルシステム、クリップボード、自動更新サーバー

**権限による制御**：macOSのentitlements.plistによるサンドボックス設定

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | デスクトップアプリ | 主機能 | アプリケーション全体のホスト環境 |

## 機能種別

ネイティブアプリケーション統合 / UI基盤

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| directory | string | No | 起動時のプロジェクトディレクトリ | 有効なパス |
| url | string | No | ディープリンクURL | opencode://スキーム |

### 入力データソース

- コマンドライン引数
- ディープリンクURL
- ユーザー操作（メニュー、ダイアログ等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| window | WebView | ネイティブウィンドウ内のWebView |
| server | ServerReadyData | サイドカーサーバーの接続情報 |

### 出力先

- ネイティブウィンドウ（WebView表示）
- OS通知センター
- ファイルシステム

## 処理フロー

### 処理シーケンス

```
1. アプリケーション起動
   └─ Tauriランタイムの初期化

2. サイドカー起動
   └─ opencode-cliをサイドカープロセスとして起動

3. サーバー待機
   └─ awaitInitialization()でサーバー準備完了を待機

4. WebView初期化
   └─ index.tsxのrender()でSolidJSアプリをマウント

5. プラットフォームAPI提供
   └─ createPlatform()でOS固有機能をラップ

6. イベントハンドリング
   └─ ディープリンク、メニュー操作、更新チェック等
```

### フローチャート

```mermaid
flowchart TD
    A[アプリ起動] --> B[Tauriランタイム初期化]
    B --> C[サイドカー起動]
    C --> D[awaitInitialization]
    D --> E{サーバー準備完了?}
    E -->|No| F[Splash画面表示]
    F --> D
    E -->|Yes| G[ServerReadyData取得]
    G --> H[createPlatform]
    H --> I[AppInterface描画]
    I --> J[createMenu]
    J --> K[listenForDeepLinks]
    K --> L[アプリケーション稼働]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | プラットフォーム判定 | ostype()でmacOS/Windows/Linuxを判定 | 起動時 |
| BR-02 | メニュー表示 | macOSのみネイティブメニューを表示 | ostype() === "macos" |
| BR-03 | 自動更新 | UPDATER_ENABLED設定に基づき更新チェック | 起動時・メニュー操作時 |
| BR-04 | WSLサポート | Windows上でWSLパス変換を実行 | window.__OPENCODE__?.wsl === true |
| BR-05 | ストレージデバウンス | 書き込みを250msでデバウンス | ストレージ操作時 |

### 計算ロジック

- ディープリンクURL解析: `getCurrent()`および`onOpenUrl()`でURLを取得
- WSLパス変換: `commands.wslPath(path, mode)`でWindows/Linux間のパス変換

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | デスクトップアプリ自体はDBを直接操作しない（サイドカー経由） |

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

Tauriプラグインのストア（opencode.global.dat等）を使用してローカル設定を永続化。SQLiteデータベースはサイドカー側で管理。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | サーバー起動失敗 | サイドカーが起動しない | エラーメッセージ表示 |
| - | 更新チェック失敗 | ネットワークエラー等 | alertOnFailでメッセージ表示 |
| - | CLI インストール失敗 | 権限不足等 | エラーダイアログ表示 |

### リトライ仕様

- awaitInitialization: サーバー準備完了まで待機（タイムアウトなし）
- 自動更新: 失敗時は次回起動時に再試行

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

該当なし（データベース操作はサイドカー側で管理）

## パフォーマンス要件

- アプリ起動: サイドカー起動完了まで数秒（Splash画面を表示）
- ストレージ書き込み: 250msデバウンスでバッチ処理

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

- macOS: entitlements.plistでサンドボックス設定
- WSL: wslPath()でパス変換時の検証
- ディープリンク: opencode://スキームのみ受け入れ

## 備考

- パッケージ名: @opencode-ai/desktop
- Tauriバージョン: v2系
- サポートプラットフォーム: macOS, Windows, Linux (deb, rpm, dmg, nsis, app)

---

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

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

### 推奨読解順序

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

Tauriのバインディング定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | bindings.ts | `packages/desktop/src/bindings.ts` | Rust側のコマンドとTypeScript型の対応 |

**読解のコツ**:
- **7-21行目**: `commands`オブジェクトで利用可能なRustコマンドを確認
- **29-50行目**: 各コマンドの引数・戻り値の型定義（ServerReadyData, WslConfig等）

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

アプリケーションの起動フローを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | entry.tsx | `packages/desktop/src/entry.tsx` | エントリーポイント、ルーティング |
| 2-2 | index.tsx | `packages/desktop/src/index.tsx` | メインアプリケーションの初期化 |

**主要処理フロー（index.tsx）**:
1. **37-43行目**: DOMルート要素の取得とi18n初期化
2. **62-418行目**: `createPlatform()`でプラットフォームAPIを構築
3. **420-424行目**: メニュー作成とディープリンク監視開始
4. **426-489行目**: `render()`でSolidJSアプリをマウント
5. **492-509行目**: `ServerGate`コンポーネントでサーバー待機

#### Step 3: プラットフォームAPIを理解する

OS固有機能のラッパー実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.tsx | `packages/desktop/src/index.tsx` | createPlatform()関数 |

**主要処理フロー**:
- **82-96行目**: `openDirectoryPickerDialog` - フォルダ選択ダイアログ
- **98-113行目**: `openFilePickerDialog` / `saveFilePickerDialog` - ファイル選択
- **115-133行目**: `openPath` - ファイル/アプリを開く
- **143-294行目**: `storage` - 永続ストレージ（デバウンス付き）
- **296-318行目**: `checkUpdate` / `update` - 自動更新
- **320-345行目**: `notify` - OS通知

#### Step 4: メニュー構築を理解する

macOSメニューの構築を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | menu.ts | `packages/desktop/src/menu.ts` | createMenu()関数 |

**主要処理フロー**:
- **11-12行目**: macOSのみメニューを作成
- **16-62行目**: OpenCodeサブメニュー（About、更新チェック、CLI インストール等）
- **64-84行目**: Fileサブメニュー（New Session、Open Project）
- **111-156行目**: Viewサブメニュー（サイドバー、ターミナル、セッションナビ）

#### Step 5: 自動更新を理解する

アプリケーション更新機能を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | updater.ts | `packages/desktop/src/updater.ts` | runUpdater()関数 |

**主要処理フロー**:
- **9行目**: `UPDATER_ENABLED`フラグの確認
- **16-21行目**: 更新チェック
- **28-34行目**: 更新ダウンロード
- **36-50行目**: インストール確認とアプリ再起動

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

```
entry.tsx
    │
    └─ index.tsx (render)
           │
           ├─ createPlatform()
           │      ├─ Tauri Plugin APIs
           │      │    ├─ @tauri-apps/plugin-dialog
           │      │    ├─ @tauri-apps/plugin-store
           │      │    ├─ @tauri-apps/plugin-updater
           │      │    └─ ...
           │      │
           │      └─ commands (bindings.ts)
           │           └─ Rust Backend
           │
           ├─ createMenu()
           │      └─ @tauri-apps/api/menu
           │
           ├─ listenForDeepLinks()
           │      └─ @tauri-apps/plugin-deep-link
           │
           └─ ServerGate
                  └─ commands.awaitInitialization()
                         └─ サイドカー(opencode-cli)起動
```

### データフロー図

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

ディープリンク
  opencode://URL ─────▶ onOpenUrl() ─────────────────▶ window.__OPENCODE__.deepLinks
     │
ユーザー操作
  メニュークリック ───▶ trigger(commandId) ──────────▶ コマンド実行
     │
サイドカー
  opencode-cli ───────▶ awaitInitialization() ──────▶ ServerReadyData
     │                                                  │
     │                                                  ▼
     │                  ServerGate ──────────────────▶ AppInterface表示
     │
ファイル選択
  ダイアログ ─────────▶ open() / save() ─────────────▶ ファイルパス
     │
設定保存
  Store API ──────────▶ デバウンス処理 ──────────────▶ *.dat ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.tsx | `packages/desktop/src/index.tsx` | ソース | メインエントリーポイント、プラットフォームAPI |
| entry.tsx | `packages/desktop/src/entry.tsx` | ソース | ルーティングエントリー |
| bindings.ts | `packages/desktop/src/bindings.ts` | ソース | TauriコマンドのTypeScriptバインディング |
| menu.ts | `packages/desktop/src/menu.ts` | ソース | macOSメニュー構築 |
| updater.ts | `packages/desktop/src/updater.ts` | ソース | 自動更新機能 |
| cli.ts | `packages/desktop/src/cli.ts` | ソース | CLIインストール機能 |
| webview-zoom.ts | `packages/desktop/src/webview-zoom.ts` | ソース | WebViewズーム機能 |
| i18n/index.ts | `packages/desktop/src/i18n/index.ts` | ソース | 多言語対応（15言語） |
| tauri.conf.json | `packages/desktop/src-tauri/tauri.conf.json` | 設定 | Tauri設定ファイル |
| package.json | `packages/desktop/package.json` | 設定 | パッケージ定義 |
