# 通知設計書 1-bgnotify - コマンド完了通知（成功）

## 概要

本ドキュメントは、Oh My Zshのbgnotifyプラグインにおけるコマンド正常完了時の通知機能について、その設計仕様を定義するものである。

### 本通知の処理概要

bgnotifyプラグインは、ターミナルがバックグラウンドにある状態で長時間実行されたコマンドが正常に完了した際に、デスクトップ通知を表示する機能を提供する。

**業務上の目的・背景**：開発者やシステム管理者がビルド、テスト、デプロイなどの長時間実行コマンドを実行し、その間に別の作業を行っている場合、コマンド完了を見逃すことがある。本通知機能により、ターミナルを監視し続けなくても、コマンドの完了を即座に把握でき、作業効率が向上する。

**通知の送信タイミング**：コマンドの実行が完了し、かつ以下の条件をすべて満たした場合に通知が送信される：(1) 実行時間がbgnotify_threshold（デフォルト5秒）以上、(2) ターミナルアプリケーションがフォアグラウンドにない、(3) コマンドの終了ステータスが0（成功）。

**通知の受信者**：コマンドを実行したユーザー自身。デスクトップ通知システムを通じて、現在ログインしているユーザーに通知が配信される。

**通知内容の概要**：通知にはタイトルとして「#win (took Xs)」（Xは実行時間）、メッセージとして実行されたコマンド文字列が含まれる。

**期待されるアクション**：受信者は通知を確認し、必要に応じてターミナルに戻って次のコマンドを実行したり、出力結果を確認したりする。

## 通知種別

デスクトップ通知（OS固有の通知システム）

対応システム：
- macOS: terminal-notifier, growlnotify
- Linux: notify-send
- KDE: kdialog
- Windows (Cygwin): notifu

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（コマンド完了時に即座に実行） |
| 優先度 | 中 |
| リトライ | 無し |

### 送信先決定ロジック

ローカルユーザーのデスクトップセッションに対して通知を送信する。SSHセッション経由の場合は通知をスキップする（`$SSH_CLIENT`または`$SSH_TTY`が設定されている場合は処理を行わない）。

## 通知テンプレート

### デスクトップ通知の場合

| 項目 | 内容 |
|-----|------|
| タイトル | `#win (took {elapsed})` |
| メッセージ | `{command}` |
| アイコン | カスタム指定可能（デフォルトなし） |

### 本文テンプレート

