DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-agent-sentinel

j

dsh-agent-sentinel

Discovered

Sentinel plugin (split from `dsh-agent-watch`): listens to the sentinel file (`.hot-reload-flag`) → on trigger, invokes the sandbox preflight check (`ctx.preflight.run`, consuming the `dsh-agent-preflight` service) → only restarts web if it passes →

Machine translated

dsh-agent-sentinel

version license TypeScript tests

一句话:热重载的协调员——监听到哨兵文件就按固定顺序走一遍「预检 → 取租约 → 停旧实例 → 起新实例 → 等就绪 → 唤醒会话 → 清哨兵」,任何一步不过就停手留档,绝不盲重启。

为什么值得用:改完代码重启,是这套体系里唯一不可逆的动作——重启前的实例已经在跑,重启后的实例没人验证过。没有协调员的「热重载」实际是赌博:坏组合一装上去就是服务不可用 + 守护熔断。本插件把「验证」「互斥」「留痕」「唤醒」串成一条fail-closed 的流水线:预检 FAIL 就保留哨兵、落盘 incident、通知会话并等修复后重试——旧实例毫发无伤。

能力

本插件无工具面,它对外的能力是「被哨兵文件触发的一段流程」:

步骤做什么失败时
① 监听fs.watch 监听 watchDirs 下的哨兵文件(.hot-reload-flag 及 legacyFlags);debounceMs 去抖—
② 预检ctx.preflight.run(workspace, 'full')(消费 dsh-agent-preflight)保留哨兵 + 落盘 incident + 通知「免疫层拦截,修复后 touch 重试」
③ 取租约写 <DSH_HOME>/.web-lifecycle-lease.json(owner=sentinel,TTL 120s)他人持租则让位(落一行理由)
④ 重启ctx.webman.killWeb(portOwner) → ctx.webman.spawnWeb(workspace)通知告警;不重复拉起
⑤ 等就绪轮询 baseUrl 至 ready(readyTimeoutMs)告警「web 重启后未在时限内就绪——请检查 web 启动日志」
⑥ 唤醒选目标会话投递唤醒(session-* 用户会话优先;显式锚点滞后 > 10 分钟判锚点腐化 → 改投最近活跃用户会话)告警「已重启但未能唤醒目标会话」+ 候选列表
⑦ 清哨兵删除哨兵文件 + 释放租约(写「已释放」留痕)留痕不静默

另外它还承担一道门控:拦截「本 web 进程内未通过预检闸门」的 daemon_restart 请求(判据读 <DSH_HOME>/.preflight-invoked.json,进程级,不比对会话 id),提示先做预检再重启。

职责分工:sentinel 协调重启 / preflight 把关 / guardian 保活——三者的能力边界不得互相吞并。

快速开始

1) 装依赖(自研插件家园 self-plugins/,在 watch profile 的 package.json 加 link 依赖):

"dsh-agent-sentinel": "link:<工作区>/self-plugins/dsh-agent-sentinel"

2) 构建:

cd self-plugins/dsh-agent-sentinel && npm install && npm run build && npm test

3) 挂组合(watch profile;inject 要求同侧存在 preflight / agentRuntime / webman 三个服务):

- id: agent-sentinel
  name: dsh-agent-sentinel
  config:
    profile: web
    port: 3080
    watchDirs: ["<工作区>"]

4) 30 秒验证:

# ① 结构性验证(不重启任何东西):插件装载证据 + 事件日志尾部
tail -3 "$DSH_HOME/.watch-events.log"
# ② 行为验证(**会真的重启 web**,确认当前无人在用时再做):
#    按开发流程写哨兵文件:改代码 → 构建 → 测试 → 写哨兵
printf '{"workspace":"<工作区>","sessionId":"session-<id>","note":"readme 验证"}' > "$DSH_HOME/.hot-reload-flag"
tail -8 "$DSH_HOME/.watch-events.log"
# 期望顺序:预检 PASS → 取租约 → kill/spawn → web 就绪 → 已唤醒会话 → 哨兵已清
ls -l "$DSH_HOME/.hot-reload-flag"       # 期望:文件已被删除(清哨兵成功)

配置

