Show HN: Adrafinil – 仅在代理工作时保持 Mac 清醒

Hacker News Top 工具

摘要

Adrafinil 是一款 macOS 工具,仅在 AI 代理活跃时保持系统唤醒,在代理会话期间阻止休眠,同时允许其他时候正常睡眠。

一个月前,有一波帖子和推文提到工程师们把 MacBook 半开半合地放在咖啡馆和公园里,因为完全合上盖子会强制休眠,从而中断他们的 AI 代理。有人用 tmux 或 Amphetamine 开玩笑,也有人为自己的选择辩护:“但我只是偶尔需要它,而且忘记禁用 Amphetamine,结果发现笔记本电脑在包里没电了,更糟糕。”<p>这是针对该问题的解决方案。与 caffeinate 不同,它即使合上盖子、没有外接电源或显示器,也能阻止 MacBook 进入休眠,通过 pmset disablesleep 1 实现。与其他防止休眠的应用不同,Adrafinil 仅在代理主动执行任务时激活。它通过安装到 Claude Code、Codex 等工具中的钩子检测代理活动。为了让您放心它正在工作,该应用在菜单栏中显示活动状态,并在合上盖子时播放提示音。<p>一旦代理完成工作,Adrafinil 会检测到并将 pmset disablesleep 重置为 0,让笔记本电脑进入休眠。如果温度过高,它也会让笔记本休眠。如果您想手动切换,可以安装可选的 MCP 并告诉您的代理让 MacBook 保持唤醒特定时间。<p>它包含四个二进制文件,其中一个是 root helper,暴露出一个简单的 setSleepBlocked 调用。所有逻辑和策略都在非特权部分运行。它们都经过公证,应用完全开源(MIT)。
查看原文
查看缓存全文

缓存时间: 2026/06/27 21:54

