🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

哨兵值守 fuhefei/dsh-sentinel

DeepSeek Harnessv0.11.1
fuhefei2 天前有提交已提供中文文档扫描:含敏感能力

条件驱动的唤醒,给 DeepSeek Harness 用:agent 注册一条 watch…

45.3/100
综合分
21
GitHub 星标
137
npm 周下载
—/5
用户评分

数据截至 2026/11/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-sentinel
npm 源 · dsh-sentinel 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · market
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/10/29·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/03·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 2 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-sentinel @ 0.11.1
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/1 16:36:44

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 21 处,展示前 19 条)
  • 读取本地文件
    lib/index.js:323
    const info = await stat(target);
  • 执行外部命令来自配置/变量
    lib/index.js:350
    exec(target, {
  • 发起网络请求
    lib/index.js:371
    const response = await fetch(target, {
  • 执行外部命令固定命令
    lib/index.js:403
    execFile("pgrep", ["-af", target], {
  • 读取本地文件
    lib/index.js:529
    text = await readFile(this.path, "utf8");
  • 写入本地文件
    lib/index.js:565
    await mkdir(dirname(this.path), { recursive: true });
  • 写入本地文件
    lib/index.js:566
    await appendFile(this.path, line, "utf8");
  • 写入本地文件
    lib/index.js:575
    await mkdir(dirname(this.path), { recursive: true });
  • 写入本地文件
    lib/index.js:577
    await writeFile(tmp, text, "utf8");
  • 写入本地文件
    lib/index.js:578
    await rename(tmp, this.path);
  • 读取本地文件
    lib/index.js:794
    const parsed = JSON.parse(await readFile(leasePath(), "utf8"));
  • 写入本地文件
    lib/index.js:807
    await mkdir(dirname(path), { recursive: true });
  • 删除本地文件
    lib/index.js:833
    if (this.duty) unlink(leasePath()).catch(() => {});
  • 读取本地文件
    lib/index.js:1185
    stat(target).then(() => {
  • 读取本地文件
    lib/index.js:1203
    if (entry?.mode === "parent" && sub !== void 0) stat(sub.spec.target).then(() => {
  • 发起网络请求
    lib/index.js:1305
    const response = await fetch(url, {
  • 发起网络请求
    lib/client.js:83
    const res = await fetch(`${STATE_PATH}?sessionId=${encodeURIComponent(sessionId)}`, { headers: { accept: "application/json" } });
  • 发起网络请求
    lib/client.js:109
    const res = await fetch(STATE_PATH, { headers: { accept: "application/json" } });
  • 发起网络请求
    lib/client.js:206
    fetch(`${CANCEL_PATH}?sessionId=${encodeURIComponent(watch.sessionId)}&id=${encodeURIComponent(watch.id)}`, { method: "POST" });
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-agent-preset-registry@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-client-ui-layout@deepseek-ai/dsh-client-ui-primitives@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-sidebar@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-llm
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

3 张 · 点击查看大图

功能亮点

  • 条件驱动唤醒智能体
  • dock与全局仪表盘

条件驱动唤醒 DeepSeek Harness:持久化的文件/命令/http/进程/webhook 监听,唤醒智能体,带 dock、侧边栏分支和全局仪表盘。

v0.14.02026-11-02
v0.13.2 之后有两波功能,外加一批可靠性工作,让提交的产物可复现。 · 浏览器/仪表盘本地化大改(PR #15,@swimmwatch 提交) · Dock、面板和可选的 better-sidebar 标签页跟随 DSH 宿主语言环境并实时切换,打开状态下改语言也能生效。 · 探测状态、触发摘要、工具回执和唤醒共用中英文展示;中性的触发/状态数据单独持久化,每个查看端按自己的语言渲染。 · 独立仪表盘重写:改用 Mustache 模板,JS/CSS/图标走外部路由,沿用同一套浏览器信任校验,支持 Accept-Language 和 ?lang 协商,严格转义,不再有内联可执行脚本。 · 服务端生成的消息使用 config.locale(默认 en;在配置档补丁里设 locale: zh 可保持中文)。 · 新增会话传感器(issue #16) · sentinel_watch({ kind: "session", target: "" }) 在另一个会话提交持久化的 turn/end(根作用域 session/event)时触发,协调者可以串行串联会话,不用在提示词层面反复戳。 · 可选 pattern 按 turn 结束原因过滤:completed、max-tokens、aborted、blocked、error、interrupted、forked。纯推送:不探测、不心跳;触发复用持久化 sidecar 的预算/冷却/唤醒路径。 · 仪表盘和 dock 显示「on turn end」以及最近一次结果。 · 可靠性 / 构建 · 提交的 lib/ 按包内相对模板 id 重建:不嵌入构建机路径,任何检出目录干净重建都字节一致。 · sidecar 折叠仍在加载时到达的 turn/end 事件会先缓冲再重放;会话触发提交在 dispose 时等待完成,一次性进程不会在写入中途丢掉已触发的行。 · .cache/ 下的 vitest 临时文件已忽略;duty-owner 端到端测试去掉了偶发失败(它的租约 TTL 比心跳还短)。 · 兼容性与边界 · 宿主版本线:DSH 0.2.0–0.2.1(engines.dsh >=0.2.0-0 <0.3.0)。在 0.2.1-rc.4 上演练过,并用真实的 0.2.1-rc.2 事件/唤醒循环验证。 · 没有常驻 dsh 进程能观察事件时发生的 turn 结束,之后不会重放——链条必须扛过整段停机时,请用探测支撑的闸门。 · 含会话监听的 sidecar 行会被 <=0.13.2 的读取端拒绝:降级前先取消会话监听。 已验证:208/208 测试、tsc -b --noEmit、pnpm build、npm pack、dsh-plugin-dev verify 5/5,外加隔离的真实宿主检查。 从 tag 安装(构建产物已提交,无需构建步骤): dsh plugin --profile web add "github:fuhefei/dsh-sentinel#v0.14.0" 感谢 @swimmwatch 的本地化大改,感谢 @canyoubarrett 对会话传感器 API 的细致调研。 · 线上部署验证(2026-11-02) 线上 DSH web 部署在一个维护窗口内从 0.2.1-rc.2 升到 0.2.1-rc.4,同时升级本插件(保留备份 + 干净重装配置档 + 自动验证/回滚路径;服务端消息配置为 locale: zh): · launcher 0.2.1-rc.4、dsh-sentinel 0.14.0、dsh-web-shell 0.2.0,配置档里没有宿主 @deepseek-ai 包; · 72 条启动记录,两个客户端 bundle 正常提供,sentinel 状态路由和 duty 租约正常应答,零跳过 bundle / 激活警告; · 部署检查器返回 RESULT: PASS,重启后一个 sentinel 文件监听唤醒了维护会话,做升级后验证。
v0.13.22026-10-19
· DSH 0.2.1 对齐 部署从 dsh 0.2.0-rc.2 升到 dsh 0.2.1-rc.2,本次发布是插件的对齐版本。插件源码无需改动:针对真实的 0.2.1-rc.2 包,tsc -b --noEmit 通过,全部 76 个测试通过,重新构建产出的 lib/ 包逐字节一致。 · devDependencies 升到 0.2.1-rc.2(全部十二个 @deepseek-ai/* 版本锁定)。 · engines.dsh 声明为 >=0.2.0-0 <0.3.0。从 0.2.1-alpha.4 起,只要清单里声明了 engines.dsh,宿主的安装校验就只看这个字段(见宿主 evaluatePluginCompatibility 源码),所以这个字段现在承担 0.2 系列的准入:0.2.0 回滚线和 0.2.1+ 都放行,更早的系列一律拒绝。 · 插件管理器展示元数据 0.2 代管理器不激活插件就能读取展示元数据,本次发布已带上:locale/en.json + locale/zh.json 的元标题/描述,外加导出的图标。dsh-plugin-guide 里的展示元数据检查现在通过了。 · 修复 · git 安装示例锁定了过期标签(#14)。github:fuhefei/dsh-sentinel#v0.11.0 让复制粘贴安装落到早于 0.1.7/0.2 兼容修复的版本——有反馈者 watch 触发并投递成功,但 v4 会话格式静默拒绝了唤醒。示例现在锁定 v0.13.2,并注明该标签跟随最新发布。 · 更正了 README 的兼容性段落:三个 harness 包自 v0.13.0 起是 peerDependencies(单宿主实例;第二份副本持有不同的 TOOL_RUNTIME_SCHEDULER 符号,会破坏真实工具调用),不是随附依赖。 · 验证 升级后的部署:在 dsh 0.2.1-rc.2 上干净重装配置档;插件激活,持有 duty 租约,客户端包带上 sidebar.panellist,状态路由有响应,71 条启动记录,零跳过包。先在线上配置档的副本上演练过;启动器 + 配置档备份保留用于回滚。
v0.13.12026-10-07
· 修复 · 客户端状态轮询器不再重叠,也不再泄漏在途请求(#13)。按会话的钩子和页面级共享轮询器都设了 setInterval,每次触发都发请求,不看上一个请求的状态,服务器一慢就堆积未完成请求——报告者隔离复现时五次触发产生了六个——卸载时只清定时器,在途请求仍会解析到已销毁的组件。fetch 完全没带 AbortSignal,最后一个全局订阅者离开时也没取消共享请求。 两者现在都改用自调度轮询器:上一个请求结束后才安排下一次触发,因此最多只有一个请求在途,每个请求都带信号,在销毁或单请求超时时中止。超时是必需的,不是防御性的——因为循环在请求结束后才重新安排,一个永不结束的请求会让轮询永久卡住。 · 改进 · 宿主对等依赖范围现在覆盖 0.2 系列,不再锁死单个版本。三个对等依赖原本精确锁定 0.2.0-rc.2,意味着插件只能装在一个宿主版本上,下一个版本就装不上——0.1.7 → 0.2.0 的升级就是这样断的,每个 0.2.x 都会重演。现在改为 >=0.2.0-rc.2 <0.3.0,仍然拒绝更老的版本。 用宿主自己的兼容性校验验证,而非人工检查:0.2.0-rc.2 和 0.2.1-alpha.1 通过;0.2.0-rc.1 和 0.1.7-rc.2 被拒。在基于线上配置档副本、运行 0.2.1-alpha.1 的预演环境验证——插件激活、持有职责租约、提供客户端部分并响应状态路由(68 条启动记录)。 · 备注 · 八个新单元测试覆盖轮询器约定:挂起服务器下不累积、顺序重排、停止时中止、超时恢复、中止与错误的上报区分、幂等启动与重启。这些测试有杀伤力——对旧的 setInterval 设计,不累积断言在十个间隔后以 11 个未完成请求失败。全套:76/76。 · dsh-web-shell 在自己的清单里仍锁定 <0.2.0,0.2.0-rc.2 恰好满足(预发布版排序低于正式版),但 0.2.1-alpha.1 不满足。如果你跑 alpha 版,终端包会被跳过,直到上游修复。 完整变更日志:
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-sentinel 条件驱动的唤醒,给 DeepSeek Harness 用:agent 注册一条 watch 就可以去睡觉——甚至直接关掉会话——条件成立时由 sentinel 把它叫醒。每一次订阅、每一次触发都是用户可见的会话事件,浏览器 dock 上随时能看到谁在值守。 Sentinel dock 面板(展开) 工作原理 Node 侧持有一个与 server 同生命周期的运行时:把插件自己的 sidecar 日志($DSH_HOME/sentinel.jsonl)折叠成活跃订阅,按共享的 5 秒心跳探测探测类传感器,同时监听宿主所有已发布会话的持久 turn/end 事件供 session 传感器使用,命中后走官方 followup 通道投递唤醒——必要时先复活休眠会话的 agent。所以订阅能扛住进程重启;server 停机期间变真的条件,会在下一次探测时补触发(session 类 watch 在下次观察到回合结束时触发)。 值守是常驻进程的事:探测和触发投递只在有一个长期运行的 dsh 进程(通常是 dsh web)时进行。一次性 headless 运行也能加载插件、创建/列出/取消 watch,但进程退出后没人探测——等下一个常驻进程起来,这些 watch 自动恢复值守。
展开完整文档(README 剩余 1 节)
dsh-sentinel

条件驱动的唤醒,给 DeepSeek Harness 用:agent 注册一条 watch 就可以去睡觉——甚至直接关掉会话——条件成立时由 sentinel 把它叫醒。每一次订阅、每一次触发都是用户可见的会话事件,浏览器 dock 上随时能看到谁在值守。

Sentinel dock 面板(展开)

工作原理

Node 侧持有一个与 server 同生命周期的运行时:把插件自己的 sidecar 日志($DSH_HOME/sentinel.jsonl)折叠成活跃订阅,按共享的 5 秒心跳探测探测类传感器,同时监听宿主所有已发布会话的持久 turn/end 事件供 session 传感器使用,命中后走官方 followup 通道投递唤醒——必要时先复活休眠会话的 agent。所以订阅能扛住进程重启;server 停机期间变真的条件,会在下一次探测时补触发(session 类 watch 在下次观察到回合结束时触发)。

值守是常驻进程的事:探测和触发投递只在有一个长期运行的 dsh 进程(通常是 dsh web)时进行。一次性 headless 运行也能加载插件、创建/列出/取消 watch,但进程退出后没人探测——等下一个常驻进程起来,这些 watch 自动恢复值守。

每个 $DSH_HOME 只有一个值守 owner:租约文件 sentinel.lease 让第一个进程拥有探测和投递权;同一 home 上的第二个 dsh 进程保持被动(工具可用,写入照常落到共享 sidecar),owner 死后一个租约 TTL 内接管。owner 每个心跳重读 sidecar,被动实例上创建的 watch 会被自动收编。投递语义是 at-least-once:崩溃前已记录但没送出的触发,重启后从 delivered 水位线重新入队。

浏览器侧是 composer 上方的 dock 卡片(conversation.input.dock 族),列出本会话的活跃 watch——传感器、目标、实时探测状态、触发预算、下次探测倒计时——展开还有最近的触发历史。它轮询只读的 state 路由;会话没有 watch 时不渲染任何东西。

两个界面暴露 server 全局的 watch 集合。侧边栏全局面板列表里多出一个哨兵条目(sidebar.panellist,id sentinel),点击即在中栏(main 同名 key)打开 watch 表——只要有活跃 watch,图标上就带一个状态点。dashboard 是跨所有会话的全量 watch 表:会话(active/dormant)、传感器、目标、pattern、触发预算、最近探测状态、下次探测。

全局 dashboard

传感器

| kind | 引擎 | 触发条件 |
| file | 路径快照 + inotify 推送 | 快照变化(亚秒级);fs 事件加速 |
| command | 只读 shell 单行输出,按间隔探测 | 输出/退出码变化 |
| http | 按间隔探测 URL | 状态/响应体变化 |
| process | pgrep -f 模式,按间隔探测 | 匹配集变化 |
| port | 对 [host:]port 做 TCP 连接,按间隔探测 | 可达性变化(open/closed/timeout) |
| webhook | 纯推送 | 对返回的 hook URL 发任何 POST |
| session | 宿主会话事件流(不探测) | 另一个会话的 turn/end;可选 pattern 过滤回合结束原因 |

带 pattern 时,探测类传感器在该正则的"不匹配→匹配"边沿触发,webhook 只接受匹配的载荷,session watch 只在回合结束原因匹配该正则时触发(原因取值:completed、max-tokens、aborted、blocked、error、interrupted、forked);不带时,探测类传感器对基线之后的任何变化触发,webhook 对任何 POST 触发,session watch 对任何回合结束触发。

session watch 让串行会话链无需在提示词里互相戳:{ "kind": "session", "target": "<另一个会话 id>", "note": "第一步跑完了,轮到你了", "maxFires": 1 } 会在目标会话结束回合时唤醒当前会话;加 pattern: "^completed$" 则只认干净完成(崩溃或中止的会话永远不会满足,链条自然停住)。事件源是宿主持久的 turn/end,没有探测基线,也不走心跳。若某个回合结束时没有任何常驻 dsh 进程在观察事件,该次结束不会被事后补发——需要扛住整段停机时间的链条应改用可探测的闸门。

配置

所有部署相关的旋钮都在插件的 config schema 里(括号内为默认值),在 profile 的 cordis.patch.yml 里对 bundle 行覆盖:

- id: dsh-sentinel
name: dsh-sentinel
config:
locale: en # 服务端消息:en(默认)或 zh;界面跟随宿主 heartbeatMs: 5000 # 探测轮间隔 probeConcurrency: 8 # 每轮并发探测数 maxSubscriptionsPerSession: 16 maxPendingWakeups: 8 # 每会话排队唤醒上限,超出丢最旧的 defaultIntervalSeconds: 30 # watch 未指定间隔时的默认值(5–86400) defaultCooldownSeconds: 60 dutyLeaseTtlMs: 30000 # owner 死后被动实例的接管窗口 notifyWebhookUrl: '' # 可选:每次触发以 JSON POST 到这里

非法值会让插件加载时以 schema 错误失败,而不是运行时乱来。

notifyWebhookUrl 把每次触发以 JSON POST({plugin, event, sessionId, id, kind, target, note, fireNumber, maxFires, summary, after})送出 harness——指向飞书/企微/Slack 机器人或任意接收端都行。这条投递是 at-most-once:POST 失败只在日志里 warn,绝不阻塞 harness 内的唤醒。

本地化

- dock、全局面板及可选的 better-sidebar 标签页跟随 DSH 的语言设置,打开时切换语言也会更新,不再用浏览器语言覆盖宿主偏好。支持英文和中文,其他宿主语言沿注册的回退链查找这两种字典,最终回退到英文。
- 可选的 better-sidebar 底部工作台标签可能保留打开时保存的标题。内容会实时更新,但切换语言后,该标签栏标题可能需要关闭并重新打开标签才会更新;Sentinel 不修改第三方标签状态。
- dashboard 链接通过 ?lang=en 或 ?lang=zh 传递界面语言。直接访问时按 Accept-Language 的权重(q)和请求顺序协商支持的语言,明确排除优先于通配符。未提供偏好则使用服务端 locale,没有可接受的偏好时回退到英文。初始 HTML 和后续刷新使用同一语言,包括页面标题、两张表的表头、状态标签、时间和触发摘要。
- 工具及后台唤醒没有浏览器语言上下文。其回执、指令和通知摘要使用插件配置 locale(默认 en,设置 zh 可保留中文服务端消息)。工具 schema、协议字段及开发诊断仍使用英文。
- 触发事件保留兼容旧消费者的可读 summary,并新增可选的语言无关字段 trigger 和 state,界面按查看者语言格式化。已知的旧版中英文摘要也按所选语言展示,不重写 sidecar 日志;未知或无法明确解析的摘要原样保留。
- 便签、目标、正则、匹配文本、webhook 载荷及前后快照保持原文。快照字节和占位符绝不翻译,因此本地化不会产生虚假变化或改变正则匹配。

例如,英文界面会显示 Snapshot changed (state: exit 0),而不是 快照发生变化(状态: exit 0),不受服务端消息语言影响。

独立页面使用 Mustache.js 4.2.0,按文档、页面、表格局部模板组织:

templates/layouts/document.html 文档元信息与资源链接 templates/dashboard.html 页面结构与表头 templates/dashboard/watches.html 监控行与空状态 templates/dashboard/fires.html 触发记录行与空状态

这是 Mustache 标准 partial 组合,不自建模板继承扩展。简单标签、badge 和正则标记直接保留在所属模板,不再拆成单标签文件。服务端渲染完整初始表格,浏览器复用同一套有实际职责的行模板和类型化展示模型。所有值均使用默认 HTML 转义,不使用原始 HTML 插槽、调用方模板或模板函数。缺失键输出空字符串,必需展示字段由模型与模板契约测试覆盖。

样式位于独立 CSS 源文件,构建时复制为发布的 CSS 资源,由文档布局通过 link 加载。独立浏览器脚本 使用 defer。布局链接包内现有 SVG 图标,避免浏览器请求不存在的默认 favicon。不使用内联样式、可执行内联脚本、运行时代码生成、函数序列化或 DSH 浏览器启动上下文。Mustache 打包进 node 和浏览器入口;嵌套模板、CSS、JavaScript 和第三方许可证声明 随 npm 包发布。初始 HTML 和样式不依赖 JavaScript。

工具

- sentinel_watch — 注册 watch:kind(file、command、http、process、port、session 或 webhook)、target、可选 pattern、interval(5–86400 秒,默认 30;session 与 webhook 忽略)、note(随每次唤醒原样送达)、maxFires(默认 1:一次性)、cooldown(默认 60 秒)、可选 ttl。session 的 target 是要观察 turn/end 的会话 id。
- sentinel_list — 列出活跃 watch 及其实时探测状态。
- sentinel_cancel — 按 id 取消一条 watch。

路由

- GET /plugins/dsh-sentinel/state?sessionId=… — dock 和侧边栏面板用的只读状态(省略 sessionId 返回所有会话)。
- GET /plugins/dsh-sentinel/dashboard — server 全局 watch 表。
- GET /plugins/dsh-sentinel/dashboard.js — 独立浏览器脚本。
- GET /plugins/dsh-sentinel/dashboard.css — 独立样式表。
- GET /plugins/dsh-sentinel/icon.svg — 用作页面 favicon 的现有包图标。
- 这三个固定资源支持无响应体的 HEAD,其他方法返回 405,并分别使用正确 MIME 类型、nosniff 和需重新验证的缓存策略。
- POST /plugins/dsh-sentinel/hook?id=watch-N&s=<sessionId> — webhook 入口;把一条 curl 塞进 CI 任务、git hook 或另一台机器的脚本,就能叫醒 agent。watch id 按会话隔离,s 限定符保证两个会话的 watch-1 hook 不打架(工具直接发完整 URL)。不带 s 的 URL 仍可用,解析到第一条匹配的 webhook watch。
- POST /plugins/dsh-sentinel/cancel?sessionId=…&id=watch-N — 手动取消。dashboard 表和每个 UI 行都带 ✕,任何 watch 都能手动停掉——包括会话和 agent 早就不在了的孤儿 watch。活跃会话离开 store 时会发 session/disposed,但 sentinel 不把它当作取消信号(目标会话被 dispose 的 session watch 仍保持 armed,直到手动取消),所以手动取消仍然是最后的兜底开关。
- 所有路由都带浏览器信任围栏:浏览器标记的跨站请求(恶意页面可以往 localhost form-POST)和 DNS rebinding 尝试(Host/Origin 指向 DNS 主机名)一律 403。curl、CI 任务这类无头客户端不受影响。state 路由还返回每个会话的 duty(租约心跳年龄)和 droppedWakeups(被 maxPendingWakeups 上限丢掉的排队唤醒)。

首次探测语义:不带 pattern 的探测类 watch 把第一次观测吸收为基线(不触发);带 pattern 的探测类 watch 如果目标已经匹配,第一次探测就触发——条件本来就成立。session watch 没有探测基线:第一条匹配的 turn/end 就触发。

兼容性

在以下宿主版本上实测通过(插件加载、duty 租约持有、web 路由应答均正常)。session 传感器要求宿主提供根级 session/event 事件流,受支持的 0.2.x 线均具备;在支持范围之外的宿主上,watch 会被接受但永远不会触发。sidecar 回滚提示:含 session watch 行(新 kind,或 fired 行上的 trigger.kind: "session")的 sentinel.jsonl 会被 0.13.2 及更旧的 reader 拒绝——降级前先取消这些 watch。

- 0.2.1-rc.4 —— 2026-11-02,线上 web 部署由 0.2.1-rc.2 升级、并同时部署 v0.14.0 插件(launcher 备份 + profile 净装 + 自动核验/回滚保留;升级前先在线上 profile 副本上彩排):launcher 0.2.1-rc.4、sentinel 0.14.0、web-shell 0.2.0;boot 图 72 条、两个客户端 bundle 正常下发、duty 租约与 state 路由应答、零跳过 bundle / 零 activation warning、profile 无宿主 @deepseek-ai 依赖。profile patch 已配置 locale: zh(服务端中文消息)。部署自带的 check-sentinel-deploy.sh 返回 RESULT: PASS。
- 0.2.1-rc.2 —— 2026-10-19,线上 web 部署由 0.2.0-rc.2 升级后实测(profile 净装、launcher 备份与回滚路径保留):插件激活、持有 duty 租约、下发客户端半侧并应答 state 路由(boot 图 71 条、零跳过 bundle、终端插件仍在)。源码无需改动——对真实 0.2.1-rc.2 包运行 tsc -b --noEmit 通过、全部 76 个测试通过、重建的 lib/ 逐字节不变——因此 0.13.2 是对齐版本:devDependencies 钉到 0.2.1-rc.2、声明 engines.dsh 为 >=0.2.0-0 <0.3.0,并补上 0.2 世代的展示元数据(locale/*.json + 图标),供插件管理器在不激活插件时读取。自 0.2.1-alpha.4 起,安装期版本闸门在声明了 engines.dsh 时只按它判断(已核对的宿主 evaluatePluginCompatibility 源码),因此 0.2 线的准入由这个字段承担;peer 范围仍作为老宿主的回退判断。
- 0.2.1-alpha.1 —— 2026-10-07,对线上 profile 副本的彩排:插件激活、持有 duty 租约、下发客户端半侧并应答 state 路由(boot 图 68 条)。能到这一步需要放宽 peer 范围(见下方 0.2.0-rc.2);并直接调用宿主的 evaluatePluginCompatibility 核对了版本闸门:当前范围放行 0.2.0-rc.2 与 0.2.1-alpha.1,仍拒绝 0.2.0-rc.1 及更旧。
- 0.2.0-rc.2 —— 2026-09-30,运行时和客户端构建依赖对齐到此版本,并重新生成 npm、pnpm 锁文件。休眠会话唤醒时从会话投影恢复原 preset,并完整传递默认模型选择,包括思考强度。值守租约固定在运行时创建时的目录;清理等待启动和探测轮次结束后再释放租约。2026-10-07 补充:三个 harness peer 由"精确单一版本"放宽为 >=0.2.0-rc.2 <0.3.0,一份构建即可服务整条 0.2 线,而不是只能服务某一个发行版——精确钉版会让插件在紧邻的下一个 0.2.x 上直接装不上,0.1.7 升 0.2.0 时就是这么坏的。
- 0.1.7-rc.2 —— 2026-09-29,对线上 profile 的副本做整轮净装升级彩排:0.1.7 删除了共享的兜底 plugin 消息来源 kind(改为每个生产者声明自己的),因此唤醒携带 { kind: 'sentinel' }——在会话流里落位同为 context,两条版本线上都渲染为 "Sentinel"。harness 依赖范围也重新钉到 0.1.7 线:严格 semver 下 >=0.1.5-rc.2 <0.2.0 不包含 0.1.7-rc.2(预发布规则),若不改,0.1.7 宿主会把本插件的 harness import 解析到 0.1.5 的副本——正是 0.1.5 对齐时消除掉的那类漂移。实测:pnpm typecheck 与全部 63 个测试通过,插件激活并持有 duty 租约,web 路由应答正常,下发的客户端 bundle 含 sidebar.panellist(boot 图 65 条)
- 0.1.5-rc.2 —— 2026-09-15,对齐 0.1.5 后的正式 web 部署实测:插件整条运行时 import 闭包都解析到部署线(harness 依赖改为显式 dependencies,profile 里更旧的 hoisted 副本再也遮不住它们),客户端半侧去掉 shim 后按真实 0.1.5 类型构建,pnpm typecheck 与全部 63 个测试通过,线上文件 watch 在改动后 1s 内经 inotify 触发,唤醒作为 plugin 来源的会话消息投递进会话;重启后部署下发的是新的客户端半侧(bundle rev 变更、含 sidebar.panellist、boot 图 54 条)
- 0.1.5-alpha.2 —— 2026-09-09,临时 web profile 实测:Node 插件加载、duty 租约、state/dashboard 路由和浏览器插件 bundle 均正常,浏览器控制台无报错;conversation.input.dock 仍是有效的会话级 list slot,插件 sidecar 不受 Session V3 迁移影响
- 0.1.1-rc.2 —— 2026-08-26,源码构建冒烟:git 装入 web profile,duty 租约持有,state 与 dashboard 路由应答正常
- 0.1.0-rc.8 —— 2026-08-20,scratch profile 冒烟
- 0.1.0-rc.7 —— 2026-08-20,正式 web 部署

这里的兼容指 cordis loader 条目、ctx.agents 跟进通道、所声明的 slot 座位和 web 路由持续可用;若某版本破坏了其中任一环节,请提 issue。插件的 harness 依赖(@deepseek-ai/dsh-tools、@deepseek-ai/dsh-llm、@deepseek-ai/dsh-scope)同时是 peerDependencies 与 devDependencies:运行时单实例由宿主提供(第二份核心包持有不同的 TOOL_RUNTIME_SCHEDULER Symbol,真实工具调用会坏),精确的 dev 钉版则让本地 typecheck/build 停在已验证线上。@deepseek-ai/cordis 与 react 仍是 peer,支持范围由 engines.dsh 声明。

安装

走官方 bundle 通道一行装完:

dsh plugin --profile web add dsh-sentinel

或者直接从 git 装(构建产物直接提交在仓库里,git 源安装不需要跑构建):

dsh plugin --profile web add "github:fuhefei/dsh-sentinel#v0.14.0"

示例里的 tag 会随最新 release 更新;更旧的 tag 钉的是更旧的宿主线,抄进别的 dsh 版本前请先看 Releases(或干脆去掉 tag 跟 main)。

或者手动加 node 半边:在你现有 base 上叠一层 patch-list 配置:

cordis.patch.yml
- insert:
- id: dsh-sentinel
name: dsh-sentinel

浏览器半边在同一个包里(./client),由 Web UI 的插件加载器注入。

侧边栏界面(0.1.5 及以后)

dock、侧边栏条目和 dashboard 在原版 host 上都能用:条目注册进官方 sidebar.panellist 座位,面板注册进布局的 main slot,无需给宿主打任何补丁。

在 0.1.2 及更早版本里,全局视图改而长在每条被监视会话行下方,需要官方树从未声明过的会话行扩展洞;该路径已退役,patches/session-row-holes.patch 只为那些旧树保留。0.1.5 起旧洞已不存在,面向它的插件必须改用上面的面板座位。

better-sidebar 集成(可选)

同一 profile 里装有 dsh-better-sidebar 时,sentinel 通过它公开的 ctx.betterSidebar.registerTab 扩展面,把全局 watch 表注册成一个侧边栏 tab(dsh-sentinel:watches,在 + 菜单里):server 上每条 watch 的实时探测状态、触发预算和最近触发历史,由一个共享轮询器供数。无需配置;没装 better-sidebar 时注册静默跳过,dock / 面板 / dashboard 照常工作。

better-sidebar 工作台里的 sentinel tab

组合使用

和 dsh-notification 一起装,整个唤醒回路就能到达桌面:sentinel 叫醒 agent,agent 干完这一轮,回合结束触发桌面通知——零集成代码,两个插件自己组合出来。

开发

npm install
npm run build # tsc -b + tsdown(服务端、宿主客户端和独立 dashboard 资源)
npm test # vitest:领域、传感器、React 生命周期、模板/浏览器、发布包资源、e2e

许可证

BSD-3-Clause,见 LICENSE。
预览分享卡片长什么样 ↓fuhefei/dsh-sentinel
分享 · DeepSeek Harness Hub
fuhefei/dsh-sentinel

条件驱动的唤醒,给 DeepSeek Harness 用:agent 注册一条 watch…

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部