@ruan-cat/claude-notifier
0.9.0
Minor Changes
🔧 修复 Stop Hooks stdin 竞争问题,优化任务管理架构 (
f9c7290) 新增功能
1. 新增独立任务删除脚本
新增
src/scripts/remove-task.ts,可被 tsx 直接调用,用于在 Bash 脚本中删除任务:bashtsx packages/claude-notifier/src/scripts/remove-task.ts /path/to/project特性:
- ✅ 接受 cwd 作为命令行参数
- ✅ 2 秒超时保护
- ✅ 详细的成功/失败日志
- ✅ 不依赖 stdin,避免竞争
2. check-and-notify 支持环境变量
check-and-notify命令现在优先使用环境变量获取数据,避免 stdin 竞争:bash# 支持的环境变量 CLAUDE_CWD # 当前工作目录 CLAUDE_HOOK_EVENT # Hook 事件名称 CLAUDE_STOP_HOOK_ACTIVE # Stop hook 是否激活数据获取优先级:
- 环境变量(优先)
- stdin(fallback)
重要改进
1. Stop 事件自动跳过
check-and-notify现在会自动检测并跳过 Stop/SubagentStop 事件:typescript// 环境变量拦截(第一重防护) if (envHookEvent === "Stop" || envHookEvent === "SubagentStop") { log("⚠️ check-and-notify 不应该在 Stop 钩子中被调用"); return; } // stdin 拦截(第二重防护) if (hook_event_name === "Stop" || hook_event_name === "SubagentStop") { log("⚠️ check-and-notify 不应该在 Stop 钩子中被调用"); return; }2. 优化日志输出
- 详细的环境变量检查日志
- 数据来源追踪(环境变量 vs stdin)
- 更清晰的警告和错误信息
破坏性变更 ⚠️
不再在 Stop Hooks 中使用 check-and-notify
原因:
多个钩子竞争读取 stdin 流,导致:
- ❌ 后续钩子无法获取数据(500ms 超时返回 null)
- ❌ 任务删除逻辑无法执行
- ❌ 已完成的任务持续触发 6 分钟、10 分钟的长任务提醒
修复方案:
任务删除现在由
task-complete-notifier.sh直接调用remove-task.ts完成:bash# task-complete-notifier.sh 中的新逻辑 tsx "$MONOREPO_ROOT/packages/claude-notifier/src/scripts/remove-task.ts" "$PROJECT_DIR"新的 Stop Hooks 配置(推荐):
json{ "Stop": [ { "hooks": [ { "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/task-complete-notifier.sh", "timeout": 20 }, { "type": "command", "command": "claude-notifier task-complete --message \"任务完成\"", "timeout": 5 } ] } ] }迁移指南:
如果你的 Stop hooks 配置中包含
check-and-notify,请移除它:diff{ "Stop": [ { "hooks": [ { "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/task-complete-notifier.sh", "timeout": 20 }, - { - "command": "claude-notifier check-and-notify", - "timeout": 5 - } ] } ] }其他 Hooks 保持不变:
check-and-notify仍然可以在以下 hooks 中正常使用:- ✅ UserPromptSubmit(创建任务)
- ✅ PreToolUse(检查长任务)
- ✅ SessionEnd(清理任务)
- ✅ SubagentStop(清理子任务)- 如果配置了环境变量
技术细节
stdin 竞争问题详解
问题机制:
- Claude Code 为每个 hook 提供相同的 stdin 数据
- Node.js 的
process.stdin是流式读取,只能被消费一次 - 第一个钩子读取后,后续钩子读到空数据
readHookInput()设置了 500ms 超时,超时后返回nullcheck-and-notify检测到null后提前返回,不执行删除任务逻辑
执行时序(修复前):
钩子 stdin 状态 结果 task-complete-notifier.sh ✅ 成功读取 Gemini 总结完成 task-complete ⚠️ 不需要 stdin 发送通知 check-and-notify ❌ stdin 已空 500ms 超时 → 提前返回 → 任务未删除 执行时序(修复后):
钩子 stdin 状态 结果 task-complete-notifier.sh ✅ 成功读取 Gemini 总结 + tsx remove-task.ts ✅ task-complete ⚠️ 不需要 stdin 发送通知 ✅ 设计权衡
为什么不在所有 hooks 中移除 check-and-notify?
- ✅ 其他 hooks(如 PreToolUse)通常只有一个钩子,不存在竞争
- ✅ 环境变量方案可以避免 stdin 竞争(长期方案)
- ✅ 长任务监控功能仍然需要
check-and-notify
为什么 Stop hooks 特殊?
- ⚠️ Stop hooks 通常包含多个钩子(Gemini 总结 + 通知)
- ⚠️ stdin 竞争在 Stop 阶段最严重(执行时间长,更容易超时)
- ⚠️ 任务删除是关键操作,必须可靠执行
相关文件
新增文件
src/scripts/remove-task.ts- 独立任务删除脚本
修改文件
src/commands/check-and-notify.ts- 支持环境变量,自动跳过 Stop 事件src/core/timer.ts- 无变更(仅被新脚本调用)
文档和报告
docs/reports/2025-11-19-stop-hooks-failure-analysis.md- 问题深度分析报告docs/reports/2025-11-19-common-tools-v0.8.0-release.md- 发布报告
依赖要求
确保以下工具已安装:
- ✅
tsx(全局安装):npm install -g tsx - ✅
node-notifier(已在依赖中) - ✅
geminiCLI(可选,用于 Gemini 总结)
验证步骤
安装 tsx(如果尚未安装)
bashnpm install -g tsx测试任务删除脚本
bashtsx packages/claude-notifier/src/scripts/remove-task.ts查看任务状态文件
bash# Windows type %TEMP%\.claude-notifier-timer.json # Linux/Mac cat ~/.claude-notifier-timer.json完整测试流程
- 启动 Claude Code 对话
- 提交任务并等待完成
- 观察 Stop hook 执行(应该看到两个通知)
- 等待 6 分钟,确认不再收到长任务通知 ✅
后续计划
短期优化
- 推动 Claude Code 支持环境变量注入
- 在 hooks.json 中配置
env字段 - 完全避免 stdin 竞争
- 在 hooks.json 中配置
- 减少 Gemini 超时时间
- 当前:Flash 5s + Pro 5s = 10s
- 优化:Flash 3s + Pro 3s = 6s
长期规划
- 重构为单一 Node.js 钩子
- 合并 task-complete-notifier.sh 的逻辑到 TypeScript
- 避免 Bash 脚本的跨平台问题
- 使用 SQLite 替代 JSON 文件
- 更好的并发控制
- 事务支持
- 性能提升
致谢
感谢所有在测试和问题排查过程中提供帮助的用户。此次修复彻底解决了长期存在的 Stop hooks 超时和重复通知问题。
0.8.2
Patch Changes
修复 Stop hooks 超时和逻辑错误,优化性能,确保任务正确清理 (
62939d2)核心修复:
- 修复 check-and-notify 的 Stop 逻辑错误
- 移除对
stop_hook_active === true的错误判断 - 现在 Stop/SubagentStop 事件能正确删除任务,避免执行错误的"清理和通知"逻辑
- 当 hookInput 为 null 时提前返回,避免执行不必要的逻辑
- 移除对
- 优化性能
- 改进日志记录,增加
stop_hook_active状态输出 - 确保 Stop 阶段快速返回,不做任何通知处理
- 提升整体 Stop hooks 执行稳定性
- 改进日志记录,增加
影响:
- 解决了 Claude Code Stop hooks 中
check-and-notify无法正确清理任务的问题 - 配合插件侧的优化,整体 Stop hooks 执行更稳定
- 修复 check-and-notify 的 Stop 逻辑错误
0.8.1
Patch Changes
修复 Stop hooks 执行超时和逻辑错误问题 (
1b0b831)核心修复:
- 修复 check-and-notify 的 Stop 逻辑错误
- 移除对
stop_hook_active === true的错误判断 - 现在 Stop/SubagentStop 事件能正确删除任务,避免执行错误的"清理和通知"逻辑
- 修复文件:
src/commands/check-and-notify.ts:160-176
- 移除对
- 优化性能和超时问题
- 改进日志记录,增加
stop_hook_active状态输出 - 确保 Stop 阶段快速返回,不做任何通知处理
- 改进日志记录,增加
影响:
- 解决了 Claude Code Stop hooks 中
check-and-notify无法正确清理任务的问题 - 配合插件侧的
cleanup-orphan-processes.sh优化,整体 Stop hooks 执行更稳定
- 修复 check-and-notify 的 Stop 逻辑错误
0.8.0
Minor Changes
改进
check-and-notify命令的事件处理和日志功能 (3afa5d1)新增功能
事件处理增强
- 新增 SessionStart 事件处理:跳过通知,避免会话启动时的干扰,立即返回不执行后续逻辑
- 新增 SessionEnd 事件处理:删除任务并清理资源,不发送通知,确保会话结束时正确清理任务数据
- 改进 UserPromptSubmit 事件处理:无条件删除旧任务并创建新任务,确保每次用户输入都重新计时
日志和性能监控
- 新增详细的日志记录系统:
- 日志文件保存在临时目录
%TEMP%\claude-notifier-debug\ - 每次执行创建独立的日志文件
check-and-notify-{timestamp}.log - 日志包含时间戳、执行耗时、各阶段详细信息
- 日志文件保存在临时目录
- 新增性能监控功能:
- 记录 stdin 读取、任务清理、通知检查等各阶段的耗时
- 输出总执行时间和各阶段耗时统计
- 当总耗时接近或超过 5 秒时自动发出警告
- 改进
--verbose选项:同时输出到控制台和日志文件
文档更新
- 更新 README.md,补充 SessionStart 和 SessionEnd 事件的说明
- 更新 CLI 使用文档,新增日志功能和性能监控的详细说明
- 更新工作机制说明,完善所有事件的处理流程
技术改进
- 优化事件处理逻辑,根据不同的
hook_event_name智能执行相应操作 - 改进注释文档,提供更清晰的函数说明和参数描述
- 增强错误处理和日志记录,便于调试和问题排查
0.7.0
Minor Changes
新增
interaction-needed通知类型,用于 Claude Code 的 Notification 钩子事件 (232b6c7)新增功能:
- 新增
InteractionNeededOptions类型定义 - 新增
interaction-neededCLI 命令,用于发送需要交互的通知 - 默认使用
alice/timeout.gif图标和warning音效 - 支持自定义消息、标题和交互详情
使用场景:
- 在 Claude Code 的 Notification 钩子中使用
- 当 Claude 使用 AskUserQuestion 工具需要用户输入时
- 需要用户确认或交互的场景
文档更新:
- 更新 CLI 使用文档,新增
interaction-needed命令说明 - 更新 Claude Code 配置文档,新增 Notification 钩子使用示例
- 新增
0.6.1
Patch Changes
修复 stdin 阻塞导致进程挂起的问题 (
43b1265)在高频调用 check-and-notify 命令时,readHookInput() 函数会永久等待 stdin 关闭事件,导致进程无法退出,累积大量未关闭的 npx 进程。
修复内容:
- 为 readHookInput() 添加 500ms 超时机制
- 超时后自动清理事件监听器,防止内存泄漏
- 确保进程能够正常退出
影响范围:
- 影响所有通过 Claude Code hooks 高频调用 check-and-notify 的场景
- Windows 系统下尤其明显(会看到大量未关闭的 npx.exe 进程)
0.6.0
Minor Changes
改进通知逻辑和事件处理 (
331ec73)破坏性变更
删除废弃的 session_id API
完全移除了所有基于
session_id的废弃函数和类型定义,不再保留兼容性:- 删除函数:
loadAllSessions()、saveAllSessions()、addOrUpdateSession()、removeSession()、cleanupExpiredSessions()、checkAndNotifySession()、checkAndNotifyAll()、getSessionState()、getAllSessionStates() - 删除类型:
TimerState、SessionTimerState
新功能
增强的事件处理
check-and-notify命令现在支持更多 Claude Code 生命周期事件:- SessionStart:跳过通知,避免会话启动时的干扰
- UserPromptSubmit:无条件删除旧任务并创建新任务,确保每次用户输入都重新计时
- SessionEnd:删除任务,不做通知,确保会话结束时清理任务
- Stop/SubagentStop:保持原有逻辑,删除任务
修复重复通知问题
修复了
lastCheckTime更新时机不当导致的重复通知问题:- 原有问题:只有在发送通知后才保存
lastCheckTime,导致没有发送通知时更新丢失 - 修复方案:在通过
MIN_CHECK_INTERVAL验证后立即更新并保存lastCheckTime - 效果:防止打开 Claude Code 后出现多次重复提醒
改进点
- 精准的事件分类:SessionStart 和 UserPromptSubmit 阶段不做长任务提醒
- 更可靠的时间戳管理:确保每次检查都会更新时间戳
- 更清晰的代码:移除所有废弃代码,简化维护成本
- 删除函数:
0.5.0
Minor Changes
重构长任务管理:基于 cwd 的智能 hook 处理 (
f1f43cb)破坏性变更
1. 数据结构变更
- 状态文件从基于
session_id改为基于cwd - 时间字段从时间戳改为语义化字符串(YYYY-MM-DD HH:mm:ss)
triggeredIndexes从存储索引改为存储分钟值(如 [6, 10])- 删除了
intervals、sound、icon字段
2. long-task 命令行为变更
- 从"长任务管理命令"改为"纯样式化通知命令"
- 移除了
--stop、--status、--session-id、--intervals等选项 - 新增
--message选项用于自定义通知消息 - 不再处理任何定时逻辑
3. check-and-notify 智能处理
- 改为根据
hook_event_name智能处理不同逻辑 - UserPromptSubmit: 添加/重置任务
- Stop/SubagentStop: 删除任务
- 其他事件: 检查并通知
- 新增
--intervals选项支持自定义提醒间隔
新功能
1. 基于 cwd 的任务管理
- 使用当前工作目录(cwd)作为任务唯一标识
- 支持多个工作目录同时运行独立任务
- 自动清理过期任务(超过 8 小时)
2. 精确时间差计算
- 通知文本显示精确的"X 分 Y 秒"格式
- 通知标题显示阶段信息(如"长任务提醒:6 分钟阶段")
- 使用 dayjs 进行时间格式化
3. 智能事件处理
- check-and-notify 根据 hook_event_name 自动决定操作
- 无需手动管理任务创建和删除
- 适配 Claude Code hooks 的完整生命周期
API 变更
新增 API
addOrResetTask(cwd)- 添加或重置任务removeTask(cwd)- 删除任务checkAndNotifyTask(cwd, intervals)- 检查并通知单个任务checkAndNotifyAllTasks(intervals)- 检查并通知所有任务formatTime(timestamp)- 格式化时间为语义化字符串parseTime(timeString)- 解析时间字符串为时间戳formatTimeDiff(startTime, endTime)- 计算时间差并格式化DEFAULT_INTERVALS- 默认提醒间隔常量
废弃 API(保留空实现用于兼容)
addOrUpdateSession()- 请使用addOrResetTask()removeSession()- 请使用removeTask()getSessionState()- 请使用getTaskState()getAllSessionStates()- 请使用getAllTaskStates()
依赖变更
- 新增
dayjs@^1.11.19用于时间格式化
迁移指南
更新 Claude Code hooks 配置
json// 旧配置(不再推荐) { "hooks": { "SessionStart": [{ "hooks": [{ "command": "npx @ruan-cat/claude-notifier long-task" }] }] } } // 新配置(推荐) { "hooks": { "UserPromptSubmit": [{ "hooks": [{ "command": "npx @ruan-cat/claude-notifier check-and-notify" }] }], "Stop": [{ "hooks": [{ "command": "npx @ruan-cat/claude-notifier check-and-notify" }] }], "BeforeToolUse": [{ "hooks": [{ "command": "npx @ruan-cat/claude-notifier check-and-notify" }] }] } }更新状态文件
旧的状态文件将被自动忽略,新版本会创建新的数据结构。无需手动迁移。
更新 API 调用
typescript// 旧 API(已废弃) import { addOrUpdateSession } from "@ruan-cat/claude-notifier"; addOrUpdateSession(sessionId); // 新 API import { addOrResetTask } from "@ruan-cat/claude-notifier"; addOrResetTask(cwd);- 状态文件从基于
0.4.0
Minor Changes
重构长任务管理系统,支持多会话管理 (
de4f5fe) 🎉 新功能
新增
check-and-notify命令 专为 Claude Code hooks 设计的高频调用命令,提供自动化的长任务管理。
核心功能:
- ✅ 自动创建新会话任务(首次检测到 session_id 时)
- ✅ 自动删除已完成任务(stop_hook_active = true 时)
- ✅ 自动清理过期任务(超过 8 小时)
- ✅ 定时检查并发送到期通知
- ✅ 防重复通知机制(10 秒内不重复检查同一任务)
推荐配置(~/.claude/settings.json):
json{ "hooks": { "BeforeToolUse": [ { "matcher": "os == 'windows'", "hooks": [ { "type": "command", "command": "npx @ruan-cat/claude-notifier check-and-notify" } ] } ], "Stop": [ { "matcher": "os == 'windows'", "hooks": [ { "type": "command", "command": "npx @ruan-cat/claude-notifier check-and-notify" } ] } ] } }🔧 重构
long-task命令重构 从单进程后台定时器重构为基于 session_id 的多会话管理系统。
主要变化:
- 从 stdin 读取 session_id(支持 Claude Code hooks)
- 支持多个 Claude Code 对话同时运行
- 无后台进程,基于状态文件管理
- 配合
check-and-notify命令使用
新用法:
bash# 从 stdin 读取 session_id 并注册任务 echo '{"session_id":"my-session"}' | npx @ruan-cat/claude-notifier long-task # 查看所有会话状态 npx @ruan-cat/claude-notifier long-task --status # 手动指定 session_id(测试用途) npx @ruan-cat/claude-notifier long-task --session-id "test-123"🐛 修复
- 修复了长任务定时器在实际运行时不生效的问题
- 修复了多个 Claude Code 实例同时运行时的冲突问题
- 修复了定时器状态文件可能无限增长的问题
📚 文档更新
- 更新 README.md,说明新的长任务管理机制
- 更新 claude-code.md,添加 check-and-notify 命令的 hooks 配置指南
- 更新 cli.md,详细说明新的命令用法和工作机制
💡 升级指南
对现有用户的影响
如果你正在使用旧版的
long-task命令:旧的直接调用方式仍然可用,但不推荐:
bash# 旧版(不推荐) npx @ruan-cat/claude-notifier long-task推荐迁移到新版:
使用
check-and-notify命令配置到 hooks,实现自动化管理:json{ "hooks": { "BeforeToolUse": [ { "matcher": "os == 'windows'", "hooks": [ { "type": "command", "command": "npx @ruan-cat/claude-notifier check-and-notify" } ] } ] } }破坏性变更
long-task命令不再启动后台进程long-task需要从 stdin 读取 session_id 或手动指定 --session-id- 旧的
--stop选项需要配合 session_id 使用
兼容性
- ✅ 所有其他命令(task-complete, timeout, error)保持不变
- ✅ 音频和图标预设完全兼容
- ✅ 现有的 hooks 配置可以继续使用
🔗 相关资源
0.3.1
Patch Changes
- 修复 timer.ts 中的类型错误,添加缺失的 DEFAULT_INTERVALS 常量定义 (
c840569)
0.3.0
Minor Changes
全面调整全部包的 files 构建输出配置,统一排除规则,避免错误发布冗余文件 (
a0004e3)主要改进
- 优化
files字段配置,更精确地控制发布到 npm 的文件列表 - 统一排除不必要的构建产物和缓存文件(如
.vitepress/cache、.vitepress/dist等),统一排除掉.vitepress文件夹 - 排除测试文件和文档文件(
**/tests/**、**/docs/**等) - 使用
dist/**替代dist/*以确保包含所有构建输出子目录 - 统一各包的文件排除规则格式
这些改动仅影响 npm 包的发布内容,不影响包的功能和 API,减少了包的体积并提升了发布质量。
- 优化
0.2.0
Minor Changes
将默认图标更改为 Alice 版本 (
4ab0797)新功能:
- 添加了三个新的图标预设:
alice/success.gif,alice/error.gif,alice/timeout.gif - 所有命令现在默认使用 Alice 风格的动态图标
具体变更:
task-complete命令:默认图标从success改为alice/success.giferror命令:默认图标从error改为alice/error.giftimeout命令:默认图标从error改为alice/timeout.giflong-task命令:默认图标从clock改为alice/timeout.gif
用户影响:
- 用户在不指定
-i, --icon参数时,将自动使用 Alice 风格的动态 GIF 图标 - 仍然支持通过
-i参数指定其他预设图标或自定义图标路径 - 旧的图标预设(success, warning, error, info, clock)仍然可用
- 添加了三个新的图标预设:
Patch Changes
修复云端环境中文档构建失败的问题 (
590984f)在根包的 package.json 中添加 @ruan-cat/claude-notifier 作为 devDependencies,确保 turbo deploy-vercel 命令能够正确识别并执行该包的 build:docs 任务。
技术细节:
- Turbo 的
^build:docs依赖解析基于 package.json 的依赖声明 - 只有在根包中声明的工作区包才会被包含在根任务的依赖图中
- 本次修复确保 GitHub Actions 工作流能够正确部署 claude-notifier 的文档站点
相关文档:
- 详细事故报告:docs/incident-reports/2025-10-28-claude-notifier-build-docs-failure.md
- Turbo 的
0.1.1
Patch Changes
- 修复生产环境资源路径问题,并重构路径查找逻辑: (
b3dbf75)- 修复:生产环境下无法找到 assets 内的图片和音频资源
- 重构:提取公共的路径查找逻辑到
src/config/utils.ts - 新增:
findResourceDir()工具函数,统一处理开发环境和生产环境的路径差异 - 优化:简化
sounds.ts和icons.ts的代码,提升可维护性 - 文档:更新
architecture.md,详细说明路径查找策略和技术背景
0.1.0
Minor Changes
- 初始化本包。 (
396eec8)- 默认用小爱丽丝作为图标 icon。
- 目前无法播出曼波的声音,自定义声音的功能疑似在 window10 系统内无法使用。