kageroumado/adrafinil 来源:https://github.com/kageroumado/adrafinil adrafinil (https://kagerou.glass) # adrafinil 处方编号 006 ・ ad·raf·i·nil /əˈdræfɪnɪl/ ・ 针对机器的清醒剂 ♡ kagerou.glass (https://kagerou.glass/adrafinil/) @kageroumado (https://x.com/kageroumado) macOS Tahoe 系统要求 清醒 ・ 某个代理正在工作 睡眠 ・ 无代理,正常睡眠 > 服用注意 ・ 用于在你入睡后仍值守的机器。 > > 凌晨3点。你已入睡。但代理没有——它仍然在你几小时前发起的会话中思考,你合上了盖子,就像一只无法完全闭合的眼睑。caffeinate 和 Amphetamine 是兴奋剂:它们让机器永远保持连线状态,无论是否有人在使用。Adrafinil 则不同,它是一种清醒剂。在代理获取它之前什么也不做,仅在需要工作时让你的 Mac 在合盖后保持唤醒,一旦最后一个会话释放便立即解除。它只为工作而醒——然后你们一起入眠。♡ — 让你的 Mac 仅在 AI 代理工作时保持唤醒。Adrafinil 是一个 macOS 菜单栏应用,它仅在 AI 编码代理拥有活跃会话期间阻止系统休眠——包括合盖(盒盖)休眠。当没有代理工作时,休眠行为不受影响:合上盖子,Mac 正常休眠。这与 caffeinate 或 Amphetamine 这类始终开启的唤醒工具相反。Adrafinil 只在代理(Claude Code、Codex、Cursor 等)处于任务中时介入,并在工作完成后立即退出。 > ⚠️ 特权休眠控制。 覆盖合盖休眠需要 root 权限。Adrafinil 将这一功能隔离在一个小巧且可审计的帮助进程中,该进程仅暴露 setSleepBlocked(Bool)——所有策略决策都位于一个非特权守护进程中。它使用标准的 IOPMAssertion 控制空闲休眠,并在验证设备上较新的私有 IOPMrootDomain 路径无法让无显示器的合盖 Mac 保持唤醒后,使用 pmset disablesleep 控制合盖休眠。详见 Docs/ARCHITECTURE.md §2。 ## 功能特性 - 感知代理,而非始终开启。 仅当至少一个代理会话持有断言时才阻止休眠。零个会话→正常休眠,包括合盖。 - 支持 9 种代理的 Hook 集成。 一键安装器可将 Adrafinil 接入 Claude Code、Codex、Cursor、Gemini CLI、Aider、Hermes、OpenCode、Cline 和 Pi 的 hook 系统。 - 亚 50ms CLI。 adrafinil acquire / release 由代理 hook 调用,往返守护进程的时间小于 50ms,因此不会延迟代理的工作流。 - 引用计数的断言。 重叠的会话会干净地堆叠;仅当最后一个会话释放时才会解除休眠。 - 温度切断。 如果合盖状态下外壳/CPU 温度超过阈值,所有断言将被强制释放,以防止包中的 Mac 过热。 - 空闲释放。 如果拥有断言进程已死亡或 CPU 空闲超过 N 分钟,断言会自动丢弃。 - 进程嗅探(可选)。 即使未安装 hook,守护进程在看到已知的代理二进制文件运行时也可自动获取断言。 - 合盖音频提示 + 开盖摘要。 合盖时(屏幕已关闭,因此无通知)会播放提示音以确认断言已持有;重新开盖时显示你离开期间运行的内容、峰值温度以及是否触发了温度切断。 - 干净卸载。 移除它在所有代理配置中添加的每个 hook 条目。 ## 系统要求 - macOS Tahoe 26.4。 这是我构建和测试的版本;可能在更早的 26.x 上也能运行,但我未在该环境中测试。 - Xcode 26+ 用于构建,需启用 Swift 6 严格并发。 - 标准安装需要管理员权限(特权帮助进程通过 SMAppService 安装)。非管理员安装路径会将 CLI 放入 ~/.local/bin 而非 /usr/local/bin。 ## 下载 下载 Adrafinil (https://github.com/kageroumado/adrafinil/releases/latest) —— 一个已签名并公证的磁盘映像。打开它,将 Adrafinil 拖入应用程序文件夹,然后启动。首次启动会请求一次管理员权限以注册特权帮助进程。需要 macOS 26.4 或更高版本。更倾向于自行构建?请参阅 构建。 ## 构建 sh git clone https://github.com/kageroumado/adrafinil.git cd adrafinil open Adrafinil.xcodeproj 在 Xcode 中,选择 Adrafinil scheme 并运行。你需要设置一个开发团队用于代码签名——守护进程(LaunchAgent)和帮助进程(LaunchDaemon)内嵌在应用 bundle 中,并在应用启动时向系统注册。(源码中未内嵌任何 Team ID;XPC 调用者检查在运行时读取你自己的签名团队,因此使用任何开发者 ID 重新构建后,其自身组件无需修改代码即可获得授权。) 如需无本地签名身份的无头编译检查: sh xcodebuild -project Adrafinil.xcodeproj -scheme Adrafinil -configuration Debug \ -destination 'generic/platform=macOS' \ CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY='' build 共享逻辑可作为一个 Swift 包独立构建和测试: sh cd AdrafinilShared swift test ## 工作原理 代理不直接与 Adrafinil 通信。每个代理的 hook 系统调用捆绑的 CLI: sh adrafinil acquire --tool claude-code --reason "long build" # 当一轮交互开始时 adrafinil release # 当代理进入空闲状态 持有是活动范围而非会话范围:Claude Code 在 UserPromptSubmit 时获取,在 Stop 时释放,因此 Mac 仅在代理实际工作时保持唤醒——打开的但空闲的会话会让它正常休眠。守护进程按会话键进行引用计数,并在计数非零时请求帮助进程阻止休眠。代理还可以通过一个有时限的持有来让 Mac 保持唤醒以执行超出回复时长的后台任务(如长时间构建或部署)——可以直接调用 adrafinil hold,或者对于支持 MCP 的代理,通过捆绑的 MCP 工具(由 adrafinil mcp 提供): sh adrafinil hold --for 30m --reason "deploy" # 最多保持唤醒 30 分钟,然后自动释放 adrafinil mcp # 通过 stdio 提供 Model Context Protocol(供代理使用) 其他子命令:statusinstall-hooksuninstall-hooksdaemon-statusversion。 ## 架构 四个产品,三个特权层级(完整细节,包括 Xcode 项目布局,请参阅 Docs/ARCHITECTURE.md): ┌──────────────────────────────────────────────────────────────┐ │ Adrafinil.app(菜单栏应用,面向用户) │ │ • 状态项、设置、安装程序 GUI、开盖摘要 │ └─────────────────────────────┬────────────────────────────────┘ │ XPC ▼ ┌──────────────────────────────────────────────────────────────┐ │ AdrafinilDaemon(LaunchAgent,以用户身份运行,常驻) │ │ • 引用计数的断言注册表 │ │ • 进程监视器(kqueue NOTE_EXIT + 定期扫描) │ │ • 温度监控(SMC) • 盖子状态监控(IORegistry) │ │ • 合盖提示音 • CLI 套接字位于 .../Adrafinil/cli.sock │ └─────────────────────────────┬────────────────────────────────┘ │ XPC(特权 Mach 服务) ▼ ┌──────────────────────────────────────────────────────────────┐ │ AdrafinilHelper(SMAppService LaunchDaemon,root 权限) │ │ • 唯一接触休眠阻止 API 的组件 │ │ • setSleepBlocked(Bool) + 只读状态/版本 │ │ • 验证调用者的代码签名要求 │ └──────────────────────────────────────────────────────────────┘ adrafinil(CLI,内嵌于 .app 中,符号链接到 PATH) • acquire / release / hold / mcp / status / install-hooks / uninstall-hooks • 连接到守护进程套接字;往返时间 <50ms - AdrafinilShared —— 一个跨所有目标共享的 Swift 包:数据模型(AgentKindAssertion)、IPC 线格式、AssertionRegistryCallerVerifier、hook 安装规范以及 CLI 参数解析器。单元测试针对此包。 - 帮助进程保持极简,便于审计。 它不包含任何策略——引用计数、温度、空闲和盖子逻辑全部位于守护进程中。特权界面只有一个可变端点加上只读内省功能。 - 守护进程是真理之源。 应用是一个纯视图层;它可以自由退出和重新启动,而不影响已持有的断言。 ## 已知的怪异之处 - 公开的 IOPM 断言无法击败合盖休眠。 使用公开类型(以及 caffeinate)的 IOPMAssertionCreateWithName 无法让合盖的 Mac 保持唤醒。Adrafinil v1 使用 pmset disablesleep 1,这种做法的副作用是它也会禁用空闲休眠,并且必须在关机时清除,否则会泄漏——帮助进程在重新生成后,会在重新应用状态之前重置为 disablesleep 0。 - 守护进程处理程序在任意队列上运行。 XPC 和套接字回调可能在任何 dispatch 队列上到达,因此断言注册表和共享状态会相应地进行同步。修改守护进程时请小心处理并发。 - CLI 有延迟预算。 acquire/release 处于每个代理会话的热路径中,因此使用静态查找(例如 AgentKind.allBinaryNames)和轻量套接字协议,而非完整的 XPC 用于 CLI ↔ 守护进程的通信。 ## 许可 MIT。随心所欲,不提供担保。 ## 致谢 由 @kageroumado (https://x.com/kageroumado) 构建,在 kagerou.glass (https://kagerou.glass) 分发。名称灵感来源于 adrafinil (https://en.wikipedia.org/wiki/Adrafinil) —— 一种促进清醒的前体药物——因为该应用仅在机器实际有工作时才让其保持唤醒。

相似文章

Ajar

Product Hunt

Ajar 是一款 Mac 实用工具,为 AI 代理提供屏幕角度同步和保持唤醒功能。

Whirr

Product Hunt

Whirr 是一款 macOS 桌面工具,可直接在 MacBook 屏幕刘海中实时展示 AI 智能体的活动。

HyperSleep

Product Hunt

HyperSleep 是一款产品,可以阻止社交媒体访问,直到你真正入睡,帮助用户养成健康的睡眠习惯。