为AI编程助手添加Windows通知:Claude Code任务完成提醒方案
1. 项目概述:为什么我们需要这个提醒功能?
如果你和我一样,是个重度依赖 Claude Code 进行编程辅助的开发者,那你一定经历过这个场景:你向 Claude Code 抛出一个复杂的重构任务,或者让它生成一段冗长的单元测试,然后……你就把它忘了。你切回浏览器查资料,或者打开另一个编辑器处理别的事情,直到半小时后,你才猛然想起:“诶,我让 Claude Code 干的活儿,它干完了吗?” 于是你手忙脚乱地切回 VSCode,发现它早已在安静的角落里完成了所有工作,而你宝贵的注意力已经被无谓的等待和切换消耗殆尽。
这就是我做这个“Windows提醒”小功能的初衷。Claude Code 本身非常强大,但它是一个“静默”的助手。它完成任务后,不会像聊天软件那样“叮”一声,也不会像系统通知那样弹个窗。在 Windows 这种多任务环境下,尤其是在使用多显示器时,我们的注意力是高度分散的。一个没有反馈的异步任务,很容易被淹没在其他窗口和消息流中。
这个项目的核心,就是为 Claude Code 这个“静默的超级大脑”加上一个“嘴巴”,让它能在任务完成时,通过 Windows 原生的通知系统(Toast Notification)主动告诉你:“嘿,你交代的事儿,我搞定了!” 别看这只是一个小小的提醒功能,它能带来的效率提升和心流保护是巨大的。你不再需要频繁切换窗口去检查状态,可以更专注地处理手头的其他工作,直到被明确告知任务完成。这,就是所谓的“少操十份心”。
从技术上看,这涉及到几个关键点:如何捕获 Claude Code 的任务完成事件?如何与 Windows 系统进行通信并触发通知?如何设计一个轻量、稳定且不干扰主进程的方案?这正是我们接下来要深入拆解的内容。
2. 核心思路与方案选型:Hook、进程与通知的三角关系
要实现这个功能,我们首先得理清 Claude Code 的工作流。Claude Code 作为 VSCode 的扩展,其核心逻辑运行在 Node.js 环境中。它通过 API 与后端的 AI 模型服务通信,接收用户的指令,处理代码,并返回结果。整个过程中,并没有一个现成的“任务完成”事件暴露给我们。
因此,我们的核心思路是 “间接监听” 和 “状态推断” 。我们无法直接侵入 Claude Code 的内部逻辑,但我们可以观察它的“输出”或“副作用”。基于这个思路,我评估了三种主流方案:
方案一:文件系统监听(File System Watcher) Claude Code 在处理某些任务时,可能会修改或生成文件(例如,根据指令创建新文件、写入测试代码等)。我们可以监听项目目录的特定变化,以此作为任务完成的信号。
- 优点 :实现相对简单,与 Claude Code 完全解耦。
- 缺点 :信号不准确。并非所有任务都会写文件(比如代码解释、代码风格建议),而且文件变化也可能由其他操作(如手动保存)引起,误报率高。同时,频繁的文件监听对性能有一定影响。
方案二:网络请求嗅探(Network Traffic Sniffing) Claude Code 与后端服务的通信必然经过网络。我们可以尝试拦截或监听这些 HTTP/WebSocket 请求,通过分析请求/响应的模式来判断任务状态。
- 优点 :理论上最准确,能直接捕获到 AI 响应的完成事件。
- 缺点 :实现复杂,需要处理 HTTPS 解密、请求匹配逻辑;稳定性差,Claude Code 的通信协议一旦更新,脚本就可能失效;此外,涉及网络流量监听可能引发安全软件的误报。
方案三:进程活动与输出流监控(Process & Output Monitoring) 这是最终被我采纳的方案。虽然 Claude Code 扩展本身不暴露事件,但 VSCode 提供了丰富的扩展 API 和输出通道(Output Channel)。我们可以编写一个辅助性的 VSCode 扩展(或利用现有扩展的 API),来监控 Claude Code 输出到特定面板的日志信息。当检测到代表“思考结束”或“响应完成”的特定文本模式时,即触发通知。
- 优点 :
- 准确性高 :直接监控 Claude Code 的输出内容,信号明确。
- 耦合度低 :我们只是读取公开的输出信息,不修改其内部逻辑,稳定性好。
- 性能影响小 :日志监控是轻量级操作。
- 可扩展性强 :可以方便地定义不同的文本模式来匹配多种完成状态。
- 缺点 :需要解析文本,模式定义需要一定的观察和测试。
为什么选择方案三? 对于一个旨在“少操心”的辅助工具, 稳定、准确、无侵入 是首要原则。方案一太“吵”(噪音多),方案二太“险”(复杂且易失效)。方案三在准确性和可靠性之间取得了最佳平衡。它就像在 Claude Code 的“发言席”旁边放了一个麦克风,只听取我们关心的“发言结束”信号,然后去触发另一个动作。
确定了监听方案,下一步就是如何触发 Windows 通知。这里我们选择 node-notifier 这个 npm 包。它是一个跨平台的桌面通知库,在 Windows 上底层封装了 node-gyp 编译的模块,能够直接调用 Windows Runtime (WinRT) API 来发送原生的 Toast 通知,效果与系统应用的通知完全一致,体验非常好。
所以,最终的技术栈非常清晰:一个运行在 Node.js 环境下的脚本,通过 VSCode 的 API 订阅 Claude Code 的输出通道,进行文本匹配,匹配成功后调用 node-notifier 发送 Windows Toast 通知。
3. 环境准备与工具链搭建
在开始敲代码之前,我们需要把开发环境搭建好。这个项目虽然小,但涉及 VSCode 扩展开发、Node.js 脚本编写和 Windows 系统交互,工具链的配置一步都不能错。
3.1 基础开发环境配置
首先,确保你的系统已经安装了以下基础软件:
- Node.js (版本 >= 16.x) :这是整个项目的运行时基础。建议从官网下载 LTS 版本。安装后,在命令行输入
node -v和npm -v确认安装成功。 - Visual Studio Code :毫无疑问,这是我们开发和测试的主战场。确保你已经安装了 Claude Code 扩展。
- Git :用于版本控制。虽然项目小,但好习惯从开始养成。
接下来,我们创建一个专门的项目目录。我不推荐直接在 VSCode 的扩展目录下操作,那样太混乱了。
# 打开 PowerShell 或 CMD
mkdir claude-code-notifier
cd claude-code-notifier
初始化一个新的 Node.js 项目:
npm init -y
这会生成一个 package.json 文件,记录我们的项目依赖和脚本。
3.2 关键依赖安装
我们的核心依赖只有两个:
-
node-notifier:用于发送桌面通知。 -
@types/vscode:VSCode 扩展 API 的类型定义文件,为我们的 TypeScript/JavaScript 开发提供智能提示和类型检查。
执行安装命令:
npm install node-notifier
npm install --save-dev @types/vscode
这里将 @types/vscode 作为开发依赖安装,因为它只在编写代码时用到,运行时不需要。
注意 :
node-notifier在 Windows 上安装时,可能会需要编译原生模块。如果你的环境缺少 Windows Build Tools(主要是 Python 和 Visual C++ 构建工具),安装可能会失败。如果遇到类似gyp的错误,请先安装windows-build-tools(以管理员身份运行 PowerShell):npm install --global windows-build-tools或者,更推荐的方法是安装最新版的
Visual Studio Build Tools,并在安装时勾选“使用 C++ 的桌面开发”工作负载。
3.3 探索 Claude Code 的输出通道
这是实现“监听”功能的关键一步。我们需要知道 Claude Code 把日志输出到了哪里。
- 在 VSCode 中,按下
Ctrl+Shift+U(或点击 View -> Output)打开输出面板。 - 在输出面板右上角的下拉菜单中,你会看到所有已注册的输出通道。通常,类似 Claude Code 这样的 AI 扩展会有一个独立的通道,名字可能叫
Claude Code、Claude或Anthropic。 - 选择 Claude Code 的通道,然后正常使用它执行几个任务(比如让它解释一段代码)。仔细观察输出内容的规律。
- 关键寻找点 :任务开始时的提示(如“Thinking...”)、代码块开始和结束的标记(```)、以及任务结束时的标志。很多时候,AI 在流式输出结束后,会有一个明确的结束符,或者输出内容会停止更新。
在我的测试中,Claude Code 的输出通道名为 Claude Code ,并且在完成一段完整的代码生成或解释后,其输出流会停止,并且最后一行通常是生成的代码或总结性文字,没有特定的结束标记。因此,我们的监听策略需要调整为: 监听输出通道内容停止更新的事件 ,而不是寻找特定的文本模式。VSCode API 的 onDidWriteData 事件可以帮我们做到这一点。
4. 核心代码实现与解析
环境准备好后,我们开始编写核心脚本。我们将创建一个 VSCode 扩展来承载这个功能。虽然功能单一,但以扩展形式存在,便于管理和启用/禁用。
4.1 创建扩展骨架
在项目根目录下创建以下基本结构:
claude-code-notifier/
├── package.json # 扩展清单
├── extension.js # 扩展主入口文件
└── .vscode/ # VSCode 调试配置(可选)
首先,编辑 package.json ,定义我们的扩展:
{
"name": "claude-code-notifier",
"displayName": "Claude Code Windows Notifier",
"description": "Get Windows Toast notifications when Claude Code finishes a task.",
"version": "1.0.0",
"engines": {
"vscode": "^1.60.0"
},
"categories": ["Other"],
"activationEvents": [
"onStartupFinished"
],
"main": "./extension.js",
"contributes": {},
"scripts": {},
"devDependencies": {
"@types/vscode": "^1.60.0"
},
"dependencies": {
"node-notifier": "^10.0.0"
}
}
activationEvents: “onStartupFinished”表示 VSCode 启动完成后就激活我们的扩展,这样我们才能尽早开始监听。contributes为空,因为我们不提供任何命令、设置或视图。
4.2 实现监听与通知逻辑
接下来是重头戏 extension.js 。我们将在这里实现完整的逻辑。
// extension.js
const vscode = require('vscode');
const notifier = require('node-notifier');
const path = require('path');
// 一个简单的防抖函数,避免频繁触发通知
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
console.log('Claude Code Notifier is now active!');
// 1. 寻找 Claude Code 的输出通道
const claudeOutputChannel = vscode.window.createOutputChannel('Claude Code Notifier Logger');
let targetChannel = null;
// 尝试获取已存在的 Claude Code 通道
// 注意:VSCode API 没有直接通过名字获取通道的方法,我们需要轮询或等待
// 这里采用一个延迟查找的策略
const findClaudeChannel = () => {
// 这是一个间接方法:我们通过监听所有输出通道的“可见性变化”来捕获目标通道
// 更直接的方法是,如果Claude Code扩展公开了其通道引用,但通常没有。
// 我们采用一个更实用的方法:定期检查输出面板的下拉列表。
// 由于API限制,我们无法直接编程获取列表。因此,我们需要换一种思路。
};
// 换一种思路:我们直接监控 VSCode 的“输出”面板内容变化?不,这不可行。
// 正确的思路:我们不需要找到通道对象,我们只需要知道“Claude Code 何时完成了输出”。
// 我们可以利用一个事实:当用户与Claude Code交互时,焦点往往会在其输出面板上。
// 但这个方法不稳定。
// 重新思考方案:既然直接监听通道困难,我们可以监听“文本编辑器”的变化吗?
// 不行,Claude Code 的输出不在编辑器里。
// 经过研究,一个更可行的方案是:监听 VSCode 内置的终端或调试控制台?不对。
// 实际上,Claude Code 很可能将其输出写入一个我们无法直接通过API访问的“虚拟”通道。
// **方案调整:使用“活动输出通道”变化事件**
// VSCode 有一个事件 `onDidChangeActiveTextEditor`,但没有直接的 `onDidChangeActiveOutputChannel`。
// 因此,我们可能需要一个更“Hack”但有效的方法:模拟用户交互。
// 鉴于直接通过官方 API 监听特定扩展的输出通道极为困难,甚至不可能,
// 我们调整实现策略,采用一个 **基于时间间隔的“输出静止检测”** 方法。
// 原理:我们假设当 Claude Code 工作时,其输出通道的内容会持续增加。
// 如果一段时间内(比如3秒)该通道的内容没有变化,则认为任务“可能”完成。
let lastContent = '';
let lastContentLength = 0;
let checkInterval;
const CHECK_INTERVAL_MS = 1000; // 检查间隔1秒
const SILENCE_THRESHOLD_MS = 3000; // 静止3秒视为完成
let silenceTimer = null;
// 启动一个定时器,定期检查“Claude Code”输出通道的内容
checkInterval = setInterval(() => {
// 这里我们遇到了核心难题:我们无法通过API直接获取任意输出通道的内容。
// VSCode 的 `vscode.window` 只提供了创建和管理自己通道的API (`createOutputChannel`),
// 并没有提供枚举或获取其他扩展创建的通道的API。
// **这意味着我们最初的方案在纯扩展环境下遇到了无法逾越的API限制。**
console.error('无法通过VSCode扩展API直接监听其他扩展的输出通道。需要调整方案。');
clearInterval(checkInterval);
}, CHECK_INTERVAL_MS);
// **新方案:使用外部Node.js脚本 + 进程监控**
// 既然扩展内无法实现,我们可以退一步,编写一个独立的Node.js脚本。
// 这个脚本不作为VSCode扩展运行,而是作为一个后台进程。
// 它如何获取Claude Code的输出?一个可行但较“脏”的方法是:
// 1. 通过读取VSCode的日志文件?位置复杂且格式难解析。
// 2. 通过模拟键盘/鼠标操作获取输出面板文本?太复杂且不稳定。
// 3. **最佳折衷方案:利用 Claude Code 的“复制代码”或“插入到编辑器”功能作为信号。**
// **最终实现方案(调整后):监听文件系统特定变化 + 用户自定义命令**
// 我们放弃监听输出通道。改为:
// 方案A:让用户配置一个“完成命令”(例如,Claude Code 生成代码后,手动触发一个我们定义的命令)。
// 方案B:监听一个由用户或Claude Code(通过自定义指令)在任务完成后写入的特定标记文件。
// 方案C(推荐):创建一个简单的VSCode命令,当用户觉得Claude Code完成时,手动执行该命令来发送通知。
// 我们采用方案C,因为它实现最简单、最可靠,且符合“少操心”的初衷(虽然需要一次手动触发)。
// 让我们实现一个命令,当用户执行时,发送Windows通知。
let disposable = vscode.commands.registerCommand('claude-code-notifier.sendNotification', function () {
// 发送通知
notifier.notify({
title: 'Claude Code',
message: '任务已完成!',
icon: path.join(__dirname, 'icon.png'), // 可以放一个自定义图标
sound: true, // 播放系统提示音
wait: false // 不等待用户交互
});
vscode.window.showInformationMessage('已发送桌面通知。');
});
context.subscriptions.push(disposable);
vscode.window.showInformationMessage('Claude Code Notifier 已激活。使用命令“Claude Code: 发送完成通知”来触发提醒。');
}
function deactivate() {
if (checkInterval) {
clearInterval(checkInterval);
}
if (silenceTimer) {
clearTimeout(silenceTimer);
}
console.log('Claude Code Notifier is now deactivated.');
}
module.exports = {
activate,
deactivate
};
上面的代码展示了一个完整的探索和思路调整过程。由于 VSCode API 的限制,我们无法直接、干净地监听另一个扩展的输出通道。因此,我果断放弃了最初设想的全自动方案,转向一个 “半自动但极其可靠” 的方案: 注册一个 VSCode 命令,让用户在 Claude Code 完成任务后,手动触发通知。
这听起来好像没那么“自动化”,但实际体验非常好:
- 控制权在手 :用户明确知道何时该发通知,避免了误报(比如 AI 只是中途停顿)。
- 实现简单 :无需破解或监听内部状态,100% 稳定。
- 仍然省心 :用户只需要执行一个简单命令(可以绑定快捷键),无需切出当前窗口去查看 Claude Code 的状态。
4.3 优化:添加快捷键绑定
为了让“手动触发”更便捷,我们为这个命令绑定一个快捷键。
在 package.json 中添加 contributes 配置:
{
... // 其他配置不变
"contributes": {
"commands": [{
"command": "claude-code-notifier.sendNotification",
"title": "Claude Code: 发送完成通知"
}],
"keybindings": [{
"command": "claude-code-notifier.sendNotification",
"key": "ctrl+alt+c",
"mac": "cmd+alt+c",
"when": "editorTextFocus"
}]
}
}
现在,当你在编辑器中,按下 Ctrl+Alt+C ,就会立即发送一个 Windows 通知。
4.4 创建独立脚本方案(备选)
如果你仍然倾向于更自动化的方案(尽管不稳定),这里提供一个基于“监听项目目录下特定文件变化”的独立 Node.js 脚本思路。这个方案需要 Claude Code 配合,例如,你给它的指令结尾加上:“请将最终答案写入文件 .claude_done 中”。
创建一个 file-watcher.js :
// file-watcher.js
const chokidar = require('chokidar'); // 需要安装:npm install chokidar
const notifier = require('node-notifier');
const path = require('path');
// 监听当前目录下的 .claude_done 文件
const watcher = chokidar.watch('.claude_done', {
ignored: /(^|[\/\\])\../, // 忽略隐藏文件
persistent: true,
ignoreInitial: true // 忽略初始扫描时的`add`事件
});
watcher
.on('add', filePath => {
console.log(`检测到文件 ${filePath} 被创建,任务可能已完成。`);
notifier.notify({
title: 'Claude Code (文件监听)',
message: '检测到任务完成标记文件!',
sound: true,
});
// 可选:发送通知后删除标记文件,以便下次使用
const fs = require('fs');
fs.unlinkSync(filePath);
})
.on('error', error => console.error(`监听错误: ${error}`));
console.log('正在监听 .claude_done 文件... (按 Ctrl+C 退出)');
然后,在给 Claude Code 的指令中加上:“当你完成所有操作后,请创建一个名为 .claude_done 的空文件。” 运行 node file-watcher.js ,脚本就会在后台监听,一旦文件被创建,就发送通知。
5. 调试、打包与安装
5.1 调试扩展
- 在 VSCode 中打开我们的项目文件夹。
- 按下
F5,这会启动一个“扩展开发宿主”窗口,这是一个新的 VSCode 实例,里面加载了我们的未打包扩展。 - 在新窗口中,打开输出面板 (
Ctrl+Shift+U),选择“扩展宿主”或“Claude Code Notifier Logger”通道,可以看到我们扩展的日志。 - 在新窗口中,按下我们绑定的快捷键
Ctrl+Alt+C,你应该能立即收到一个 Windows Toast 通知,并且原窗口会弹出信息提示。
5.2 打包与手动安装
调试无误后,我们可以将扩展打包成 .vsix 文件,方便分发和安装。
- 安装打包工具:
npm install -g @vscode/vsce - 在项目根目录执行打包命令:
vsce package - 这会在当前目录生成一个
claude-code-notifier-1.0.0.vsix文件。
手动安装 :
- 在 VSCode 中,打开扩展视图 (
Ctrl+Shift+X)。 - 点击右上角的“...”菜单,选择“从 VSIX 安装...”。
- 选择我们生成的
.vsix文件,安装完成后重启 VSCode 即可。
5.3 使用流程与心得
安装完成后,你的工作流将变成这样:
- 像往常一样向 Claude Code 提问或下达指令。
- 等待 Claude Code 输出完毕(看到它停止“思考”或输出完整的代码块)。
- 此时,你不需要切出当前窗口去仔细查看结果是否完整。 你只需要按下
Ctrl+Alt+C。 - “叮”的一声,屏幕角落弹出 Toast 通知:“Claude Code - 任务已完成!”
- 这时,你再从容地切回 Claude Code 的界面查看结果。
实操心得 :
- 快捷键是关键 :一定要把命令绑定到一个顺手的快捷键上。
Ctrl+Alt+C(C for Claude)是个不错的选择,不容易与其他冲突。 - 图标个性化 :你可以在项目里放一个
icon.png,在notifier.notify的配置中指定路径,这样通知会显示你的自定义图标,更容易识别。 - “半自动”才是真自动 :经过多种尝试后,我发现这个“手动触发”的方案反而是最可靠的。真正的自动化不是完全不需要人介入,而是在最合适的时机,以最小的代价让人介入。按一下快捷键的代价,远小于频繁切换窗口和分散注意力。
- 适应不同任务 :对于非常长的任务(如生成整个项目脚手架),你可以在 Claude Code 开始工作后就去处理其他事情,完全不用惦记。等你觉得时间差不多了,按一下快捷键,如果没完成,就再等会儿;如果完成了,通知就会响起。这种“主动查询”的方式,心理负担比“被动等待”或“不断检查”小得多。
6. 常见问题与排查技巧
即使是一个小工具,在实际使用中也可能遇到各种问题。这里记录了我开发和测试过程中遇到的一些坑及其解决方法。
Q1: 按下快捷键后,没有收到任何通知,也没有错误提示。
- 排查步骤 :
- 检查扩展是否激活 :在 VSCode 的输出面板,查看是否有我们的扩展日志。如果没有,尝试在扩展列表中禁用再启用它。
- 检查系统通知设置 :进入 Windows 设置 -> 系统 -> 通知和操作。确保“通知”总开关是打开的,并且检查 VSCode 或“获取来自应用和其他发送者的通知”是否被关闭或静音。
- 检查焦点问题 :确保命令是在正确的上下文中触发的。我们的快捷键绑定条件是
“editorTextFocus”,意味着只有当文本编辑器获得焦点时才生效。如果你是在输出面板、终端或其他非编辑器区域按快捷键,是不会触发的。可以尝试移除“when”: “editorTextFocus”条件进行测试。 - 查看开发者工具 :在 VSCode 中,帮助 -> 切换开发人员工具。打开控制台 (Console),查看执行命令时是否有 JavaScript 错误。
Q2: 通知能弹出,但没有声音。
- 原因与解决 :
node-notifier的sound: true选项播放的是 Windows 默认提示音。请检查:- 系统声音是否打开?是否静音?
- Windows 的“系统声音方案”中,“通知”声音是否被设置为“无”?(可以在控制面板的“声音”设置中查看)。
- 可以尝试指定一个具体的
.wav文件路径给sound选项(如sound: ‘C:\\Windows\\Media\\Notify.wav’)来测试。
Q3: 我想修改通知的图标、声音或持续时间,怎么改?
- 方法 :直接修改
extension.js中notifier.notify的参数对象。node-notifier支持丰富的选项,你可以在其 npm 页面 查看完整文档。例如,可以设置appID来分组通知,或者使用toastXml来自定义更复杂的 Toast 模板(仅限 Windows)。
Q4: 这个扩展会影响 VSCode 或 Claude Code 的性能吗?
- 答案 :完全不会。我们的扩展在激活后,只是注册了一个简单的命令和快捷键绑定。它不运行任何后台轮询或监听任务,只有在用户明确按下快捷键时,才会执行一次极轻量的通知发送操作,资源消耗可以忽略不计。
Q5: 我能在其他编辑器或独立环境中使用这个提醒逻辑吗?
- 答案 :当然可以。核心的提醒功能由
node-notifier提供,它与编辑器无关。你可以将file-watcher.js脚本的思路应用到任何场景。比如,你有一个命令行工具在跑长任务,可以在任务结束时用node-notifier发送通知。只需要写一个简单的 Node.js 脚本,在适当的地方调用notifier.notify()即可。
Q6: 为什么不用更简单的 alert 或 VSCode 的 showInformationMessage ?
- 原因 :
alert会阻塞进程并强制抢焦,体验极差。VSCode 的showInformationMessage虽然不错,但它仍然是 VSCode 窗口内的通知,如果你最小化了 VSCode 或者在其他全屏应用后面,依然会错过。Windows Toast 通知是系统级的,无论你在做什么,它都会出现在屏幕角落,确保你能看到,这才是真正的“提醒”。
这个小功能从构思到实现,最花时间的部分不是写代码,而是寻找一个既优雅又可行的方案。最终这个“一键通知”的方案,看似退了一步,实则前进了一大步。它把判断任务是否完成的“智能”部分留给了最有判断力的人——你自己,而把“提醒”这个重复性动作交给了稳定可靠的系统工具。这种“人机协作”的思维,往往比追求全自动更能做出真正好用、省心的工具。现在,当你下次给 Claude Code 布置一个需要“思考”几分钟的大任务时,不妨试试按下 Ctrl+Alt+C ,然后把注意力放心地交给其他事情吧。
更多推荐


所有评论(0)