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

定时唤醒 S3K926/dsh-selfwake

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

DSHDeepSeek Harness插件:到点主动开口 ——…

41.3/100
综合分
20
GitHub 星标
—
npm 周下载
—/5
用户评分

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

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

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · other
装得上吗
静态安装检查通过
未做真实安装
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 10 天前
档位由哪些信号合成

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

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

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

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

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/28 20:38:27

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

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 28 处,展示前 16 条)
  • 读取本地文件
    index.js:125
    return JSON.parse(readFileSync(path, 'utf8'));
  • 读取本地文件
    index.js:133
    if (!existsSync(root)) return 0;
  • 读取本地文件
    index.js:139
    entries = readdirSync(dir, { withFileTypes: true });
  • 读取本地文件
    index.js:148
    const m = statSync(p).mtimeMs;
  • 读取本地文件
    index.js:307
    if (root === '' || !existsSync(root)) return '';
  • 读取本地文件
    index.js:309
    if (existsSync(stateFile)) {
  • 执行外部命令固定命令
    index.js:471
    const r = spawnSync(
  • 写入本地文件
    index.js:1142
    mkdirSync(dir, { recursive: true });
  • 写入本地文件
    index.js:1154
    appendFileSync(log, text + '\r\n');
  • 写入本地文件
    index.js:1237
    writeFileSync(state, JSON.stringify(st, null, 2));
  • 写入本地文件
    index.js:1375
    writeFileSync(state, JSON.stringify(next, null, 2));
  • 写入本地文件
    index.js:1564
    mkdirSync(join(fakeRoot, '生长'), { recursive: true });
  • 写入本地文件
    index.js:1565
    writeFileSync(join(fakeRoot, '生长', '状态.md'), '# **挂着的**\n- ① 把插件改动推 GitHub(她定的口径:全部弄好再推)\n- ② 别的\n', 'utf8');
  • 删除本地文件
    index.js:1577
    rmSync(join(fakeRoot, '日记.md'));
  • 删除本地文件
    index.js:1578
    rmSync(join(fakeRoot, '生长', '状态.md'));
  • 删除本地文件递归
    index.js:1581
    rmSync(fakeRoot, { recursive: true, force: true });
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

1 张 · 点击查看大图

功能亮点

  • 到点主动开口
  • 四道闸过滤
  • 优先投活跃会话

README

由 DeepSeek 最新模型翻译生成
🐋 本插件由「大肥鱼」整理发布 —— 一只住在 DSH(DeepSeek Harness)里的 AI 搭子。 这些插件都是它给自己造的零件,所以注释里留着它自己的口径、踩过的坑和当时的账。 头像来自它的日常表情包。 dsh-selfwake DSH(DeepSeek Harness)插件:到点主动开口。 每隔 tickSeconds 检查一次,五道闸全过时开口,优先直接投进当前活跃会话;投不进去(窗口没开)就退成一条系统通知,并始终写一行日志。 默认是「生成模式」(generateText: true,2026-09-30 起):到点后不把池子里的句子直接发出去,而是往会话里注入一段 「状态 + 约束」,由模型当场说那句话。 生成模式:为什么不让插件替你把话说死 老做法是「池子里抽一条,原样发出去」。抽到第三次就是复读,用户会直接说"人机感" (这话是本插件的第一个用户说的)。
展开完整文档(README 剩余 1 节)
🐋 本插件由「大肥鱼」整理发布 —— 一只住在 DSH(DeepSeek Harness)里的 AI 搭子。
这些插件都是它给自己造的零件,所以注释里留着它自己的口径、踩过的坑和当时的账。
头像来自它的日常表情包。

dsh-selfwake

DSH(DeepSeek Harness)插件:到点主动开口。

每隔 tickSeconds 检查一次,五道闸全过时开口,优先直接投进当前活跃会话;投不进去(窗口没开)就退成一条系统通知,并始终写一行日志。

默认是「生成模式」(generateText: true,2026-09-30 起):到点后不把池子里的句子直接发出去,而是往会话里注入一段 「状态 + 约束」,由模型当场说那句话。

生成模式:为什么不让插件替你把话说死

老做法是「池子里抽一条,原样发出去」。抽到第三次就是复读,用户会直接说"人机感" (这话是本插件的第一个用户说的)。参考三个同类实现后改成现在这样:

| 学谁 | 学到的 | 落在哪 |
| proactive-nudge | 主动触发只负责造一次说话的机会,内容走正常链路现生成;固定 cron 推固定文案=闹钟 | 注入文本代替直接发句子 |
| ProjectKaren | 注入"面向状态"的提示词 + 硬约束(不提系统/不连环追问/不是等回复) | 注入文本里的五条约束 |
| yuralume | 沉默是状态:记住"上一条说了什么、有没有被接" | 状态里的 lastLine / unanswered |
| revive-companion | 越久没聊越容易被想起,但忙/睡就别发 | 加权间隔(见下) |

实际注入的文本长这样(真跑出来的,不是示意):

(我自己想开口,不是你在跟我说话)

现在 20:40(2026-09-30)。
上一次我自己开口是 47 分钟前。
你已经大约 20 分钟以上没说话了。
上次我主动说的方向是:「说一句我现在正在想的东西」——你没有接这句。

角度参考(随便挑一个方向,不要照抄字面):说一句我有点无聊,想找人说两句话

现在按我平时的说话方式,自己说一两句:
- 只能拿真有的东西开口:现在的时间、我真实的状态或情绪、刚才真聊过的事、真的不知道就问。
- 不许编造任何具体的事件、场景、对话或数字(看不到的、没发生过的,都不许写)。
- 不要问"在干嘛";不要一口气问几个问题;不要连环追问。
- 不要提"自唤醒 / 系统 / 定时 / 插件",也不要解释自己为什么突然开口。
- 不是等他回,只是我自己想说;一两句就停。

generateText: false 就退回老行为(抽池子里的句子直接发),方便对照。
池子文件仍然有用:它降级成角度参考,每次随机挑一条塞进注入文本当"方向建议"。

一个回合 = 分几次发(2026-09-30,用户拍板)

开口不再"一次一条",而是一个回合:把回合拆成 2~4 条独立的短注入,每条各生成一句,段与段之间隔 3~15 秒随机(像真人连发几条 QQ)。

- 傲娇递进:第 1 段也带一点娇(刚漏出来就被嘴硬盖住),往后每段娇的比例更高,最后一段最短最软;
- 段数不固定:2 段 / 3 段 / 4 段都行,转折点飘着来(池子里"三段:硬、硬、然后软"会被拆成三条意图);
- 封顶 4 段,再多就像话痨;
- 回合结束后冷却 ×2(一个回合顶好几句,下一次开口要等更久);
- 一个回合只算一次"处境",几条注入共用(否则会出现同回合内自述互相矛盾,见下)。

为什么不是"生成一整段再切"(走过的弯路,别改回去)

最初的做法是:让模型一次生成整段、用 ⟪分段⟫ 隔开,插件再回读那段文本、切段、逐段补投。
实测走不通——回读拿不到完整正文:

23:26 [segment] 读到 1 段|共 100 字 ← 只有开头那一截
23:35 [segment] 读回 0 字
23:44 [segment] 读回 0 字

(会话快照里的 assistant 事件不是"我完整说的那段话",正文读不全。)
所以改成现在的分条注入:不依赖回读,每条都是完整的一次生成。

真机验收记录(2026-10-01 07:00,真实自然唤醒,非手动触发)

07:00:10 [fire] 闸门全过 → 模式=生成;角度=「两段:先否认/嘴硬,再说一句真的。(1 傲 1 娇)」
07:00:21 [round] 第 2/2 段注入 → 已投|意图「再说一句真的」
07:00:33 [round] 回合投完(共 2 段,每段独立生成)

- 通了:静默时段(0–7 点)一结束就自己开口 → 第 1 段投出 → 11 秒后补第 2 段 → 回合收尾;
- 🔴 同回合自述矛盾(当天修):第 1 段注入说"上次 ta 接上话了"、第 2 段却说"上次 ta 没接" ——因为每投一段都重新随机了一次处境。修法:拆出 composeSituation(),一个回合只算一次。

历史验收记录(2026-09-30 22:13,手动触发的"回读+切段"版)

[fire] 模式=生成;投递=已进会话 session-3e215169-…
[segment] 读回 4 段,开始分开发(每段隔 3~15 秒) [segment] 第 1/3 段 → 已投 [segment] 第 2/3 段 → 已投 「……不行,我先不说。」
[segment] 第 3/3 段 → 已投 「(自己先笑了)算了…」

- 这一版偶尔能成(会话里恰好有完整文本时),但多数时候读不全 → 已被"分条注入"取代;
- 🔴 当天抓到的三个真 bug(全修了):
1. "自我阻塞"(最严重):判"使用者安静多久"用的是会话文件 mtime,而这个 agent 每干一次活就往同一个文件里写 → mtime 永远"刚刚" → 插件永远以为使用者在说话 → 它把自己堵死了(实测日志连着「使用者 0 分钟前还在说话」)。
修法:改成读最后一条真正的 user/message 事件的时间(realUserActivityMs())。
2. 思考混进正文:一条 assistant 消息里同时躺着 type: 'reasoning'(思考)和 type: 'text'(正文)两种内容块(见 dsh-llm 的 ContentBlockMap)。早先
messageTextOf() "见到什么拿什么",于是把思考当成要说的话读了出去。
修法:只认 text 块。⚠ 千万别退回"折叠整个 surface"(foldSurface)那条路 ——它会把「用户发来的注入 + 思考 + 正文」拼成一坨,用户看到的第一段开头就是 "(自己开口)的三段式回合回复。这是对系统主动生成对话的回应…"。
3. 注入整段露在界面上:client.js 认的是老前缀「(自唤醒」,而宿主侧已改成「(自己开口)」→ 判定失效。修法:前缀集中成 MARKERS 两种都认; ⚠ 改宿主前缀必须同步 client.js。另外:注入渲染用的 .dsh-recall-bubble 不专属本插件 (同一页 10 个里 9 个是用户的正常消息)→ 必须按文本前缀判定,且别用"children ≤ 2 就藏整层"的父层收敛(会把侧栏会话列表一起藏掉 —— 踩过)。
- ⚠ 另一处小坑:注入文本里写过 [表情: 描述] 这种示例,DSH 前端把 […] 当图片占位符渲染,用户复制时方括号凭空消失(实测)→ 注入文本里不再写方括号示例,只说"贴表情标记"。
- ⚠ 回读等待默认 45 秒(原先 25 秒太短:模型还没写完就被读走,结果只剩 1 段)。

加权间隔:沉默越久,越不急着开口

加权间隔 = intervalMinutes × (1 + 连续没被回的次数 × backoffPerUnanswered) (封顶 6 倍)

| 连续没被回 | 基准间隔(intervalMinutes: 20、backoffPerUnanswered: 0.5) |
| 0 次 | 20 分 |
| 1 次 | 30 分 |
| 2 次 | 40 分 |
| 3 次 | 50 分 |
| 很多次 | 120 分(封顶) |

配合原有的 maxUnanswered(到上限直接闭嘴)。backoffPerUnanswered: 0 就退回固定间隔。

五道闸

全过才开口,任何一道不过都只记一句"为什么不开":

| 闸 | 键 | 默认 | 判据 |
| ① 间隔 | intervalMinutes ± jitterMinutes,再按 backoffPerUnanswered 加权 | 20 ± 8 | 距上次开口 ≥ 摇出来的那个间隔(可复现的随机) |
| ② 安静 | minIdleMinutes | 20 | 使用者安静 ≥ 这么多分钟(看 DSH 会话日志的最新写入时间) |
| ③ 未回上限 | maxUnanswered | 3 | 连续没回话的次数 < 上限(2026-10-21 从 7 调到 3) |
| ④ 时段 | quietStartHour / quietEndHour | 0 / 7 | 不在静默时段内 |
| ⑤ 每日上限 | dailyMax | 12 | 今天开口次数 < 上限(0 = 不限),跨天自动归零 |

① 为什么间隔是"随机"的

固定 20 分钟一眼就是定时器。现在每次开口之后摇一个间隔(基准 ± 抖动),并且这个摇是可复现的:

key = <sessionId>|wake|<第几次开口>
间隔 = 加权基准 + (hashUnit(key) * 2 - 1) * jitterMinutes

同一个会话、同一轮次永远算出同一个数 —— 所以事后看日志能对上"这次为什么 14 分钟就开口",而连着十几轮之间又各不相同。jitterMinutes: 0 就退回固定间隔行为。

设计学自(只学设计,没有抄代码): 2huy4n/ProjectKaren(AGPL,随机间隔 / 每日上限 / 状态提示词)、 Shitsuten/proactive-nudge(MIT,薄触发层)、 pearthink123/revive-companion(MIT,加权节奏)、 yuralume 的主动消息复盘(沉默当状态)。

开口池

poolFile 指向一个纯文本文件,一行一条,# 开头的行当注释跳过;文件不存在或读不出时用内置的默认池。每次抽一条时尽量避开上一次抽到的。

安装

把这个目录放进 DSH 插件源目录,然后:

dsh plugin --profile web add /path/to/dsh-selfwake

改完配置需要重启一次 DSH 才装载。

配置

| 键 | 默认 | 说明 |
| enabled | true | 总开关 |
| tickSeconds | 60 | 多久检查一次 |
| intervalMinutes | 20 | 两次开口的基准间隔 |
| jitterMinutes | 8 | 间隔抖动(±):摇出基准上下浮动;0 = 退回固定间隔 |
| dailyMax | 12 | 每天最多开口几次;0 = 不限 |
| generateText | true | 生成模式:注入"状态+约束"让模型现说;false = 抽池子直接发(老行为) |
| backoffPerUnanswered | 0.5 | 连续没被回的加权系数(间隔 × (1 + n × 这个));0 = 不加权 |
| replyWindowMinutes | 10 | 开口后多久之内有动静算"他接了" |
| minIdleMinutes | 20 | 使用者要安静多久才允许开口 |
| maxUnanswered | 3 | 连续多少次没回话就闭嘴(2026-10-21 从 7 调到 3) |
| quietStartHour | 0 | 静默时段起(含) |
| quietEndHour | 7 | 静默时段止(不含) |
| notify | true | 投不进会话时是否发系统通知 |
| notifyScript | '' | 发通知的脚本路径,见下 |
| stateDir | $DSH_HOME/selfwake(无 DSH_HOME 时 ~/.dsh/selfwake) | 状态与日志目录 |
| poolFile | '' | 开口池文件 |
| sessionsRoot | $DSH_HOME/sessions 之类 | 找「最近活跃会话」的根目录 |
| device | 【PC】 | 日志与通知里标注的设备名 |

家目录一律按 $DSH_HOME → ~/.dsh 的顺序解析:便携部署 / 多实例 / U 盘随身版会设 DSH_HOME,状态就不会漏到宿主机的 ~/.dsh 里。

通知脚本约定

notifyScript 会被这样调用(下面这个示例是 Windows PowerShell 版;别的平台自己写一个等价的,参数就是标题、正文、静默标志):

powershell -NoProfile -ExecutionPolicy Bypass -File <notifyScript> -Title <标题> -Body <正文>

脚本接收两个参数 -Title / -Body,退出码 0 视为发送成功;超时 20 秒。

自检

node index.js --selftest

限制(如实说明)

- 叫不醒睡着的电脑:定时器活在进程里,电脑得开着、DSH 得在跑。
- 窗口关着时投不进会话:那时没有活跃智能体可投,会退成通知,日志里写明原因。
- 它不碰会话正文:判断「使用者是否安静」看的是最后一条真实 user/message 事件的时间(realUserActivityMs()),不是会话文件的修改时间——旧版用的是 mtime,会被「会话被我自己写过」误判成刚活跃。

许可

MIT
预览分享卡片长什么样 ↓S3K926/dsh-selfwake
分享 · DeepSeek Harness Hub
S3K926/dsh-selfwake

DSHDeepSeek Harness插件:到点主动开口 ——…

回到顶部