cursor-guard 4.4.0 → 4.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/ROADMAP.md +164 -3
- package/SKILL.md +6 -3
- package/package.json +1 -1
- package/references/bin/cursor-guard-backup.js +9 -1
- package/references/dashboard/public/app.js +218 -32
- package/references/dashboard/public/index.html +14 -19
- package/references/dashboard/public/style.css +257 -14
- package/references/dashboard/server.js +118 -51
- package/references/lib/auto-backup.js +27 -38
- package/references/lib/core/backups.js +18 -14
- package/references/lib/core/core.test.js +40 -0
- package/references/lib/core/doctor-fix.js +5 -0
- package/references/lib/core/doctor.js +16 -2
- package/references/lib/core/restore.js +56 -22
- package/references/lib/core/snapshot.js +22 -4
- package/references/mcp/server.js +33 -0
package/README.md
CHANGED
|
@@ -380,9 +380,11 @@ The skill activates on these signals:
|
|
|
380
380
|
### v4.4.0 — V4 Final
|
|
381
381
|
|
|
382
382
|
- **Fix**: First snapshot now generates "Added N: file1, file2, ..." summary instead of blank — previously the very first backup had no summary because there was no parent tree to diff against
|
|
383
|
+
- **Feature**: `--dashboard` flag for watcher — `npx cursor-guard-backup --path <dir> --dashboard` starts the web dashboard alongside the watcher in a single process. Optional port: `--dashboard 4000`. Auto-increments if port is busy
|
|
383
384
|
- **Feature**: Doctor check "Git retention" — warns when git backup commits exceed 500 and `git_retention.enabled` is `false`, guiding users to enable auto-pruning before refs grow unbounded
|
|
384
385
|
- **Feature**: Doctor check "Backup integrity" — verifies that the latest auto-backup commit's tree object is reachable via `git cat-file -t`, catching silent corruption early
|
|
385
386
|
- **Improve**: `cursor-guard-init` now detects existing `.cursor-guard.json` and displays an upgrade notice instead of silently overwriting
|
|
387
|
+
- **Improve**: Dashboard server refactored to export `startDashboardServer()` for embedding into other processes
|
|
386
388
|
|
|
387
389
|
### v4.3.5
|
|
388
390
|
|
package/README.zh-CN.md
CHANGED
|
@@ -380,9 +380,11 @@ node references\dashboard\server.js --path "D:\MyProject"
|
|
|
380
380
|
### v4.4.0 — V4 收官版
|
|
381
381
|
|
|
382
382
|
- **修复**:首次快照现在会生成 "Added N: file1, file2, ..." 摘要,而不是空白——之前第一次备份因为没有 parent tree 对比所以 summary 始终为空
|
|
383
|
+
- **功能**:Watcher `--dashboard` 参数——`npx cursor-guard-backup --path <dir> --dashboard` 启动时同时启动 Web 仪表盘,单进程完成监控+查看。可选端口:`--dashboard 4000`,端口被占自动递增
|
|
383
384
|
- **功能**:Doctor 新增 "Git retention" 检查——当 Git 备份 commit 数超过 500 且 `git_retention.enabled` 为 `false` 时发出 WARN,引导用户开启自动清理防止 ref 无限增长
|
|
384
385
|
- **功能**:Doctor 新增 "Backup integrity" 检查——通过 `git cat-file -t` 验证最近一次 auto-backup commit 的 tree 对象是否可达,尽早发现静默损坏
|
|
385
386
|
- **改进**:`cursor-guard-init` 现在检测已有 `.cursor-guard.json`,显示升级提示而非静默覆盖
|
|
387
|
+
- **改进**:Dashboard server 重构,导出 `startDashboardServer()` 供嵌入其他进程使用
|
|
386
388
|
|
|
387
389
|
### v4.3.5
|
|
388
390
|
|
package/ROADMAP.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
> 本文档描述 cursor-guard 从 V2 到 V7 的长期演进方向。
|
|
4
4
|
> 每一代向下兼容,低版本功能永远不废弃。
|
|
5
5
|
>
|
|
6
|
-
> **当前版本**:`V4.
|
|
7
|
-
> **文档状态**:`V2` ~ `V4.
|
|
6
|
+
> **当前版本**:`V4.5.1`(V4 最终版)
|
|
7
|
+
> **文档状态**:`V2` ~ `V4.5.1` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
|
|
8
8
|
|
|
9
9
|
## 阅读导航
|
|
10
10
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|---|---|---|---|
|
|
21
21
|
| `V2` | 能用 | Skill + Script | "AI 弄丢代码能恢复" |
|
|
22
22
|
| `V3` | 更稳 | + Core 抽取 + 可选 MCP | "恢复操作更标准、更省 token" |
|
|
23
|
-
| `V4` | 更聪明 | + 主动检测 + 可观测 + Web 仪表盘 + Intent + 增量摘要 | "cursor-guard 会主动提醒你,能看到为什么备份、改了什么" ✅ |
|
|
23
|
+
| `V4` | 更聪明 | + 主动检测 + 可观测 + Web 仪表盘 + Intent + 增量摘要 + 安全硬化 | "cursor-guard 会主动提醒你,能看到为什么备份、改了什么" ✅ |
|
|
24
24
|
| `V5` | 成闭环 | + 变更控制层 | "AI 代码变更可预防、可追溯、可按事件恢复"(intent 基础已在 V4.3 落地) |
|
|
25
25
|
| `V6` | 成标准 | + 开放协议 + 团队工作流 | "把 AI 代码变更安全做成跨工具标准" |
|
|
26
26
|
| `V7` | 可证明 | + 可验证信任 + 治理层 | "能证明安全流程被执行了" |
|
|
@@ -457,6 +457,58 @@ V4 经过 4 轮系统性代码审查,修复了以下关键问题:
|
|
|
457
457
|
| V4.3.4 | **运维加固**:`backup.log` 日志轮转(1MB / 3 文件);watcher 单实例保护加固(锁文件时间戳 + 24h 超时);`previewProjectRestore` 保护路径分组摘要(降低 token 消耗);SKILL.md 硬规则 #15(升级后提交 skill 文件) | ✅ |
|
|
458
458
|
| V4.3.5 | **Summary 准确性修复 + UI 优化**:备份摘要改用 `diff-tree` 增量对比(修复 porcelain 假摘要 bug);仪表盘变更列三行堆叠布局;配色全面优化(背景层级 / 状态色 / 文字层级) | ✅ |
|
|
459
459
|
| V4.4.0 | **V4 收官版**:首次快照 summary(无 parent 时生成 Added N: ...);doctor 新增 Git retention 警告(>500 commits + disabled)和 Backup integrity 校验(`cat-file -t` tree 可达性);`cursor-guard-init` 升级检测(已有配置提示) | ✅ |
|
|
460
|
+
| V4.4.1 | **安全硬化版(5 项审计修复 + UX 优化)**:见下方详细说明 | ✅ |
|
|
461
|
+
| V4.5.0 | **V4 最终版(异常检测修复 + Dashboard 全面升级)**:见下方详细说明 | ✅ 收官 |
|
|
462
|
+
|
|
463
|
+
#### V4.4.1 详细内容
|
|
464
|
+
|
|
465
|
+
**安全修复(2×P1 + 3×P2)**:
|
|
466
|
+
|
|
467
|
+
| 级别 | 问题 | 修复 |
|
|
468
|
+
|------|------|------|
|
|
469
|
+
| P1 | `restoreFile` 接受目录 pathspec(`src`、`.cursor`)和项目根(`.`),单文件 API 能恢复整个目录或回滚受保护资产 | `validateRelativePath` 拦截 `.` 和空路径;`isToolPath` 匹配裸 `.cursor`;git 路径用 `cat-file -t` 验证必须是 blob(文件),tree(目录)直接拒绝;shadow 路径用 `statSync` 拦截目录 |
|
|
470
|
+
| P1 | `restore_project` 对 HEAD 已删除的受保护文件不处理,旧快照会把它们复活 | 恢复前用 `ls-tree HEAD -- <path>` 检查存在性,HEAD 中不存在的路径用 `rmSync/unlinkSync` 清除 |
|
|
471
|
+
| P2 | Git retention 重建链只保留 subject(`%s`),丢失 V4.3 审计 trailers | 改用 `%B`(完整 body + trailers),重建用 `fullBody` 传入 `commit-tree -m` |
|
|
472
|
+
| P2 | Dashboard 仅绑定 127.0.0.1 但无 Host/token 防护,可被 DNS rebinding 读取 | 加 Host header 校验(`127.0.0.1`/`localhost`)+ per-process 随机 token 注入 index.html,API 请求必须携带 |
|
|
473
|
+
| P2 | `doctor_fix` 初始化 Git 时 `git add -A` 会提交 `node_modules/` | 在 `git add -A` 前写入 `node_modules/` 和 `.cursor/skills/**/node_modules/` 到 `.gitignore` |
|
|
474
|
+
|
|
475
|
+
**回归测试**:新增 3 条负例锁定 restore 防线(目录 pathspec / 受保护 .cursor / 项目根 `.`),总测试 143/143 全绿。
|
|
476
|
+
|
|
477
|
+
**Dashboard UX**:
|
|
478
|
+
- 骨架屏加载(shimmer 占位,消除白屏→弹出的突兀感)
|
|
479
|
+
- 渐进渲染(`page-data?scope=` 按需返回,overview 先渲染,backups+doctor 并行加载)
|
|
480
|
+
- 备份 summary 行级统计(`git diff-tree --numstat`,每文件 `(+N -M)`),分行显示
|
|
481
|
+
- Summary 可见性提升(12px + secondary 颜色 + monospace 字体)
|
|
482
|
+
- 去除变更列冗余 trigger badge(类型列已有)
|
|
483
|
+
- Pre-restore 快照记录恢复方向(`From: <HEAD短hash>`、`Restore-To: <目标短hash>`、`File: <文件路径>`),表格琥珀色显示 `ab1b45d → f4029e9`
|
|
484
|
+
|
|
485
|
+
**架构级防护缺口修复**:
|
|
486
|
+
- MCP 工具注入 watcher 未运行警告(`_warning` 字段),AI 第一次调任何工具就能看到保护缺口
|
|
487
|
+
- SKILL.md Hard Rule #1 升级:"任何文件写入/删除前必须 snapshot"(之前仅要求"高风险操作前")
|
|
488
|
+
- SKILL.md 新增 Hard Rule #3a:"必须检查 watcher 状态"——看到 `_warning` 必须告知用户
|
|
489
|
+
|
|
490
|
+
#### V4.5.0 详细内容
|
|
491
|
+
|
|
492
|
+
**Bug 修复**:
|
|
493
|
+
|
|
494
|
+
| 问题 | 根因 | 修复 |
|
|
495
|
+
|------|------|------|
|
|
496
|
+
| 异常检测 `changedFileCount` 虚高 | `auto-backup.js` 用 `git status --porcelain`(对比 HEAD)计数,而非对比上一次备份的增量 | 改用 `createGitSnapshot` 返回的 `changedCount`(来自 `diff-tree`),异常检测和 Summary 共享同一数据源。移除了未使用的 `execFileSync` 和 `unquoteGitPath` 导入 |
|
|
497
|
+
| 诊断锁文件状态判断不够智能 | `doctor.js` Lock file 检测只要存在就报 WARN,不区分 watcher 是否在运行 | 加入 PID 存活判断(`process.kill(pid, 0)`):PID 在线 → PASS(`watcher running`);PID 已死 → WARN(`stale lock file`);无 PID → WARN(兜底)。前端 i18n 同步补全 `detail.lock_running` / `detail.lock_stale` / `detail.lock_exists` |
|
|
498
|
+
|
|
499
|
+
**Dashboard 升级(10 项改进)**:
|
|
500
|
+
|
|
501
|
+
| 优先级 | 改进 | 说明 |
|
|
502
|
+
|--------|------|------|
|
|
503
|
+
| 高 | 告警卡片补全 | 显示触发时间、过期倒计时(实时递减)、具体数字(N 文件 / N 秒 / 阈值 N) |
|
|
504
|
+
| 高 | 告警历史 | 保留最近 20 条告警记录,即使过期也显示在卡片下方(最近 5 条) |
|
|
505
|
+
| 中 | 文件搜索框 | 备份表格上方输入框,按文件名/意图/摘要实时过滤相关备份 |
|
|
506
|
+
| 中 | 恢复命令复制 | 抽屉底部显示 `restore_project` 和 `restore_file` MCP 命令,一键复制 |
|
|
507
|
+
| 低 | 筛选按钮计数 | "Git 自动备份 (12)" 而非仅 "Git 自动备份";无数据的类型自动隐藏 |
|
|
508
|
+
| 低 | Watcher 最后扫描 | 卡片增加 "最后扫描: 3s 前",确认 watcher 实际在工作 |
|
|
509
|
+
| 中 | 摘要展开/收起 | 变更摘要超过 2 行时自动折叠,显示 `+N more` 按钮点击展开;避免行过长截断,无需进抽屉即可看全 |
|
|
510
|
+
| 修复 | `showLoading` 引用 | 项目切换时调用了不存在的 `showLoading()`,改为 `showSkeleton()` |
|
|
511
|
+
| 优化 | i18n 补全 | 新增 14 个双语 key(告警详情、告警历史、文件搜索、恢复命令、扫描时间) |
|
|
460
512
|
|
|
461
513
|
> **注**:V4.2 的 Web 仪表盘最初在 V4.0 规划中标记为"不做",但用户需求明确后实施。事实证明只读仪表盘投入产出比合理,且不违反安全原则。
|
|
462
514
|
|
|
@@ -466,6 +518,18 @@ V4 经过 4 轮系统性代码审查,修复了以下关键问题:
|
|
|
466
518
|
- ~~不做 Web 仪表盘~~ → V4.2 已实施(只读、本地、零依赖)
|
|
467
519
|
- 不做云端同步
|
|
468
520
|
|
|
521
|
+
### V4 遗留的架构缺口(V5 接手)
|
|
522
|
+
|
|
523
|
+
通过 V4.4.1 的安全审计和真实场景测试,发现以下架构层面的保护缺口。这些不是代码 bug,而是设计边界:
|
|
524
|
+
|
|
525
|
+
| 缺口 | 现状 | 影响 | V5 改进方向 |
|
|
526
|
+
|------|------|------|------------|
|
|
527
|
+
| **Watcher 停止 = 裸奔** | Watcher 不运行期间的文件变更无任何自动备份 | 如果 AI agent 也没手动 snapshot,变更永久丢失 | **`always_watch` 配置项**:在 `.cursor-guard.json` 中设置 `"always_watch": true`,MCP server 启动时自动 fork watcher 进程。用户可选两种模式:轻量模式(默认,AI 手动 snapshot)和强保护模式(watcher 始终在后台) |
|
|
528
|
+
| **保护依赖 AI 自觉** | SKILL.md 要求 AI 在写入前 snapshot,但没有强制机制 | AI 不遵守协议就直接写,保护形同虚设 | **embedded watcher + `begin_edit` 意图绑定**:MCP server 内嵌 watcher 循环 + 按文件路径匹配 intent,消除进程边界和并发竞争(详见 V5 设计) |
|
|
529
|
+
| **自动备份无意图上下文** | auto-backup 只有 `trigger: auto`,不知道是谁改的、为什么改 | 事后回溯只能看到时间点快照,不知道操作意图 | **`begin_edit` → 文件路径绑定**:AI 编辑前声明意图和目标文件,embedded watcher 检测变更时按路径匹配 intent,自动备份也能带上下文 |
|
|
530
|
+
| **无跨进程写拦截** | 当前 MCP 架构下无法拦截 Cursor 编辑器的文件写入 | 只能在写后检测,不能写前阻止 | 等待 MCP 协议支持 `notification` / `resource subscription`,或探索 fs watch + pre-commit 组合 |
|
|
531
|
+
| **意图队列并发问题** | 曾考虑"意图队列"(AI 写文件 → watcher 读文件关联 intent),但存在 4 类并发竞态:多 Agent 竞争、意图-变更错位、意图堆积、空意图残留 | 文件 I/O 跨进程 + 时间顺序绑定 = 不可靠 | **同进程内存 Map + 文件路径绑定**:消灭进程边界后无 IPC,按路径而非时间匹配消除歧义(详见 V5 设计) |
|
|
532
|
+
|
|
469
533
|
### 进入 V5 的衡量标准
|
|
470
534
|
|
|
471
535
|
- V4 的主动提醒功能误报率 < 10%
|
|
@@ -522,8 +586,101 @@ V5 不是"三个方向选一个",而是把下面这条链路做完整:
|
|
|
522
586
|
| `impact set` | 为高风险编辑记录受影响文件 / 符号 / 测试集合 | `impact_set` 字段 | 查询事件时能看到"这次改动可能波及哪里" |
|
|
523
587
|
| `MCP / CLI surface` | 暴露最小可用接口给 Agent 和终端 | `register_intent` / `list_active_intents` / `audit_query` / `get_event` / `restore_from_event` | AI 不需要拼复杂 shell,就能完成查询与恢复 |
|
|
524
588
|
| `dashboard / doctor` | 把活跃会话、冲突告警、最近 AI 事件纳入诊断和看板 | `dashboard` / `doctor` 扩展字段 | 用户能看见"现在谁在改、最近改了什么、哪里有冲突" |
|
|
589
|
+
| `always_watch` | 配置项 `"always_watch": true`,MCP server 启动时自动内嵌 watcher 循环;用户可选两种保护模式:**轻量模式**(默认,AI 手动 `snapshot_now`)vs **强保护模式**(watcher 始终在后台,所有变更自动备份) | `.cursor-guard.json` 配置 + MCP server 启动逻辑 | MCP server 启动后,`always_watch: true` 的项目自动有 watcher 保护,无需额外命令;选择权在用户 |
|
|
590
|
+
| `embedded watcher` | **消灭进程边界**:不再是独立后台进程,而是 MCP server 同进程内的 watcher 循环。同进程 = 无 IPC、无文件桥接、无并发竞争。检测到文件变更时自动创建 snapshot,不依赖 AI 手动调用 | MCP server 内部模块 | watcher 停止 = 裸奔的保护缺口彻底消除;AI 忘记 snapshot 也有兜底 |
|
|
591
|
+
| `begin_edit` / `end_edit` | **意图-变更原子绑定**:AI 编辑前调 `begin_edit({ intent, files[], agent, session })`,在内存 `Map<session, EditScope>` 注册编辑意图和目标文件。embedded watcher 检测到变更时按**文件路径**匹配 intent,自动备份带完整上下文。`end_edit(session)` 或 TTL(默认 5 分钟)自动清除 | `begin_edit` / `end_edit` MCP 工具 + 内存 `activeEdits` Map | auto-backup 也能带 intent/agent/session;并发多 Agent 按文件路径消歧,不按时间顺序 |
|
|
525
592
|
| `tests / docs` | 为事件链路补齐单测、集成测试和文档 | tests + schema docs | V5.0 的所有核心事件和恢复路径都有测试覆盖 |
|
|
526
593
|
|
|
594
|
+
### V5 核心设计:Embedded Watcher + 文件路径意图绑定
|
|
595
|
+
|
|
596
|
+
#### 问题根因
|
|
597
|
+
|
|
598
|
+
V4 的自动备份(auto-backup)和意图上下文(intent)分属两个独立进程:
|
|
599
|
+
|
|
600
|
+
```
|
|
601
|
+
MCP Server 进程(知道 intent) ←——×——→ Watcher 进程(知道文件变了)
|
|
602
|
+
↑ ↑
|
|
603
|
+
AI agent 调用 fs 检测循环
|
|
604
|
+
有上下文 无上下文
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
- `auto-backup.js` 调用 snapshot 时只传 `{ trigger: 'auto', changedFileCount }`,没有 intent/agent/session
|
|
608
|
+
- 只有 `snapshot_now` MCP 工具支持 intent 参数
|
|
609
|
+
- 曾考虑"意图队列"(AI 写文件 → watcher 读文件关联),但存在 4 类并发竞态:
|
|
610
|
+
|
|
611
|
+
| 竞态场景 | 描述 |
|
|
612
|
+
|---------|------|
|
|
613
|
+
| 多 Agent 竞争 | A 提交意图 → B 提交意图 → watcher 触发 → 绑谁的? |
|
|
614
|
+
| 意图-变更错位 | A 提交意图但未改文件 → B 改了另一个文件 → A 的意图被错绑到 B 的变更 |
|
|
615
|
+
| 意图堆积 | 一个 cycle 内多个 agent 提交意图 → watcher 只产生一次 commit → 意图丢失或错配 |
|
|
616
|
+
| 空意图残留 | Agent 提交意图后放弃 → 意图留在队列 → 被绑到下一次无关变更 |
|
|
617
|
+
|
|
618
|
+
根本原因:**意图提交和文件变更是两个独立事件,跨进程 + 按时间绑定 = 无法原子化**。
|
|
619
|
+
|
|
620
|
+
#### 方案:同进程 + 按文件路径绑定
|
|
621
|
+
|
|
622
|
+
```
|
|
623
|
+
┌─────────────── MCP Server 进程(V5) ──────────────────┐
|
|
624
|
+
│ │
|
|
625
|
+
│ AI agent 调用 内存 activeEdits │
|
|
626
|
+
│ begin_edit({ Map<session, { │
|
|
627
|
+
│ intent, → intent, files[], │
|
|
628
|
+
│ files[], agent, timestamp, │
|
|
629
|
+
│ agent, ttl │
|
|
630
|
+
│ session }> │
|
|
631
|
+
│ }) ↓ 直接读取(同进程) │
|
|
632
|
+
│ │
|
|
633
|
+
│ Embedded Watcher 循环 ←─── 检测到 src/auth.ts 变更 │
|
|
634
|
+
│ 查 activeEdits: │
|
|
635
|
+
│ s1 声明了 [src/auth.ts] → 匹配 ✅ │
|
|
636
|
+
│ s2 声明了 [src/style.css] → 不匹配 ❌ │
|
|
637
|
+
│ → 创建 auto-backup commit 带 s1 的 intent │
|
|
638
|
+
│ │
|
|
639
|
+
└─────────────────────────────────────────────────────────┘
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
**核心优势**:
|
|
643
|
+
- **同进程**:无 IPC、无文件 I/O、无并发竞争(Node.js 单线程 event loop)
|
|
644
|
+
- **按文件路径绑定**:不同 Agent 改不同文件时各自匹配,无歧义
|
|
645
|
+
- **TTL 自动过期**:空意图 5 分钟后自动清除,不会残留
|
|
646
|
+
- **多 Agent 同文件**:标记为 `multi-agent overlap`,附上所有匹配意图(同时作为冲突检测信号)
|
|
647
|
+
|
|
648
|
+
#### 并发场景处理
|
|
649
|
+
|
|
650
|
+
| 场景 | 处理方式 |
|
|
651
|
+
|------|---------|
|
|
652
|
+
| A 改 `auth.ts`,B 改 `style.css` | 各自匹配各自的 `begin_edit` scope,零歧义 |
|
|
653
|
+
| A、B 都声明要改 `auth.ts` | `begin_edit` 时即检测到重叠,返回 advisory warning;auto-backup 附上两个 intent |
|
|
654
|
+
| A 声明了意图但没改文件 | TTL 到期自动清除;`end_edit` 可提前关闭 |
|
|
655
|
+
| 文件变更但没有任何 `begin_edit` | 降级为普通 auto-backup(和 V4 行为一致,无退化) |
|
|
656
|
+
| AI 直接调 `snapshot_now(intent=...)` | 和现在一模一样,完全兼容 |
|
|
657
|
+
|
|
658
|
+
#### 实现分期
|
|
659
|
+
|
|
660
|
+
```
|
|
661
|
+
Phase 1 (V5.0):
|
|
662
|
+
├── always_watch: true → MCP server 内嵌 watcher 循环
|
|
663
|
+
├── 新增 begin_edit / end_edit MCP 工具
|
|
664
|
+
├── 内存 Map<session, EditScope> 管理活跃编辑意图
|
|
665
|
+
└── watcher 变更检测时查 Map,按文件路径匹配 intent → 写入 commit trailer
|
|
666
|
+
|
|
667
|
+
Phase 2 (V5.x):
|
|
668
|
+
├── begin_edit → 产生 intent_registered 事件(写入审计存储)
|
|
669
|
+
├── 文件变更 → 产生 edit_applied 事件(关联 intent + before_ref)
|
|
670
|
+
├── end_edit → 产生 intent_released 事件
|
|
671
|
+
└── 完整审计链闭环,支持 restore_from_event
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
#### 与"意图队列"方案的本质区别
|
|
675
|
+
|
|
676
|
+
| | 意图队列(已否决) | embedded watcher + begin_edit |
|
|
677
|
+
|---|---|---|
|
|
678
|
+
| 通信方式 | 文件 I/O(跨进程) | 内存 Map(同进程) |
|
|
679
|
+
| 绑定维度 | 时间顺序(先进先出) | 文件路径(精确匹配) |
|
|
680
|
+
| 并发安全 | 4 类竞态条件 | 无竞态(单进程 event loop) |
|
|
681
|
+
| 空意图处理 | 残留在文件中 | TTL 自动过期 + `end_edit` 显式关闭 |
|
|
682
|
+
| 多 Agent 消歧 | 无法消歧 | 文件路径级消歧 + 冲突检测信号 |
|
|
683
|
+
|
|
527
684
|
### V5 主线 A:并发编辑安全(预防层)
|
|
528
685
|
|
|
529
686
|
```
|
|
@@ -650,6 +807,10 @@ V5 的关键不是"多打一行日志",而是建立完整证据链:
|
|
|
650
807
|
|
|
651
808
|
### V5 完成标志(Definition of Done)
|
|
652
809
|
|
|
810
|
+
- `always_watch: true` 配置生效后,MCP server 启动自动内嵌 watcher 循环,用户无需额外命令
|
|
811
|
+
- `begin_edit` / `end_edit` MCP 工具可用,AI 能声明编辑意图和目标文件
|
|
812
|
+
- embedded watcher 的自动备份能通过文件路径匹配关联 `begin_edit` 中的 intent/agent/session
|
|
813
|
+
- 无 `begin_edit` 时自动备份行为与 V4 一致(无退化)
|
|
653
814
|
- AI 能在高风险写入前注册意图并创建 `pre-edit` 快照
|
|
654
815
|
- 用户能查询最近一次 AI 编辑的完整上下文
|
|
655
816
|
- 给定 `event_id` 能找到对应快照并执行恢复
|
package/SKILL.md
CHANGED
|
@@ -147,7 +147,7 @@ When the target file of an edit **falls outside the protected scope**, the agent
|
|
|
147
147
|
|
|
148
148
|
> **MCP shortcut**: if `snapshot_now` tool is available, call it with `{ "path": "<project>", "strategy": "git" }` instead of the shell commands below. The tool handles temp index, secrets exclusion, and ref creation internally, and returns `{ "git": { "status": "created", "commitHash": "...", "shortHash": "..." } }`. Report the `shortHash` to the user and proceed.
|
|
149
149
|
>
|
|
150
|
-
> **Best practice — intent context**:
|
|
150
|
+
> **Best practice — intent context**: Before making high-risk changes, call `snapshot_now` with `intent` to directly record what you are about to do. The intent is stored in the Git commit trailer — no intermediary, no file bridge, no concurrency issues. Example:
|
|
151
151
|
> ```json
|
|
152
152
|
> {
|
|
153
153
|
> "path": "/project",
|
|
@@ -158,7 +158,9 @@ When the target file of an edit **falls outside the protected scope**, the agent
|
|
|
158
158
|
> "session": "6290c87f"
|
|
159
159
|
> }
|
|
160
160
|
> ```
|
|
161
|
-
> The `intent`, `agent`, and `session` fields are stored as Git commit trailers and displayed in the dashboard restore-point list and detail drawer
|
|
161
|
+
> The `intent`, `agent`, and `session` fields are stored as Git commit trailers and displayed in the dashboard restore-point list and detail drawer.
|
|
162
|
+
>
|
|
163
|
+
> **Timeline the user sees**: manual snapshot with intent ("AI准备重构 calculator.js") → auto-backup with file changes ("Modified 2: src/app.js (+15 -3)"). The causal relationship is clear from ordering — the manual snapshot explains WHY, the auto-backup shows WHAT changed.
|
|
162
164
|
|
|
163
165
|
Use a **temporary index and dedicated ref** so the user's staged/unstaged state is never touched:
|
|
164
166
|
|
|
@@ -569,9 +571,10 @@ Skip the block for unrelated turns.
|
|
|
569
571
|
|
|
570
572
|
## Hard Rules (Non-Negotiable)
|
|
571
573
|
|
|
572
|
-
1. **MUST snapshot before
|
|
574
|
+
1. **MUST snapshot before ANY file write or delete** — call `snapshot_now` (with `intent`) before creating, editing, or deleting files. This is NOT optional and NOT just for "high-risk" operations. Every write is potentially destructive. No exceptions unless user explicitly says "不用备份" / "skip backup". If the MCP response includes `_warning` about the watcher being stopped, tell the user immediately.
|
|
573
575
|
2. **MUST Read before Write** — never overwrite a file the agent hasn't read in the current turn.
|
|
574
576
|
3. **MUST preserve current version before restore** — every restore operation must first snapshot the current state (§5a Step 4). Skip ONLY when: (a) user explicitly opts out, (b) current state is identical to target, or (c) no changes exist. If preservation fails, abort restore by default.
|
|
577
|
+
3a. **MUST check watcher status** — if any MCP tool returns `_warning` about the watcher not running, immediately warn the user: "自动备份守护进程未运行,当前处于无保护状态。建议先启动 watcher 或在每次修改前手动调用 snapshot_now。" Do NOT silently continue editing files without protection.
|
|
575
578
|
4. **Do not** treat Timeline/Checkpoints as the only or primary recovery path.
|
|
576
579
|
5. **Do not** recommend Checkpoints as long-term or sole backup.
|
|
577
580
|
6. **No automatic push** to remotes; local commits only unless user requests push.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursor-guard",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.1",
|
|
4
4
|
"description": "Protects code from accidental AI overwrite or deletion in Cursor IDE — mandatory pre-write snapshots, review-before-apply, local Git safety net, and deterministic recovery. | 保护代码免受 Cursor AI 代理意外覆写或删除——强制写前快照、预览再执行、本地 Git 安全网、确定性恢复。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cursor",
|
|
@@ -12,6 +12,7 @@ if (args.help || args.h) {
|
|
|
12
12
|
Options:
|
|
13
13
|
--path <dir> Project directory to watch (default: current dir)
|
|
14
14
|
--interval <sec> Override backup interval in seconds
|
|
15
|
+
--dashboard [port] Start dashboard server alongside watcher (default port: 3120)
|
|
15
16
|
--help, -h Show this help message
|
|
16
17
|
--version, -v Show version number`);
|
|
17
18
|
process.exit(0);
|
|
@@ -27,5 +28,12 @@ const targetPath = args.path || '.';
|
|
|
27
28
|
const interval = parseInt(args.interval, 10) || 0;
|
|
28
29
|
const resolved = path.resolve(targetPath);
|
|
29
30
|
|
|
31
|
+
const opts = {};
|
|
32
|
+
if (args.dashboard !== undefined) {
|
|
33
|
+
opts.dashboardPort = (typeof args.dashboard === 'string' && /^\d+$/.test(args.dashboard))
|
|
34
|
+
? parseInt(args.dashboard, 10)
|
|
35
|
+
: 3120;
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
const { runBackup } = require('../lib/auto-backup');
|
|
31
|
-
runBackup(resolved, interval);
|
|
39
|
+
runBackup(resolved, interval, opts);
|