惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Vercel News
Vercel News
F
Fortinet All Blogs
月光博客
月光博客
G
Google Developers Blog
博客园 - Franky
GbyAI
GbyAI
The Cloudflare Blog
I
InfoQ
雷峰网
雷峰网
WordPress大学
WordPress大学
罗磊的独立博客
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
小众软件
小众软件
腾讯CDC
B
Blog
量子位
V
V2EX
S
SegmentFault 最新的问题
Google DeepMind News
Google DeepMind News

博客园 - 陈哈哈

Windows 上 agent-browser 使用问题排查与解决 踩坑实录:win11中Claude Code MCP 配置 context7 失败与调用问题全排查 Android N 多窗口模式,你需要知道的一切 Mac下设置Android源代码编译环境 Android编译过程中的碎碎念 编译Android AOSP代码 国内不FQ下载Android 源代码 android-plugmgr源代码分析 收集最好的Mac软件和使用方法 为什么使用Binder而不是其他IPC机制 Android什么时候进行View中Background的加载 Android属性动画源代码解析(超详细) Fragment提交transaction导致state loss异常 Android怎么找到最优适配资源 解决在onCreate()过程中获取View的width和Height为0的4种方法 【译】使用newInstance()来实例化fragment 【译】Activitys, Threads和 内存泄露 【译】什么导致了Context泄露:Handler&内部类 【译】用Fragment解决屏幕旋转(状态发生变化)状态不能保持的问题
Claude Code Windows 通知配置指南
陈哈哈 · 2026-03-18 · via 博客园 - 陈哈哈

背景

在使用 Claude Code 时,经常会同时开启多个终端窗口运行不同的任务。当某个任务需要用户输入或完成时,如果能收到 Windows 系统通知,就能及时切换到对应的终端进行处理。

本文记录了在 Windows 上为 Claude Code 配置通知功能的完整过程,包括遇到的问题和最终解决方案。

最终效果

配置完成后,当 Claude Code 需要用户输入或任务完成时,会弹出 Windows 原生通知,显示:

  • 🔴 需要输入 - 当 Claude Code 提出问题等待回答
  • 等待输入 - 当任务暂停等待用户操作
  • 任务完成 - 当任务执行完毕

通知内容包含:任务名称、具体问题、当前工作目录,方便用户识别是哪个终端的任务。

前置要求

  1. 安装 BurntToast 模块(需要管理员权限安装,PowerShell 通知模块)
Install-Module -Name BurntToast -Scope CurrentUser
  1. 确认 PowerShell 版本(需要 5.1+)
$PSVersionTable.PSVersion

配置步骤

1. 创建通知脚本

~/.claude/hooks/ 目录下创建 gsd-burnttoast-notify.js

#!/usr/bin/env node
// Claude Code Notification Hook
// Sends Windows toast notifications via BurntToast module.

const { spawnSync } = require('child_process');
const path = require('path');
const fs = require('fs');

const STATE_FILE = path.join(process.env.TEMP || process.env.TMP || '/tmp', 'claude-cc-ask-marker.json');