(键名与 src/index.ts 的 Config schema 一致;默认值取自源码)

项默认说明
dshHome$DSH_HOME(空串则回退进程 cwd)哨兵文件/日志/租约/incident 的根
watchDirs[]fs.watch 监听的目录列表(哨兵文件所在目录,通常是工作区)
flagFile.hot-reload-flag哨兵文件名
legacyFlags[]兼容的旧哨兵文件名(可多个)
bin''(交给 runtime 发现)dsh bin.js 路径覆盖
profileweb重启目标 profile
port3080web 端口(查端口归属 / 判活)
baseUrlhttp://127.0.0.1:3080就绪探活基址
readyTimeoutMs30000重启后就绪等待上限
incidentFile''(回退 $DSH_HOME/.watch-incident.json)事故落档路径
defaultWorkspace''(回退进程 cwd)默认工作区
debounceMs300哨兵文件事件去抖(编辑器写文件会触发多次事件)
launchCmd[]启动命令覆盖(交给 runtime)
telegramBotToken''事故告警 bot token(只在组合 patch 里配,不进源码)
telegramChatId''事故告警目标 chat(同上)
httpProxyhttp://127.0.0.1:16888告警通道代理

落盘与自证(出问题时先看这里)

本插件不写 *-trace.jsonl 阶段轨迹,它的自证是一组状态文件 + 一行行事件日志:

文件谁写内容
<DSH_HOME>/.hot-reload-flag调用方(人/agent)哨兵本体:{ workspace, sessionId, note }。被成功处理才删除——它在 = 这次热重载没完成
<DSH_HOME>/.watch-events.log本插件事件行(append):预检结果 / 租约取得与让位 / 重启 / 就绪 / 唤醒结果 / 哨兵清理。这是主要的人类可读时间线
<DSH_HOME>/.watch-incident.json本插件事故落档(覆盖写):{ at, ...detail }——预检失败等重大异常的结构化记录
<DSH_HOME>/.web-lifecycle-lease.json本插件(与 guardian 共用的同一份契约)生命周期租约:{ owner, atMs, ttlMs, note? }。TTL 120s;释放写「已释放」留痕而非删文件
<DSH_HOME>/.sentinel-web-start.json本插件{ atMs, workspace, pid }——本次 web 的启动时刻与 pid。「构建产物 vs 生效」判据的取证面
<DSH_HOME>/.preflight-invoked.jsondsh-agent-plugin-manager只读输入:daemon_restart 门控据此判断「本 web 进程内是否调用过预检」

一条命令答五问:

tail -12 "$DSH_HOME/.watch-events.log"; echo ---; cat "$DSH_HOME/.sentinel-web-start.json"
# ① 跑的是哪个构建  → 本插件不写 build 自报;用 .sentinel-web-start.json 的 atMs(web 启动时刻)对比 lib/index.js 的 mtime——**产物 mtime 晚于启动时刻 = 新构建还没生效**
# ② 谁发起          → 哨兵文件里的 workspace/sessionId/note(触发者留的信);事件行记录"谁来唤醒/投给谁"
# ③ 断在哪一段      → 事件行序列即断点:只有"预检…"无后续 = 卡在门控;有 kill 无 spawn = 卡在拉起;有 spawn 没就绪 = 卡在等待;就绪了没唤醒 = 卡在会话选择
# ④ 结果质量        → 是否出现"哨兵已清"(成功收口);告警行文案区分「未就绪」与「已重启但未唤醒」(+候选列表)
# ⑤ 耗时与预算      → 就绪等待对比 readyTimeoutMs(30000);租约 ttlMs=120000;debounceMs=300(去抖)

读日志的正确姿势:.watch-events.log 是 append-only 的时间线,最后一行才是当前状态。哨兵文件仍存在 + 最后一行是预检 FAIL = 免疫层正确拦下(不是故障,是设计);哨兵文件仍存在 + 最后一行是「等待确认」= 报告已送达,等人工放行。

生效判据与回退

