会话运行期间阻止 Mac 空闲休眠,任务不中断
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/wjvalue/dsh-mac-keep-awake.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 29 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令
查看扫描证据(共 1 处,展示前 1 条)
- 执行外部命令来自配置/变量src/keep-awake.js:110
const child = spawn(argv[0], argv.slice(1), { stdio: 'ignore', detached: false })
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 阻止Mac空闲休眠
DeepSeek Harness 会话运行期间让 macOS 保持唤醒(不进入空闲系统休眠)· DSH 插件,会话进行时阻止 Mac 空闲休眠
README
由 DeepSeek 最新模型翻译生成dsh-mac-keep-awake
English: README.en.md
会话进行时不让 Mac 空闲休眠的 DeepSeek Harness 插件。
While any DSH session is running, hold a macOS power assertion so the machine does
not idle-sleep and interrupt the session.
它做什么
只要有任意一个 DSH 会话处于运行中,插件就持有一次 macOS 电源断言(PreventUserIdleSystemSleep);最后一个会话结束后立即释放。
- ✅ 会话跑长任务时,Mac 不会因为空闲而休眠,任务不会被打断
- ✅ 屏幕照常可以息屏(用的是 caffeinate -i,不是 -i -d),长时间跑不会一直亮着
- ✅ 多个会话只持有一个断言(按 session id 引用计数)
- ✅ DSH 进程崩溃也不会把电脑永久钉住(见下方 -w 说明)
工作原理
断言由子进程 caffeinate -i -w <DSH 主进程 pid> 提供:
| 参数 | 作用 |
| -i | 只阻止系统空闲休眠,不阻止屏幕息屏 |
| -w <pid> | 被监视的进程退出时,caffeinate 自己退出 —— 崩溃安全网 |
展开完整文档(README 剩余 1 节)
dsh-mac-keep-awake
English: README.en.md
会话进行时不让 Mac 空闲休眠的 DeepSeek Harness 插件。
While any DSH session is running, hold a macOS power assertion so the machine does
not idle-sleep and interrupt the session.
它做什么
只要有任意一个 DSH 会话处于运行中,插件就持有一次 macOS 电源断言(PreventUserIdleSystemSleep);最后一个会话结束后立即释放。
- ✅ 会话跑长任务时,Mac 不会因为空闲而休眠,任务不会被打断
- ✅ 屏幕照常可以息屏(用的是 caffeinate -i,不是 -i -d),长时间跑不会一直亮着
- ✅ 多个会话只持有一个断言(按 session id 引用计数)
- ✅ DSH 进程崩溃也不会把电脑永久钉住(见下方 -w 说明)
工作原理
断言由子进程 caffeinate -i -w <DSH 主进程 pid> 提供:
| 参数 | 作用 |
| -i | 只阻止系统空闲休眠,不阻止屏幕息屏 |
| -w <pid> | 被监视的进程退出时,caffeinate 自己退出 —— 崩溃安全网 |
| -d | (可选,默认关)同时阻止屏幕息屏 |
| -t <秒> | (可选,默认关)兜底超时,到点自动释放 |
断言断了怎么办:两条阶梯,都不终止
子进程有三种结束方式,含义完全不同:
| 结束方式 | 含义 | 处理 |
| error 事件 / 退出码非 0 | 这次尝试失败 | 失败阶梯 |
| 退出码 0 且无信号,且活够了 1 秒 | 正常结束(-t 到点就是这样),这一轮确实起到了作用 | 清零计数,1 秒后重新获取 |
| 退出码 0,但瞬间就退出,连续 3 次 | 可执行文件是坏的(比如指到 /usr/bin/true) | 升级到失败阶梯,避免空转 |
为什么用"活了多久"而不是只看退出码:maxHours 设得很短时,-t 会反复到点。
每一次都是功能在正常工作;如果按次数累计,三次之后就会把一份健康配置误判成故障—— 那正是最初 BUG 1 的同一类错误。(这是我自己修完 BUG 1 后引入、又自己抓出来的。)
失败阶梯是指数退避、上限 60 秒,而且永不终止:超过 3 次之后只把那条 error 打一次,然后继续按 60 秒的节奏重试。这样即使原因是暂时的(工具没装好、路径写错后又被修正),插件也会自己恢复,不需要任何状态变化来触发。
为什么不做成"放弃":会话还在跑、断言却永久没了,是最糟的结果 —— 而且旧实现里 reconcile 在集合没变时是空操作,一旦放弃就再也回不来。
(这正是独立验证时被抓出来的 BUG 1 + BUG 2。)
子进程活过 5 秒会被记为"健康",两条阶梯清零 —— 否则一次已经恢复的故障会让插件在下一次真的坏掉时保持沉默。该计时器带 generation 校验,过期的计时器不会误重置已经替换掉的子进程。
释放:SIGTERM → 2 秒 → SIGKILL
释放时先发 SIGTERM;2 秒内没确认退出就升级 SIGKILL,避免"控制器报告已释放、机器却还被钉着"。
待升级的句柄会被一直跟踪,而不是只跟踪计时器。 release() 会立刻把 child
置空,所以如果只跟踪计时器,dispose() 一旦把待触发的计时器清掉,那个忽略
SIGTERM 的子进程就永远不会被杀,插件事后还会报告"全部已释放"。
因此 escalations 存的是 { handle, timer }。
这是独立验证抓出来的第 4 个真实缺陷(BUG 3 的补丁没覆盖到 teardown 路径)。
dispose() 对未决升级两者都不做
发现上述缺陷后,第一版修法是 flushEscalations():dispose 时对未确认退出的句柄 立刻补发 SIGKILL。但独立验证马上又抓出这个修法自己的问题 ——
exited() 要等异步的 exit 事件落地才为真,所以一个守规矩的子进程在自己
的宽限窗口里仍然读作"活着",于是被白白补了一发 SIGKILL(真机 10/10 复现)。
所以现在 dispose() 既不取消、也不强制执行这些计时器,而是*让它们按原定时间
自己触发(settleEscalations() 是个有意的空实现):
- 到点时会重新检查 exited();
- 守规矩的子进程已经退出 → 不补信号;
- 忽略 SIGTERM 的子进程仍然没退出 → 照常 SIGKILL。
计时器都是 unref() 的,不会拖住进程;即使宿主在这之前退出, caffeinate -w <host pid> 仍是最后一道保险。
两个"显而易见"的写法都是错的,而且都是被独立验证抓出来的 —— 这是
settleEscalations() 里那段注释存在的意义:防止以后有人把它"清理"回去。
信号与对账
1. agent/status —— 权威的每会话 running/idle 转换,由 agent loop 自己发出。
事件虽是 agent 作用域的,但本插件从根级别加载(上下文未打 scope 标签), cordis 的 scope 载体过滤器会放行未打标签的监听者,所以不加 { global: true } 也能收到。监听时仍然带上该选项,作为廉价保险:万一未来 loader 把宿主插件放进 agent 作用域内加载,普通监听会被过滤掉,带了这个选项不受影响。
(实证:用本机 app 内的 cordis 4.0.4 + dsh-scope 复核过;宿主自带的 api-session-controller / compaction-basic / agent-team / subagent 监听同样的事件时都没传这个选项。)
2. agent/disposed —— 会话在仍被标记为 running 时被销毁的兜底释放(同样带上 { global: true },理由同上)。
3. session/event 里的 compaction/start … compaction/end —— 补 maintenance 盲区,见下。
4. 周期性对账 ctx.agents.list() —— 兜住事件覆盖不到的情况:插件热重载时已经在运行的会话,或者 fiber 被替换期间漏掉的 idle 转换。
对账是权威的(整体替换集合),所以既能获取也能释放;同时把仍开着 compaction 括号的会话并进去(注册表看不见它们)。
为什么必须有对账:插件热重载(patchReload: live)后,如果没有对账,它会一直空等到下一个回合边界才可能拿到断言 —— 而「刚装上插件」正是最需要它的时刻。
计数以 session id 存进 Set,所以同一个会话重复收到 running 永远不会把计数抬高。
Host 另外还会广播 api-session/status,但故意没有订阅:它就是由 agent/status 在同一次派发里派生的,订阅它只会多一条永远不可能产生分歧的代码路径。
maintenance 盲区(已覆盖)
Agent.status 对 idle 和 maintenance 两个阶段都返回 'idle':
get status() { return this.phase.kind === 'idle' || this.phase.kind === 'maintenance' ? 'idle' : 'running' }
而手动 /compact 正是跑在 runMaintenance 里的。这台机器用电池时 60 秒就休眠,所以一个长时间 compaction 如果被当成 idle,就是一个真实的休眠窗口; agent/status 也看不到它(只在状态变化时才发,idle→maintenance 不算变化)。
由于没有公开的 phase 访问器,插件改为订阅持久化的 compaction/start / compaction/end 括号:括号开着就一直持有断言。自动压缩(在 agent/pre-step 里跑)本来就处于 running,不需要这条;它只为手动 /compact 补位。
括号若因崩溃永不闭合:maxHours(若配置)或下一次对账会收敛,因为对账对「非压缩中的会话」是权威的。
配置
在 profile 的 cordis.patch.yml 里覆盖这一行的 config:
- id: keep-awake
name: 'dsh-mac-keep-awake'
config:
enabled: true # 总开关 preventDisplaySleep: false # true = 屏幕也不息屏(加 -d) maxHours: 0 # >0 = 兜底超时(小时),到点自动释放 reconcileSeconds: 60 # 对账间隔;0 = 关闭对账 executable: /usr/bin/caffeinate
安装
1. 打包并暂存到 profile 的 vendor/ 目录
node scripts/install.mjs
2. 用 DSH 插件管理器装(desktop profile 只能由 Electron 应用管理) spec: file:vendor/dsh-mac-keep-awake-1.4.1.tgz
安装后 bundle 自带的 cordis.patch.yml 会插入 Host 半身; patchReload: live 意味着改完 src/ 重新安装即可生效,无需重启应用。
验证
node --test test/.test.js
- test/keep-awake.test.js —— 34 个单元测试,注入假 spawn 与可控时钟,验证计数与阶梯逻辑:重复事件、交错 enter/leave、对账与事件竞争、过期回调不能复活句柄、正常退出(退出码 0)不算失败、带信号退出仍算失败、反复的正常到期不会升级、瞬间正常退出会升级、失败阶梯不终止且能自愈、健康计时器重置阶梯、过期健康计时器不误重置、 SIGTERM 无效时升级 SIGKILL、dispose 不会漏掉还在宽限期里的子进程、非 darwin 平台降级。
- test/wiring.test.js —— 15 个接线测试,用假 cordis ctx 验证 index.js: { global: true } 回归守卫(验证每个 agent 事件恰好注册一次且带该选项)、热重载时对已在运行的会话立即获取、malformed payload 不抛异常、手动 /compact 期间仍持有断言、对账不会丢掉开着的 compaction 括号、压缩中被销毁的会话不会永久钉住机器、以及「不留下任何 caffeinate 进程」。
- test/integration.pmset.test.js —— 2 个真机测试,直接读内核账本 pmset -g assertions:断言真的出现、真的只有一个、真的在最后一个会话结束时消失;以及被监视进程被 SIGKILL 后 caffeinate 自行退出。
手工确认真机状态:
pmset -g assertions | grep -A2 caffeinate
pid 89135(caffeinate): ... PreventUserIdleSystemSleep named: "caffeinate command-line tool"
Details: caffeinate asserting on behalf of Process ID 87704
pgrep -fl "caffeinate -i -w"
会话跑完后再执行一次,应当什么都不输出。
平台支持
仅 macOS(caffeinate 是 macOS 专有工具)。其他平台上插件会正常加载但只打一条 warning,不持有任何断言,也不会报错 —— 它不会让 DSH 起不来。
目录
index.js # Host 半身:事件接线、对账循环、Config src/keep-awake.js # 引用计数控制器(纯逻辑,可注入) test/keep-awake.test.js # 控制器单元测试(假 spawn) test/wiring.test.js # index.js 接线测试(假 cordis ctx + 真 pmset) test/integration.pmset.test.js# 真机 pmset 集成测试 cordis.patch.yml # bundle patch:一行 insert 挂载 Host 半身 scripts/install.mjs # 打包 + 暂存到 profile vendor/
License
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
wjvalue/dsh-mac-keep-awake
会话运行期间阻止 Mac 空闲休眠,任务不中断
相关插件 · 其他
模型破甲清洗YuJunZhiXue/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 14,822已汉化DeepSeek 客户端
73
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 718已汉化DSH
71.2
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,261已汉化DSH
70.7
破甲评测WoYun520/dsh-purge
在本机分离宿主拦截与模型拒绝,做受控红队评测
★ 199已汉化DSH
69.7