function getState() {
  try { return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')); }
  catch { return { askCount: 0, lastCwd: '' }; }
}

function writeState(state) {
  try { fs.writeFileSync(STATE_FILE, JSON.stringify(state), 'utf8'); } catch {}
}

function clearState() {
  try { fs.unlinkSync(STATE_FILE); } catch {}
}

function psEscape(s) {
  return String(s).replace(/'/g, "''");
}

function truncate(s, maxLen) {
  if (!s) return '';
  return s.length > maxLen ? s.substring(0, maxLen) + '...' : s;
}

function getCwdName() {
  try {
    return path.basename(process.cwd()) || process.cwd();
  } catch {
    return 'unknown';
  }
}

function sendToast(lines) {
  const textParams = lines.filter(l => l).map(l => `'${psEscape(truncate(l, 150))}'`).join(', ');
  const script = [
    "Import-Module BurntToast -ErrorAction SilentlyContinue;",
    `New-BurntToastNotification -Text ${textParams} -Sound Default;`
  ].join(' ');

  spawnSync('powershell', [
    '-ExecutionPolicy', 'RemoteSigned',
    '-NoProfile',
    '-WindowStyle', 'Hidden',
    '-Command', script
  ], { windowsHide: true, encoding: 'utf8' });
}

// --ask: PermissionRequest hook for AskUserQuestion
if (process.argv.includes('--ask')) {
  const prompt = process.env.CLAUDE_PERMISSION_PROMPT || '';
  const task = process.env.CLAUDE_TASK || '';
  const cwd = getCwdName();

  const lines = [
    '🔴 Claude Code - 需要你的输入',
    task ? `任务: ${task}` : '',
    prompt ? `问题: ${prompt}` : '',
    `目录: ${cwd}`
  ];
  sendToast(lines);
  process.exit(0);
}

// --mark-ask: PreToolUse hook for AskUserQuestion
if (process.argv.includes('--mark-ask')) {
  const state = getState();
  state.askCount += 1;
  state.askTime = Date.now();
  state.lastCwd = getCwdName();
  writeState(state);
  process.exit(0);
}

// --stop: Stop hook
if (process.argv.includes('--stop')) {
  const state = getState();
  const now = Date.now();
  const recent = state.askTime && (now - state.askTime) < 60000;
  const task = process.env.CLAUDE_TASK || '';
  const cwd = getCwdName();

  if (recent) {
    clearState();
    const lines = [
      '⏳ Claude Code - 等待输入',
      task ? `任务: ${task}` : '',
      `目录: ${cwd}`
    ];
    sendToast(lines);
  } else {
    clearState();
    const lines = [
      '✅ Claude Code - 任务完成',
      task ? `任务: ${task}` : '',
      `目录: ${cwd}`
    ];
    sendToast(lines);
  }
  process.exit(0);
}

// Default
const task = process.env.CLAUDE_TASK || '';
const cwd = getCwdName();
sendToast(['Claude Code', task || 'Notification', `目录: ${cwd}`]);
process.exit(0);

2. 配置 Claude Code Hooks

编辑 ~/.claude/settings.json,添加 hooks 配置:

{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "AskUserQuestion",
        "hooks": [
          {
            "type": "command",
            "command": "node \"C:/Users/你的用户名/.claude/hooks/gsd-burnttoast-notify.js\" --ask"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "AskUserQuestion",
        "hooks": [
          {
            "type": "command",
            "command": "node \"C:/Users/你的用户名/.claude/hooks/gsd-burnttoast-notify.js\" --mark-ask"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "node \"C:/Users/你的用户名/.claude/hooks/gsd-burnttoast-notify.js\" --stop"
          }
        ]
      }
    ]
  },
  "permissions": {
    "defaultMode": "bypassPermissions"
  }
}

注意:将 你的用户名 替换为你的 Windows 用户名。

遇到的问题与解决方案

问题 1:Notification hook 不存在

现象:配置了 Notification hook 但不触发。

原因:Claude Code v2.1.50 不支持 Notification hook 类型。

解决:改用 PermissionRequest hook(当 AskUserQuestion 触发时)。

问题 2:Hooks 被跳过

现象:日志显示 Skipping hook execution - workspace trust not accepted

原因:工作区信任未接受,hooks 被安全策略跳过。

解决:在 settings.json 中添加 "permissions": { "defaultMode": "bypassPermissions" }

问题 3:环境变量 $env: 被转义

现象:PowerShell 命令中的 $env:CLAUDE_TASK 变成了 :CLAUDE_TASK

原因:Bash shell 在传递命令时吞掉了 $ 字符。

解决:使用 Node.js spawnSync + 数组参数,绕过 Bash 变量展开。

问题 4:Toast 按钮点击无反应

现象:通知上的按钮点击后没有任何反应。

原因:BurntToast 的按钮需要注册 COM Activator 才能执行命令,PowerShell 没有这个能力。

解决:放弃按钮功能,只使用基础通知。

问题 5:PowerShell 窗口闪烁

现象:发送通知时 PowerShell 窗口一闪而过。

原因spawnSync 创建的进程短暂显示窗口。

解决:添加 -WindowStyle HiddenwindowsHide: true 参数。

技术细节

Hook 类型

Claude Code 支持以下 hook 类型:

Hook 触发时机
PreToolUse 工具执行前
PostToolUse 工具执行后
PermissionRequest 权限请求时
Stop Agent 停止时
SubagentStop 子 Agent 停止时
UserPromptSubmit 用户提交输入时

环境变量

Hook 执行时可用的环境变量:

  • CLAUDE_TASK - 当前任务名称
  • CLAUDE_PERMISSION_PROMPT - 权限/问题提示内容
  • CLAUDE_IDLE_PROMPT - 空闲提示内容

状态共享

由于每次 hook 执行都是独立进程,需要通过临时文件共享状态:

  • 文件位置:%TEMP%\claude-cc-ask-marker.json
  • 内容:{ askCount, askTime, lastCwd }
  • 用途:区分"任务完成"和"等待输入"

限制

  1. 无法聚焦特定终端 Tab:Windows Terminal 没有公开 API 来定位特定 Tab,通知只能提示用户手动切换。

  2. 按钮功能不可用:BurntToast 的按钮需要 COM 注册,PowerShell 无法实现。

  3. 字符编码:中文路径可能显示乱码,这是 PowerShell 的限制。

参考资料

总结

通过配置 Claude Code 的 hooks 系统,结合 PowerShell 的 BurntToast 模块,可以实现任务状态的通知功能。虽然有一些 Windows 系统层面的限制(如无法聚焦特定终端 Tab、按钮功能不可用),但基础的通知功能已经能满足日常使用需求。

配置完成后,当你同时运行多个 Claude Code 任务时,就能通过通知的"目录"字段快速识别是哪个任务需要关注了。