Gmarker689 fa44163ca3 refactor: 用 StopFailure 事件替代定时轮询,移除空闲检测定时器
- 移除 heartbeat 空闲检测机制(PreToolUse 空 matcher)
- 新增 StopFailure hooks 处理 API 错误中断场景
- PostToolUse 仅保留 Edit(Write 通过 PreToolUse 快照实现)
- 移除 extension.ts 中 idleTimer/idleCooldown/heartbeatWatcher
- 更新 README hooks 配置文档
- 添加 MIT LICENSE
2026-06-24 17:58:15 +08:00
2026-06-19 14:04:25 +08:00

AI Code Diff Preview

类 Cursor 风格的 AI 代码差异预览 VSCode 插件 — Accept/Reject 审查变更。

使用方法

  1. 安装 .vsix 并重启 VSCode
  2. 将下面配置复制到项目 .claude/settings.json(或 ~/.claude/settings.json 全局生效)
  3. 用 Claude Code 编辑项目 → Stop 后自动弹出 QuickPick 变更列表 → VSCode 内置 Diff 逐文件审查 AI Diff 触发AI Diff后快捷键Ctrl+Shift+D打开QuickPick预览,一键 接受/拒绝 变更 QuickPick 进入单个diff界面可在状态栏右下角选择单个文件接受/拒绝 Accepet/Reject

Claude Code Hooks 必须配置

将以下内容写入 .claude/settings.json:

settings.json路径

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const fs=require('fs'),p=require('path');let b='';process.stdin.on('data',c=>b+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(b);const fp=j.tool_input?.file_path;if(!fp)return;const d=p.join(process.env.CLAUDE_PLUGIN_ROOT||'.','.claude','hooks');fs.mkdirSync(d,{recursive:true});let oc='';try{oc=fs.readFileSync(fp,'utf-8')}catch(e){}const s={originalContent:oc,timestamp:Date.now()};const f=p.join(d,'pre-write-snapshot.json'),tmp=f+'.tmp';fs.writeFileSync(tmp,JSON.stringify(s));fs.renameSync(tmp,f)}catch(e){}})\"",
            "timeout": 5
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const fs=require('fs'),p=require('path'),d=p.join(process.env.CLAUDE_PLUGIN_ROOT||'.','.claude','hooks');let b='';process.stdin.on('data',c=>b+=c);process.stdin.on('end',()=>{try{const j=JSON.parse(b);const e={type:'edit',filePath:j.tool_input?.file_path||'',content:j.tool_input?.content||'',oldString:j.tool_input?.old_string||'',newString:j.tool_input?.new_string||'',timestamp:Date.now(),toolName:'Edit'};fs.mkdirSync(d,{recursive:true});const t=p.join(d,'pending.json'),tmp=t+'.tmp';fs.writeFileSync(tmp,JSON.stringify(e));fs.renameSync(tmp,t)}catch{}})\"",
            "timeout": 5
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const fs=require('fs'),p=require('path'),d=p.join(process.env.CLAUDE_PLUGIN_ROOT||'.','.claude','hooks');try{fs.mkdirSync(d,{recursive:true});const t=p.join(d,'pending.json'),tmp=t+'.tmp';fs.writeFileSync(tmp,JSON.stringify({type:'stop',filePath:'',content:'',oldString:'',newString:'',timestamp:Date.now(),toolName:'Stop'}));fs.renameSync(tmp,t)}catch{}\"",
            "timeout": 5
          }
        ]
      }
    ],
    "StopFailure": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const fs=require('fs'),p=require('path'),d=p.join(process.env.CLAUDE_PLUGIN_ROOT||'.','.claude','hooks');try{fs.mkdirSync(d,{recursive:true});const t=p.join(d,'pending.json'),tmp=t+'.tmp';fs.writeFileSync(tmp,JSON.stringify({type:'stopFailure',filePath:'',content:'',oldString:'',newString:'',timestamp:Date.now(),toolName:'StopFailure'}));fs.renameSync(tmp,t)}catch{}\"",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

Hooks 说明

Hook 匹配器 作用
PreToolUse Write 写入前保存文件原始内容快照,用于 diff 对比
PostToolUse Edit 记录编辑信息(oldString/newString),用于精确 diff
Stop — Claude 正常完成响应 → 触发变更总览
StopFailure — API 错误导致中断 → 触发变更总览

命令

命令 快捷键 功能
AI Diff: 显示所有变更文件列表 Ctrl+Shift+D QuickPick 总览 + Accept All / Reject All
AI Diff: 下一个变更 Alt+↓ 跳转下一个 pending 文件
AI Diff: 上一个变更 Alt+↑ 跳转上一个 pending 文件
AI Diff: 接受所有变更 Ctrl+Shift+A Accept All
AI Diff: 拒绝所有变更 Ctrl+Shift+R Reject All

Diff 编辑器打开后,状态栏右侧自动出现 Accept / Reject / 接受全部 按钮。

开发

npm install
npm run build     # 编译
npm run test      # 测试
npm run package   # 生成 ai-diff-preview-*.vsix

许可证

MIT © 2026 Gmaker689

S
Description
No description provided
Readme MIT 295 KiB
Languages
TypeScript 96.8%
JavaScript 2.1%
Batchfile 1.1%