生效判据(三选一,按可靠性排序):

  1. 产物 vs 进程(本插件最可靠的一条):<DSH_HOME>/.sentinel-web-start.json 的 atMs 晚于 lib/index.js 的 mtime ⇒ 当前守护进程加载的是这个构建。反之(产物比启动新)⇒ 改了代码但没重启守护,改动未生效;
  2. 生态级:plugin_boot_status(dsh-plugin-bootreport)返回的 liveNow 含本插件 ⇒ 同上;
  3. 行为级:写哨兵文件后 .watch-events.log 出现新的预检/重启/唤醒行 ⇒ 监听与流程都在工作。

注意:重新构建 ≠ 生效——产物 mtime 新只证明「构建过」,进程启动时间晚于产物 mtime 才算「在跑它」。watch 侧没有 hasUnverifiedBuilds() 类兜底(web 侧有),所以守护侧的「构建完没重启」是最容易漏的一类失效:改动躺在磁盘上,机制照旧跑旧代码。

回退(三档):

  • 源码级:git -C self-plugins/dsh-agent-sentinel revert <commit> → npm run build → npm test → (由主人)重启 watch profile;
  • 组合级:在 watch profile 给 agent-sentinel 行加 disabled: true(或移除该行)→ 由主人重启 watch profile;
  • 运行期:删除残留哨兵文件 rm "$DSH_HOME/.hot-reload-flag"(= 主动放弃这次热重载,仓库保持旧代码运行);事件日志/incident 可随时归档。

部署边界(守护族硬约束):本插件运行在 watch profile,而 watch 侧的更新与重启由主人执行——改代码、构建、跑测试、出报告都归开发者;kill / 重启守护进程不归开发者(守护链是最后一道托底,自己把自己杀掉会让整个体系在无人接管时停摆)。同理,本插件负责重启的是 web 实例,不是它自己所在的守护进程。

测试

npm test        # = node --test "tests/*.test.mjs"(跑 lib/ 产物,需先 npm run build)

