# dsh-notifier 使用指南（从零到日常）

> 给**你自己**的指南：电脑跑 DSH，手机 IM 收通知、远程审批、随时和 agent 聊。
> 推荐路径是浏览器里的 Web 管理台；YAML 只作为高级/自动化入口，不是另一套控制台。
>
> 三个地方：**电脑**（跑 DSH）、**手机**（IM 软件）、**浏览器**（配置用）。

## 三分钟上手

| 步骤 | 做什么 | 在哪做 |
|---|---|---|
| ① 装插件 | `dsh plugin add dsh-notifier --profile <你的profile名>` | 电脑终端 |
| ② 打开管理台 | 重启 DSH，打开启动日志打印的 `http://127.0.0.1:<端口>/#token=...` 完整链接 | 浏览器 |
| ③ 走首访向导 | 选通知渠道 → 填凭证 → 点「保存并发送测试通知」 | 浏览器 |
| ④ 确认收到 | **手机当场收到测试通知 = 初始化完成** | 手机 |

之后的事（配对成员、远程审批、多 agent 路由）都不阻塞通知，什么时候要什么时候配。

---

## 第一步：装插件

```bash
dsh plugin add dsh-notifier --profile <你的profile名>
```

不用写 YAML。管理台默认启用，只监听本机 `127.0.0.1`。

## 第二步：打开 Web 管理台（唯一控制台）

重启 DSH 后，在启动日志里找 **「Web 管理台已就绪」** 一行，原样打开它打印的完整链接：

- 链接形如 `http://127.0.0.1:<端口>/#token=...`——**token 只在 `#` 后面**，不进访问日志，也只在首次启动打印这一次；
- 首选端口被占用时会自动换系统分配的空闲端口，所以**照抄日志里的链接就行，不用猜端口**；
- 链接打开后 token 静默验证、地址栏自动清掉 `#` 部分；验证失败会进入站内解锁门，可手动粘贴 token。

之后所有日常配置都在这个网页里做。token 只保存在当前浏览器会话（sessionStorage），关闭标签页即失效；丢了就删除 state 里的 `admin:token-hash` 再重启，会重新生成并再打印一次。

## 第三步：首访向导配通道（当场收到测试通知）

首次进入且没有任何已配置出站通道时，首页就是三步向导：

1. **选渠道**——挑你手机上有的：Bark（iPhone）/ Telegram / 飞书 / 钉钉 / WxPusher……（入站对话渠道不出现在向导里，以后在「通知渠道」页配）；
2. **填凭证**——每个字段旁边写着去哪拿值；带 `*` 的是必填；
3. **保存并发送测试通知**——真实发一条到你的手机。**收到 = 完成**；失败会给出原因，改完当场重试，输入不会丢。

> 注意区分两个状态：**保存成功 ≠ 通知可达**——保存只写盘（state.json，0600），测试发送才验证真实投递。向导完成以「手机收到」为准。

### 以后再加入站（让它听你说话）

入站不影响通知，什么时候配都行。「通知渠道」页找到对应入站卡片：

| 你常用 | 怎么配 |
|---|---|
| 飞书 / QQ / 钉钉 | 卡片上点 **「扫码授权」**，网页里直接出二维码，手机扫一下，网页每 2 秒自动轮询到「完成」 |
| 微信个人号 | 卡片上点 **「扫码授权」**，**用你自己的微信**扫并确认——机器人会成为你的专属好友（只和你一对一，别人加不了） |
| Telegram | 找 @BotFather 发 `/newbot` 拿 token，贴进卡片表单 |
| WxPusher | 仅当你有公网可回调（六通道唯一）才考虑 |

QQ、微信 iLink、钉钉的图片消息归一代码已接线并通过契约测试；真实平台消息形状和设备行为仍待验证，文件收发不要当作已支持能力。

### 保存后

网页保存的凭证重启一次 DSH 才并入运行时链路（连接在启动时拉起）；出站卡片会标「重启后生效」角标。但**测试发送不受此限**——它用最新合并配置当场真测，保存完立刻就能验证连通性。

## 第四步：配对成员（把你的 IM 账号连上）

配对 = 告诉插件「这个 IM 账号就是我」。做一次，后续不用再配。想要手机远程审批/对话时才需要。

> **用微信的可以跳过**——扫码授权后身份通常自动登记（专属好友，天然只有你）。没自动登记就去「成员」页手动确认。

1. 管理台进 **「成员」** 页 → **铸造配对码**（默认 10 分钟有效，码面只在弹窗显示一次，当场复制）；
2. 手机私聊你的机器人，发送：

   ```
   /pair 刚才复制的码
   ```

3. 收到 **「配对成功！你是首位成员（owner），已可使用全部功能。」** —— 完成。

三条细则：码只在**私聊**发（群里发会被拒但码不作废）；输错 5 次锁 10 分钟；
换号时旧号发 `/unpair`、新号去「成员」页再铸一枚新码。

