knownothing114/dsh-notify

knownothing114/dsh-notify

当 dsh 需要你注意时发出桌面通知——权限确认、提问、计划审批、回合完成、目标、出错、工作流——并提供设置页「通知」选项卡,改动即时生效。

通知与集成

dsh-notify

English | 简体中文 | 日本語

dsh(DeepSeek Harness)向けプラグイン。dsh がユーザーの注意を必要とするとき、デスクトップ通知でお知らせします。

dsh 自体は「ユーザーの介入が必要」な場面で何の合図も出しません。権限確認(承認)待ち、 ask_user_question による質問、プラン(計画)の承認待ち、ターン/セッション完了、 ゴールの完了・ブロック、エラー発生、ワークフロー終了 —— ターミナルやブラウザのタブが バックグラウンドにあると、こうしたタイミングを見逃しがちです。本プラグインは dsh ホストの イベントバスを監視し、これらの瞬間にネイティブのデスクトップ通知(macOS / Linux のシステム通知、 Windows のポップアップ、ターミナルベル、または独自コマンド)を即座に表示します。

本プラグインは純粋なオブザーバーです。すべてのリスナーは受動的で、特に approval/request リスナーは通知するだけで、ユーザーに代わって判断することは決してなく、 常に next() でリクエストを転送します。承認チェーンの動作は本プラグイン未導入時と完全に同じです。

機能

トリガー発火タイミングデフォルト
approval権限確認リクエスト(サンドボックス昇格、承認が必要な操作など)オン
questionask_user_question による質問 / exit_plan_mode によるプラン承認待ちオン
turnCompleteターン完了(エージェントの応答が終わり、次の入力を待っている状態)オン
goalゴールの完了 / ブロックオン
errorセッションのエラー発生オン
workflowtool_workflow の実行終了オン

通知チャンネル(channel):

  • auto(デフォルト): macOS → osascript システム通知 / Windows → PowerShell ポップアップ / その他 → notify-send
  • osascript / notify-send / powershell: チャンネルを明示指定
  • bell: ターミナルベル(\x07)— 依存ゼロのフォールバック
  • custom: 独自コマンドテンプレートを実行(プレースホルダー {title} {body} {app})
  • none: 無効

ランタイム依存は @deepseek-ai の 2 パッケージのみ(settings と schemastery)。任意の profile(web / headless / カスタム)で動作します。

すべてのオプションは Web の 設定 → 通知 タブからも変更できます(後述の「設定タブ(Web)」参照)。 変更は設定ファイルに書き込まれ、即座に反映されます(再起動不要)。

インストール

web profile を例に説明します(他の profile も同様):

# 1. プラグインを profile の依存関係に追加します。
#    ローカルディレクトリは pnpm が node_modules にリンクします。git URL や
#    公開済みの npm パッケージ名でも構いません。
dsh plugin --profile web add /path/to/dsh-notify
#    または本リポジトリから:
dsh plugin --profile web add git+https://github.com/knownothing114/dsh-notify.git
#    または(npm 公開後): dsh plugin --profile web add dsh-notify

このコマンドは依存関係の追加とバンドル登録を自動で行います。profile マニフェストの dsh.profile.bundles に dsh-notify が含まれているか確認し、含まれていない場合は手動で追加してください:

// ~/.dsh/profiles/web/package.json
{
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "dsh-notify"          // ← この行を追加
      ]
    }
  }
}
# 2. dsh web を再起動します。プラグインは起動時に読み込まれます(HMR は設定のみホットリロード)。

設定

初期状態で妥当なデフォルト値が組み込まれているため、通常は変更不要です。調整したい場合は、 profile の cordis.patch.yml(または --patch オーバーレイ)で行 id dsh-notify を指定して 上書きします。上書きは該当行の config を丸ごと置き換えるため、プラグイン側でデフォルトと 深いマージを行います。変更したいキーだけを書けば OK です:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: dsh-notify
  config:
    channel: auto        # auto | osascript | notify-send | powershell | bell | custom | none
    appName: dsh         # 通知に表示される送信元名(custom テンプレートの {app})
    sound: true          # macOS で通知音を鳴らす
    minIntervalMs: 3000  # 通知間の最小間隔(連投ガード)
    rootsOnly: true      # ルートセッションのみ通知(サブエージェント / バックグラウンド子タスクを無視)
    verbose: false       # 各通知を dsh ログにも出力
    customCommand: ""    # channel が custom のときのコマンドテンプレート(例):
                         #   terminal-notifier -message {body} -title {title}
    triggers:
      approval: true
      question: true
      turnComplete: true
      goal: true
      error: true
      workflow: true
    enabled: true        # マスタースイッチ

