前言¶
在 macOS 上給 DeepSeek Harness(DSH)加通知,社區裏常見的做法是開一個外部進程跑 osascript -e 'display notification ...'。這條路在新版 macOS 上有兩個實打實的問題:通知實際歸屬發起 osascript 的父進程,與 DSH 的簽名對不上,系統可能一聲不響把通知丟掉;就算顯示出來,圖標也不是 DSH,點擊也回不到會話。
dsh-macos-notify 換的思路是:讓 DSH 應用自己的 GUI 進程來發通知。插件由 Chanceux-L 維護,屬於客戶端類插件,通過 DSH 的雙半(宿主 + 客戶端)結構實現,目標是通知歸屬 DSH 自己的名字和圖標,並且點一下就能跳回對應會話。
架構¶
插件分宿主半邊和客戶端半邊,中間靠 Web 接口輪詢連接:
┌─ 宿主半邊 index.js(Node,inject: ['sessions','webServer'])──────────┐
│ 監聽頂級會話事件:turn/end(completed/error)、ask_user_question、 │
│ approval/asked │
│ → 通知寫入內存隊列(上限 100 條) │
│ → ctx.webServer.register 暴露: │
│ GET /macos-notify/now → 當前最新通知 id │
│ GET /macos-notify/pending?since=N → 增量拉取隊列 │
│ 子代理 / fork / team 成員會話帶 parentSession / delegationDepth 頭, │
│ 直接跳過——只有用戶可見的頂級會話才通知。 │
└──────────────────────────────────────────────────────────────────────┘
│ 輪詢(2 秒)
┌─ 客戶端半邊 client.js(Web GUI 頁面,inject: ['uiWorkspace'])───────┐
│ window.__ModuleLoader__.load 註冊,每 2s 拉取隊列 │
│ → new Notification() 發出——Electron 渲染進程中即 DSH 應用自身的 │
│ macOS 原生通知 │
│ → onclick 調 uiWorkspace.openSession(sessionId) 跳轉會話 + │
│ window.focus() │
│ Notification 不可用/被拒時回退:頁內 AudioContext 提示音 + 標題閃爍 │
└──────────────────────────────────────────────────────────────────────┘
│ 頁面關閉(超過 clientQuietMs 無輪詢)
┌─ 宿主回退通道 ──────────────────────────────────────────────────────┐
│ afplay 播 /System/Library/Sounds 系統音效 │
│ 阻塞輸入(提問/審批)時額外 open -a "DeepSeek Harness" 拉起窗口 │
└──────────────────────────────────────────────────────────────────────┘
宿主半邊負責監聽會話事件並維護隊列,客戶端半邊在渲染進程裏執行 new Notification(),這正是通知能歸屬 DSH 簽名的原因。子代理、fork 出來的會話和 team 成員會話會被跳過,只有用戶直接看到事件的頂級會話才通知。
核心功能¶
- 回合完成 / 失敗通知:
turn/end時按reason.kind分派,失敗附錯誤消息(截斷至 120 字符),並顯示回合耗時。 - 提問通知:Agent 調用
ask_user_question時通知第一個問題(含 header),多個問題時顯示(+N more)。 - 審批通知:
approval/asked時通知工具名與原因。 - 點擊跳轉會話:通知
onclick→uiWorkspace.openSession(sessionId)+window.focus()。 - 無 GUI 回退:頁面關閉超過
clientQuietMs未輪詢時,宿主直接afplay播系統音效;提問/審批還會open -a拉起 DSH 窗口。 - 智能過濾:跳過子代理、fork、team 成員會話;短於
minTurnSeconds的回合不通知;超過 10 分鐘的過期通知不補發。
全部行爲都可通過配置關閉或調整,見下文配置項。
安裝與啓用¶
推薦用 DSH CLI 以 github: 源碼形式安裝:
dsh plugin --profile web add github:Chanceux-L/dsh-macos-notify
也可以手動把目錄鏈接或克隆到 profile 的 node_modules 下:
git clone https://github.com/Chanceux-L/dsh-macos-notify \
~/.dsh/profiles/desktop/node_modules/dsh-macos-notify
# 或者開發時用符號鏈接:
ln -s /path/to/dsh-macos-notify ~/.dsh/profiles/desktop/node_modules/dsh-macos-notify
插件通過 cordis.patch.yml 以 insert 方式註冊(id: macos-notify),不需要手動改配置文件。重啓 DSH 後,第一次發通知會觸發系統的通知權限彈窗,允許即可。
配置項¶
在 profile patch 的 config: 下覆蓋,默認值定義在 index.js 的 DEFAULTS。
| 鍵 | 類型 | 默認 | 說明 |
|---|---|---|---|
onCompleted |
boolean | true |
回合完成時通知 |
onError |
boolean | true |
回合失敗時通知 |
onQuestion |
boolean | true |
Agent 提問時通知 |
onApproval |
boolean | true |
需要工具審批時通知 |
minTurnSeconds |
number | 5 |
回合短於該秒數不通知 |
titlePrefix |
string | "DSH" |
通知標題前綴,格式 前綴 · 會話標題 |
soundCompleted |
string | "Glass" |
宿主回退音效(/System/Library/Sounds 下的文件名,不帶 .aiff;'' 關閉) |
soundQuestion |
string | "Ping" |
提問回退音效 |
soundApproval |
string | "Funk" |
審批迴退音效 |
soundError |
string | "Basso" |
失敗回退音效 |
activateOnInput |
boolean | true |
無 GUI 且提問/審批阻塞時 open -a 拉起 DSH 窗口 |
clientQuietMs |
number | 15000 |
客戶端超過該毫秒未輪詢,宿主啓用回退通道 |
debug |
boolean | false |
追加投遞診斷到 ~/.dsh/macos-notify.log |
配置示例:
- insert:
- id: macos-notify
name: 'dsh-macos-notify'
config:
titlePrefix: DSH
minTurnSeconds: 10
soundCompleted: Glass
典型用法¶
按上面的命令裝好並重啓 DSH 後,最小可用配置就是默認值,不需要額外寫 patch。下面給出常見調整的示例。
想讓快速連續的回合別刷屏,把閾值抬高:
- insert:
- id: macos-notify
config:
minTurnSeconds: 30
頁面常駐、不需要宿主回退音效時,可以關掉對應開關:
- insert:
- id: macos-notify
config:
onCompleted: true
onError: true
onQuestion: true
onApproval: true
clientQuietMs: 600000
activateOnInput: false
排障時打開 debug,投遞診斷會追加到 ~/.dsh/macos-notify.log:
- insert:
- id: macos-notify
config:
debug: true
與現有插件對比¶
| dsh-macos-notify(本插件) | CrombastiC/dsh-macos-notify | jypjypjypjyp/dsh-notifier | dsh-complete-notify | |
|---|---|---|---|---|
| 通知通道 | 應用自身 GUI 進程(Web Notification) | 外部 osascript 進程 |
外部 osascript 進程 |
外部 osascript 進程 |
| macOS 簽名校驗 | 通過,歸屬 DSH 自身 | 可能被靜默丟棄 | 可能被靜默丟棄 | 可能被靜默丟棄 |
| 通知圖標歸屬 | DeepSeek Harness | 其他應用身份 | 其他應用身份 | 其他應用身份 |
| 點擊跳轉會話 | ✅ uiWorkspace.openSession |
❌ | ❌ | ❌ |
| 頁面關閉回退 | ✅ afplay + open -a | 部分 | 部分 | 部分 |
| 提問/審批/失敗分類通知 | ✅ | 部分 | 部分 | 部分 |
適用場景與注意¶
適合在 macOS 上日常用 DSH 圖形界面、希望回合結束、Agent 提問或需要審批時收到可點擊通知的開發者。插件本身只做通知投遞,不改變會話邏輯。
幾點需要注意:
- 插件以當前 dsh 進程的權限運行,安裝前應先檢查源碼與許可證(本倉庫爲 MIT)。
- 插件依賴 Electron 渲染進程裏的 Web Notification API,需要 macOS 允許 DSH 發通知;首次觸發會彈系統權限框。
- Dock 圖標數字角標需要 DSH 官方在 Electron 主進程暴露
app.dock.setBadgeCountIPC,插件層無法實現。 - 跨工作區會話跳轉尚未實現,
uiWorkspace.openSession當前只支持當前工作區內的導航。 - 宿主回退音效依賴
/System/Library/Sounds下的系統音效文件。
小結¶
dsh-macos-notify 解決的問題很具體:讓 DSH 的通知在 macOS 上真正歸屬於應用自己,並且能點回會話。它用雙半插件結構把事件監聽、隊列和原生通知串起來,配套了過濾、回退和全套配置。如果需要在 macOS 上給 DSH 加通知,這是一個可以直接落地的方案。
目錄頁:https://www.skillhub.cn/plugins/Chanceux-L/dsh-macos-notify
GitHub:https://github.com/Chanceux-L/dsh-macos-notify