> 全新安装时也会自动铸一枚「引导码」，码面写在 `<stateDir>/bootstrap-paircode.txt`（仅本机你自己可读，
> 终端只提示路径不打码面）；`cat` 一下即可，效果等同——但用网页铸码就不用碰文件了。
> WxPusher 订阅你的应用后，「成员」页会出现待确认身份，点「转正」等同配对。

## 第五步：日常使用

### 收通知（全自动）

任务结束/出错、agent 等审批、长任务心跳（默认 15 分钟）与卡住提醒（10 分钟无动静）。
某条会话吵：`/quiet <会话>` 闭嘴，`/unquiet <会话>` 恢复。

### 远程审批

- Telegram / 飞书：卡片上直接点 **批准 / 拒绝** 按钮；
- QQ 单聊：优先使用原生按钮；QQ 群聊控制目标 fail-closed 并回退为文本；
- 微信 iLink / WxPusher / 钉钉：按提示**回复 `1`（同意）或 `2`（拒绝）**；
- 不回 = 不同意，永远不会因沉默误批准。

### 远程会话（手机当键盘）

直接发文字就是给 agent 的输入；任务中途发 `! 改成方案B` 可以纠偏；
连续几条碎片会自动合并成一句。

### 远程提问（agent 反过来问你）

agent 遇到需要你拍板的选择（走哪个方案、删不删文件），会在手机上直接出**选择题**：

- 飞书 / Telegram / QQ 单聊：**选项卡片点一下即答**（一选项一按钮）；
- QQ 群聊 / 微信 / 钉钉 / WxPusher：按提示**回复编号**（如 `2`；多选用逗号隔开，如 `1,3`）。

答错了会收到提示并重发选项，问题不作废，再答就行；
一直不答就超时交回电脑端处理——**永远不会替你猜答案**（与审批同一原则：沉默不作数）。目前 DSH 宿主没有安全的 desktop `ask_user` 接口；电脑端只能接收 fail-closed 的回退结果，不能把桌面当作可用的提问结算入口。需要手动裁决时，可在本机 Web 管理台的脱敏问题列表中 choose/reject，结算仍经 Control Core。

### 命令速查（私聊机器人发）

| 命令 | 干什么 |
|---|---|
| `/help` | 列出全部可用命令 |
| `/whoami` | 看我是谁、绑定状态 |
| `/status` | 任务/会话跑得怎么样 |
| `/agent` | 列 agent 与会话名（`/quiet` 要用） |
| `/stop` | 停掉当前任务 |
| `/quiet`·`/unquiet <会话>` | 静默/恢复会话推送 |
| `/route …` | 多 agent 路由 |
| `/unpair` | 解绑（换号用） |

管理台页面：首页（链路状态/下一步/健康矩阵/提问/审计流）、通知渠道（凭证/测试/扫码）、成员、通知（实时事件流）；绑定矩阵与会话台账在「打开高级设置」里。

---

## 高级入口：YAML / CLI

全部配置也可以纯 YAML + 命令行完成：出站渠道写在 `cordis.patch.yml` 的 `channels` 下，
入站用 `node scripts/channel-login.mjs <qq|dingtalk|feishu|wechat>` 扫码。字段清单见
[README](../README.zh-CN.md#配置项)——这是高级/自动化入口；没特殊理由的话，网页点选快得多。

## 出问题了

| 现象 | 处理 |
|---|---|
| 找不到管理台链接 | 重启 DSH 看启动日志「Web 管理台已就绪」一行；链接照抄，端口不用猜（冲突会自动换） |
| token 失效/丢失 | 删 `state.json` 里 `admin:token-hash` 再重启，会重新生成并再打印一次 |
| 测试发送失败 | 按页面给出的原因修凭证后当场重试（测试不挑运行时状态，保存后即可测） |
| 网页配完运行链路没变化 | 正常——「重启后生效」：重启一次 DSH，通道卡片角标会消失 |
| Telegram 409 冲突 | 之前设过 webhook，去 @BotFather 删掉 |
| 飞书/钉钉里搜不到机器人 | 应用可用范围/机器人可见范围没开给自己，平台后台加 |
| QQ 群里发消息没反应 | QQ 群消息只有 @机器人才送达；配对必须在单聊 |
| 微信机器人不应答 | iLink 会话过期，「通知渠道」页 wechat 卡片重新点「扫码授权」（CLI 党重跑 `node scripts/wechat-login.mjs`） |
| 配对码已过期/被用 | 「成员」页再铸一枚（微信不需要配对码） |
| 手机远程控制/会话命令被拒（日志报 `missing_accountId`） | v0.8.x 起 accountId 来源规则：**绝不拿 channel 兜底**——来源必须真实存在，accountId 缺失一律 fail-closed 拒绝。单账号不配也行（通道会注入默认）；**同渠道跑多机器人/多应用（多账号）时必须在每个入站通道显式配置 accountId**（如 wxpusher 的 `accountId` 字段：本地账号标识，不要填 APP_TOKEN），否则消息无法归属到具体账号、远程控制/审批回执会被拒 |
| `你不在白名单中` | 该 IM 账号没配对——回第四步（微信用户检查是不是换了微信扫的码，重扫即自动换绑） |
| 其他 | 管理台「首页」看健康矩阵与实时事件流 |