設定タブ(Web の「通知」タブ)

web profile では、プラグインが 設定 に専用の 「通知」 タブを登録します。上記の 設定項目をすべて表示し、フォームから変更できます(保存 / 破棄 / 全体の「初期値に戻す」):

  • マスタースイッチ、通知チャンネル、アプリ名、通知音、最小通知間隔、ルートセッションのみ、ログ出力、カスタムコマンド
  • 6 つのトリガースイッチ

設定の優先順位(高い方が有効): 設定ファイル($DSH_HOME/settings.yaml。タブが書き込み、 ホット適用)→ profile パッチ(cordis.patch.yml の config:)→ 組み込みデフォルト値。 ホストプラグインは通知のたびに設定をリアルタイムで読み取るため、タブでの変更は即座に反映されます。

ブラウザ側は dist/client.js(dsh クライアントモジュール形式のプリビルドバンドル。ホストが /plugins/dsh-notify/client.js として配信)で実装され、ホスト側が notify 設定名前空間を 登録します。プラグインパッケージの初回インストール・アップグレード時は dsh web の再起動が 必要です。以後のタブ内の変更に再起動は不要です。

注記: dsh の API プロキシはデフォルトでホワイトリストに載った設定名前空間だけを Web UI に 公開します(モデルプロバイダー + 明示的な許可リスト)。そのため本プラグインはプロキシの settings ハンドラをラップし、notify 名前空間を標準の settings RPC で読み書きできるように します。他の名前空間はコアのホワイトリスト動作のままです。

仕組み(イベントマッピング)

トリガー監視するイベント
approvalホスト側の approval/request ウォーターフォール(受動的: return next() で転送し、判定には関与しません)
question / プラン承認session/event 内の tool/call(ツール名 ask_user_question / exit_plan_mode)。質問文はツール引数から抽出
turnCompletesession/event 内の turn/end(reason.kind === "completed")
goalgoal/changed(操作 complete / block)。本文にゴールの内容を含む
erroragent/error
workflowsession/event 内の tool-workflow/run-end(completed 以外の停止理由でも通知)

すべてのリスナーはルートコンテキストに登録されます。dsh のスコープルーティング規則により すべてのエージェント / セッションイベントを受信でき、rootsOnly は ctx.agents.roots() で サブエージェントのノイズを除外します。通知は分離された spawn プロセスで送信されるため、 エージェントループをブロックすることはなく、失敗はログに記録されるだけです。

アンインストール

dsh plugin --profile web remove dsh-notify
# さらに ~/.dsh/profiles/web/package.json の bundles から "dsh-notify" を削除し、再起動

よくある質問

  • 通知が出ない? 解決された channel が OS と合っているか確認してください。macOS なら channel: osascript を明示(verbose: true で dsh ログに各通知が出力されます)。 Linux では notify-send(libnotify)が必要です。おやすみモードや通知権限も確認してください。
  • 通知が多すぎる? minIntervalMs を増やすか、不要な triggers をオフにしてください。
  • サブエージェントがノイズになる? rootsOnly: true のままにしてください。
  • 設定変更が反映されない? cordis.patch.yml の変更は HMR でホットリロードされます。 プラグインの追加・削除や package.json の bundles 変更は dsh web の再起動が必要です。

開発

cd dsh-notify
npm install   # @deepseek-ai/dsh-settings と @deepseek-ai/schemastery をインストール
npm test      # node --test: 純関数のユニットテスト + apply() のスモークテスト + クライアントフォームテスト(30 ケース)

プロジェクト構成

├── lib/index.mjs            ホストプラグイン(イベントリスナー、設定名前空間、apiProxy 公開ラッパー)
├── dist/client.js           ブラウザバンドル(設定 → 通知 タブ)。/plugins/dsh-notify/client.js として配信
├── cordis.patch.yml         bundle パッチ(プラグイン行のマウント)
├── docs/
│   ├── README.zh-CN.md      简体中文文档
│   ├── README.ja.md         日本語ドキュメント
│   └── third-party-settings-namespace-exposure.md   開発メモ: サードパーティ設定名前空間の Web UI への公開方法
├── test/                    node --test テストスイート(ユニット / レンダー / インタラクション / 統合)
└── package.json             プラグインマニフェスト(exports、dsh.bundle / dsh.client 宣言)

ライセンス

MIT