```
タイトル: #win (took 1m 30s)
メッセージ: npm run build
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | - | - | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| elapsed | 実行時間（人間が読みやすい形式） | EPOCHSECONDS計算結果 | Yes |
| command | 実行されたコマンド | preexecフックで取得 | Yes |
| exit_status | 終了ステータス | precmdフックで取得 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| シェルフック | precmd（プロンプト表示直前） | exit_status == 0 かつ elapsed >= threshold かつ ターミナルがバックグラウンド | コマンド正常完了時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| SSH接続時 | SSH_CLIENTまたはSSH_TTYが設定されている場合 |
| 非インタラクティブシェル | 対話モードでない場合 |
| 実行時間がしきい値未満 | elapsed < bgnotify_threshold（デフォルト5秒） |
| ターミナルがフォアグラウンド | 現在アクティブなアプリがターミナルの場合 |
| コマンド失敗時 | exit_status != 0（別の通知として処理） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[preexec: コマンド実行開始] --> B[タイムスタンプ記録]
    B --> C[コマンド実行]
    C --> D[precmd: コマンド完了]
    D --> E{タイムスタンプ有効?}
    E -->|No| F[終了]
    E -->|Yes| G{実行時間 >= しきい値?}
    G -->|No| F
    G -->|Yes| H{ターミナルがバックグラウンド?}
    H -->|No| F
    H -->|Yes| I{exit_status == 0?}
    I -->|No| J[失敗通知へ]
    I -->|Yes| K[成功通知送信]
    K --> L[bgnotify関数呼び出し]
    L --> M{通知コマンド選択}
    M -->|macOS| N[terminal-notifier]
    M -->|Linux| O[notify-send]
    M -->|KDE| P[kdialog]
    M -->|Windows| Q[notifu]
    N --> F
    O --> F
    P --> F
    Q --> F
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はデータベースを使用しない。シェル変数のみで状態管理を行う。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | - | データベース不使用 |

### シェル変数一覧

| 変数名 | 用途 | デフォルト値 |
|--------|------|-------------|
| bgnotify_timestamp | コマンド開始時刻 | EPOCHSECONDS |
| bgnotify_lastcmd | 最後に実行したコマンド | preexec引数 |
| bgnotify_threshold | 通知しきい値（秒） | 5 |
| bgnotify_bell | ベル音有効化フラグ | true |
| bgnotify_termid | ターミナルID（キャッシュ） | 起動時に取得 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 通知コマンド未インストール | terminal-notifier等が存在しない | 通知をスキップ（サイレント失敗） |
| アプリID取得失敗 | lsappinfo/xprop等が失敗 | EPOCHSECONDS代替値を返す |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（24時間対応）

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

- 通知にはユーザーが実行したコマンド文字列が含まれるため、機密性の高いコマンド（パスワード含むコマンド等）は通知に表示される可能性がある
- ローカル通知のみであり、ネットワーク経由での送信は行われない
- SSH接続時は自動的に無効化されるため、リモートセッションでの誤動作を防止

## 備考

- bgnotify_formatted関数はユーザーがオーバーライド可能であり、カスタム通知形式を定義できる
- bgnotify_extraargs変数で各通知コマンドに追加引数を渡すことが可能

---

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

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

### 推奨読解順序

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

まず、プラグインで使用されるシェル変数とその役割を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | 135-144行目のデフォルト値設定でシェル変数の構造を把握 |

**読解のコツ**: zshのパラメータ展開 `${var:-default}` は変数が未設定の場合にデフォルト値を使用する記法。

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

処理の起点となるフック登録を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | 36-38行目のadd-zsh-hookでpreexec/precmdフック登録を確認 |

**主要処理フロー**:
1. **36行目**: `autoload -Uz add-zsh-hook` - フック登録関数のロード
2. **37行目**: `add-zsh-hook preexec bgnotify_begin` - コマンド実行前フック
3. **38行目**: `add-zsh-hook precmd bgnotify_end` - プロンプト表示前フック

#### Step 3: コマンド開始処理を理解する

preexecフックで呼ばれるbgnotify_begin関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | 13-16行目のbgnotify_begin関数でタイムスタンプとコマンドの記録方法を理解 |

**主要処理フロー**:
- **14行目**: `bgnotify_timestamp=$EPOCHSECONDS` - 開始時刻記録
- **15行目**: `bgnotify_lastcmd="${1:-$2}"` - 実行コマンド記録

#### Step 4: コマンド完了処理を理解する

precmdフックで呼ばれるbgnotify_end関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | 18-34行目のbgnotify_end関数で条件判定と通知呼び出しの流れを理解 |

**主要処理フロー**:
- **20行目**: `local exit_status=$?` - 終了ステータス取得
- **21行目**: `local elapsed=$(( EPOCHSECONDS - bgnotify_timestamp ))` - 実行時間計算
- **24行目**: タイムスタンプ有効性チェック
- **25行目**: しきい値チェック
- **28行目**: フォアグラウンドチェック
- **30行目**: `bgnotify_formatted` 呼び出し

#### Step 5: 通知フォーマット処理を理解する

実際の通知メッセージ生成を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | 44-60行目のbgnotify_formatted関数で通知メッセージの生成方法を理解 |

**主要処理フロー**:
- **50-52行目**: 実行時間の人間可読形式への変換
- **54行目**: ベル音の出力（オプション）
- **55-59行目**: exit_statusによる分岐（成功: #win、失敗: #fail）

#### Step 6: 通知送信処理を理解する

OS固有の通知コマンド呼び出しを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | 117-133行目のbgnotify関数で各OS向け通知コマンドの選択と実行を理解 |

**主要処理フロー**:
- **121-123行目**: macOS (terminal-notifier)
- **124-125行目**: macOS (growlnotify)
- **126-127行目**: Linux (notify-send)
- **128-129行目**: KDE (kdialog)
- **130-131行目**: Windows/Cygwin (notifu)

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

```
[シェル起動]
    │
    ├─ プラグインロード (bgnotify.plugin.zsh)
    │      ├─ zmodload zsh/datetime (8行目)
    │      ├─ add-zsh-hook preexec bgnotify_begin (37行目)
    │      ├─ add-zsh-hook precmd bgnotify_end (38行目)
    │      └─ bgnotify_termid 初期化 (144行目)
    │
[コマンド実行開始]
    │
    ├─ bgnotify_begin (preexecフック)
    │      └─ タイムスタンプ・コマンド記録
    │
[コマンド実行完了]
    │
    └─ bgnotify_end (precmdフック)
           ├─ 条件チェック
           └─ bgnotify_formatted
                  ├─ 時間フォーマット
                  ├─ ベル音出力 (オプション)
                  └─ bgnotify
                         └─ OS固有通知コマンド
```

### データフロー図

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

EPOCHSECONDS ─────────▶ bgnotify_begin ───────────▶ bgnotify_timestamp
preexec引数 ──────────▶                           ▶ bgnotify_lastcmd

                        bgnotify_end
$? (exit_status) ─────▶ ├─ 実行時間計算            ▶ elapsed
bgnotify_timestamp ───▶ ├─ 条件判定
bgnotify_lastcmd ─────▶ └─ bgnotify_formatted ────▶ 通知タイトル/メッセージ
                                │
                                └─ bgnotify ──────▶ デスクトップ通知
                                       │
                                       └──────────▶ ベル音 (\a)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bgnotify.plugin.zsh | `plugins/bgnotify/bgnotify.plugin.zsh` | ソース | メインプラグインファイル、全ての通知ロジックを含む |