56 例离线测试全部通过(# pass 56 / # fail 0,8 个 suite):

文件覆盖
tests/lease.test.mjs生命周期租约(单点所有权):无租约放行、坏时钟/时钟偏移放行 + 落盘 issue、过期接管、自持放行、他人持有时让位且理由里带 holder/age/remaining/note;尸体测试用真实时刻表(事故当刻:一方取租 → 另一方巡检必须让位)+ 过期接管样本
tests/wake-target.test.mjs唤醒目标选择:isUserSession 判据(session-* 前缀且非空白——子代理裸 uuid 不可唤醒)、按最近活跃降序排名、显式锚点新鲜度(滞后 > DEFAULT_ANCHOR_STALE_MS 10 分钟判腐化 → 改投最近活跃用户会话)、updatedAt 秒/毫秒归一化、候选列表逐次换人留痕
tests/preflight-gate.test.mjsdaemon_restart 门控判据:本进程内已调用预检 → 放行;未调用 / 调用早于进程启动 → 拦截并给出理由(进程级判据,不比对会话 id)
tests/alert-transport.test.mjs告警传输:走 Node 子进程 fetch(NODE_USE_ENV_PROXY=1)主通道,curl.exe -x <proxy> 为兜底;每条结论都落盘(发送中/送达通道/失败原因)——不允许「告警发没发出去事后无法回答」

可能需要网络/真实外部依赖:仅告警通道(Telegram)需要真实 token + 网络/代理;测试用桩覆盖,不真发消息。其余全部离线(文件系统 + 纯函数)。

设计要点

  • fail-closed 是全部意义:预检 FAIL ⇒ 保留哨兵、不 kill 旧 web。旧实例可能有毛病,但它是在跑的;新实例没验证过。判据不是"能不能起来",而是"能不能加载完"(见 dsh-agent-preflight 的 grace 窗口)。
  • 单点所有权用落盘租约,不用内存锁:重启与保活是两个进程,内存锁跨不了进程。租约必须带 TTL(120s)——发起者崩溃不得把资源永久锁死;坏数据(损坏/时钟偏移)一律放行 + 落盘 issue,不静默也不死锁;让位必须写理由(否则下次事故仍回答不了「为什么多发了一条唤醒」)。
  • 唤醒目标是「用户会话」而非「最近更新的会话」:子代理会话是裸 uuid、不可 prompt,且「最近更新」常常就是它。判据严格取 session-* 前缀且非空白;显式锚点只在新鲜(≤10 分钟)时优先,滞后即判腐化并改投——锚点是锚点,不是真源。
  • curl.exe 不能用来发告警:实测经代理 CONNECT 成功但 TLS 必失败(exit 35,-k / --http1.1 / --tlsv1.2 各变体同样失败),同代理下 Node fetch 正常。这条是环境事实,不是偏好。
  • 告警不许静默失败:任何「本应发生但没发生」的分支都要落盘(if (!token || !chat) return + 空 on('error') 是反模式)——静默失败是死亡温床。
  • 模型可见 ⟺ 已记录:唤醒/通知走会话事件(session/prompt),不搞私有投递通道,否则「投过没有」无法从日志重建。
  • .sentinel-web-start.json 是刻意保留的取证面:它让「这次重启之后,跑的是哪个产物」变成一条 cat 能回答的问题——构建 vs 生效的判据就是它。

相关文档

文档内容
docs/semantic.md权威契约:定位与反定位、术语、概念模型与不变量、契约(含调用点清单)、边界与信任、可证伪验收清单、实践修订记录、未决问题
alice-digital-life本插件所属生态的中心索引(全部自研插件)
技能 guardian-lifecycle / guardian-robustness-audit / preventive-lifecycle / plugin-maintainability守护型进程的安全替换(先新后旧 / 验证再杀)、守护链健壮性审计清单、预防性存活、可维护性五问

License

MIT © jonah791


本插件属于我的数字生命爱丽丝(alice-digital-life)的 DSH 自研插件生态——50 个插件按生命/认知/感知/行动/通信/治理/呈现七层组织。

Comments

Loading…

Similar plugins

dsh-subagent-cursor

by NinjaSln-labs

DeepSeek Harness 插件:Cursor-as-subagent 提供方——一次本地 @cursor/sdk one-shot 运行、摘要优先结果、可无人值守的 Profile Bundle

Manifest valid

★ 0

↓ 353/wk

MIT

TypeScript

Sep 19, 2026

dsh plugin --profile web add dsh-subagent-cursor

by tianyaojiudi-prog

DSH(DeepSeek Harness) 插件:把一段可在设置页随时改写的文字,作为全局系统提示词段注入到所有会话,含子代理与工作流内部子代理;文本与开关即时生效,无需重启。

Tools & CapabilitiesManifest valid

★ 8

MIT

JavaScript

Oct 2, 2026

dsh plugin --profile web add dsh-djy-xttsc

by Ayle5678

一款DSH (DeepSeek Harness) 插件:类似 Claude Code 中 Auto Mode 的一种命令通过机制,给 dsh中的full access 加一层 LLM 安全网的自动审批插件。

Manifest valid

★ 0

MIT

TypeScript

Aug 26, 2026

dsh plugin --profile web add dsh-auto-guard

by bpc-oss

DeepSeek Harness plugin: subagent_routed — run a one-shot subagent fully mounted on ANY agent preset from ANY session, with per-call model/provider override and a model-availability pre-check.

Workflow & AutomationTools & CapabilitiesManifest valid

★ 3

MIT

JavaScript

Sep 12, 2026

dsh plugin --profile web add dsh-routed-subagent

by jkrandom-sudo

Security audit for DeepSeek Harness plugins: static permission profile with file/line evidence + a runtime sentinel gating credential access and unknown-host egress · DSH 插件安全审计:静态权限画像(附文件/行号证据)+ 运行时哨

Manifest valid

★ 4

↓ 154/wk

MIT

TypeScript

Sep 11, 2026

dsh plugin --profile web add dsh-plugin-audit

by 2768651338

DeepSeek Harness 的图形化插件管理插件:在 设置 → 插件 里新增「插件管家」标签页,用中文名和说明展示每个插件是做什么的,并提供一键启停开关与内置备注编辑——启停写入全局层补丁并实时热生效,备注保存到本地覆盖文件长期生效。

UI & ExperienceManifest valid

★ 8

MIT

JavaScript

Oct 1, 2026

dsh plugin --profile web add @2768651338/dsh-plugin-manager