cursor-guard 4.6.0 → 4.6.2

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/LICENSE CHANGED
@@ -1,21 +1,65 @@
1
- MIT License
2
-
3
- Copyright (c) 2026
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: zhangqiang8vipp
6
+ Licensed Work: cursor-guard
7
+ The Licensed Work is (c) 2026 zhangqiang8vipp
8
+ Additional Use Grant: You may make use of the Licensed Work, provided that
9
+ you may not use the Licensed Work for a Commercial Use.
10
+ "Commercial Use" means distribution, sale, licensing,
11
+ sublicensing, or providing the Licensed Work (or any
12
+ derivative work) to third parties as a paid product or
13
+ service, or incorporating it into a paid product or
14
+ service offered to third parties.
15
+ Change Date: 2056-03-22
16
+ Change License: Apache License, Version 2.0
17
+
18
+ For information about alternative licensing arrangements for the Licensed Work,
19
+ please contact: zhangqiang8vipp
20
+
21
+ Notice
22
+
23
+ Business Source License 1.1
24
+
25
+ Terms
26
+
27
+ The Licensor hereby grants you the right to copy, modify, create derivative
28
+ works, redistribute, and make non-commercial use of the Licensed Work. The
29
+ Licensor may make an Additional Use Grant, above, permitting limited commercial
30
+ use.
31
+
32
+ Effective on the Change Date, or the fourth anniversary of the first publicly
33
+ available distribution of a specific version of the Licensed Work under this
34
+ License, whichever comes first, the Licensor hereby grants you rights under
35
+ the terms of the Change License, and the rights granted in the paragraph
36
+ above terminate.
37
+
38
+ If your use of the Licensed Work does not comply with the requirements
39
+ currently in effect as described in this License, you must purchase a
40
+ commercial license from the Licensor, its affiliated entities, or authorized
41
+ resellers, or you must refrain from using the Licensed Work.
42
+
43
+ All copies of the original and modified Licensed Work, and derivative works
44
+ of the Licensed Work, are subject to this License. This License applies
45
+ separately for each version of the Licensed Work and the Change Date may vary
46
+ for each version of the Licensed Work released by Licensor.
47
+
48
+ You must conspicuously display this License on each original or modified copy
49
+ of the Licensed Work. If you receive the Licensed Work in original or
50
+ modified form from a third party, the terms and conditions set forth in this
51
+ License apply to your use of that work.
52
+
53
+ Any use of the Licensed Work in violation of this License will automatically
54
+ terminate your rights under this License for the current and all other
55
+ versions of the Licensed Work.
56
+
57
+ This License does not grant you any right in any trademark or logo of
58
+ Licensor or its affiliates (provided that you may use a trademark or logo of
59
+ Licensor as expressly required by this License).
60
+
61
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
62
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
63
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
64
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
65
+ TITLE.
package/ROADMAP.md CHANGED
@@ -3,8 +3,8 @@
3
3
  > 本文档描述 cursor-guard 从 V2 到 V7 的长期演进方向。
4
4
  > 每一代向下兼容,低版本功能永远不废弃。
5
5
  >
6
- > **当前版本**:`V4.6.0`
7
- > **文档状态**:`V2` ~ `V4.6.0` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
6
+ > **当前版本**:`V4.6.1`
7
+ > **文档状态**:`V2` ~ `V4.6.1` 已完成交付(含 V5 intent/audit 基础),`V5` 主体规划中
8
8
 
9
9
  ## 阅读导航
10
10
 
@@ -466,6 +466,7 @@ V4 经过 4 轮系统性代码审查,修复了以下关键问题:
466
466
  | V4.5.7 | **文件详情 Modal 修复 + Dashboard 端口复用**:见下方详细说明 | ✅ |
467
467
  | V4.5.8 | **Dashboard 版本更新检测 + 一键重启**:见下方详细说明 | ✅ |
468
468
  | V4.6.0 | **告警 UX 全面升级**:见下方详细说明 | ✅ |
469
+ | V4.6.1 | **告警历史弹窗化**:见下方详细说明 | ✅ |
469
470
 
470
471
  #### V4.4.1 详细内容
471
472
 
@@ -698,6 +699,17 @@ V4 经过 4 轮系统性代码审查,修复了以下关键问题:
698
699
  | 告警历史常驻入口 | `buildAlertHistoryHtml()` 提取为独立函数,在活跃告警和无告警两种状态下都渲染"历史 N 条"折叠按钮,告警激活时也能查看历史 |
699
700
  | 告警历史 localStorage 持久化 | 新增 `loadAlertHistory()` / `saveAlertHistory()`,使用 `localStorage` key `cursorGuard_alertHistory` 持久化最近 20 条告警历史,刷新页面不丢失 |
700
701
 
702
+ #### V4.6.1 详细内容
703
+
704
+ **告警历史弹窗化**:
705
+
706
+ | 改动 | 说明 |
707
+ |------|------|
708
+ | 历史按钮改为弹窗触发 | "历史 N 条"按钮点击后打开全屏 Modal(复用 `file-modal`),不再内联折叠展开 |
709
+ | 历史表格化展示 | Modal 内以表格呈现所有历史告警:触发时间、详情、文件类型分布、文件列表按钮 |
710
+ | 嵌套文件详情 | 每条历史告警的"查看文件"按钮可再打开文件详情 Modal,查看具体变更文件列表 |
711
+ | 新增 i18n keys | `alert.col.detail` / `alert.col.breakdown` / `alert.col.files`(中英双语) |
712
+
701
713
  #### V4.5.x 新增配置参考
702
714
 
703
715
  | 字段 | 类型 | 默认值 | 引入版本 | 说明 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-guard",
3
- "version": "4.6.0",
3
+ "version": "4.6.2",
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",
@@ -14,7 +14,7 @@
14
14
  "cross-platform"
15
15
  ],
16
16
  "author": "zhangqiang8vipp",
17
- "license": "MIT",
17
+ "license": "BUSL-1.1",
18
18
  "repository": {
19
19
  "type": "git",
20
20
  "url": "https://github.com/zhangqiang8vipp/cursor-guard.git"
@@ -52,6 +52,9 @@ const I18N = {
52
52
  'alert.col.file': 'File',
53
53
  'alert.col.action': 'Action',
54
54
  'alert.col.changes':'Changes',
55
+ 'alert.col.detail': 'Detail',
56
+ 'alert.col.breakdown': 'Breakdown',
57
+ 'alert.col.files': 'Files',
55
58
  'alert.action.modified': 'Modified',
56
59
  'alert.action.added': 'Added',
57
60
  'alert.action.deleted': 'Deleted',
@@ -276,6 +279,9 @@ const I18N = {
276
279
  'alert.col.file': '文件',
277
280
  'alert.col.action': '操作',
278
281
  'alert.col.changes':'变化量',
282
+ 'alert.col.detail': '详情',
283
+ 'alert.col.breakdown': '文件类型',
284
+ 'alert.col.files': '文件列表',
279
285
  'alert.action.modified': '修改',
280
286
  'alert.action.added': '新增',
281
287
  'alert.action.deleted': '删除',
@@ -913,24 +919,55 @@ function alertFileBreakdown(files) {
913
919
  function buildAlertHistoryHtml() {
914
920
  if (state.alertHistory.length === 0) return '';
915
921
  const count = state.alertHistory.length;
916
- const rows = state.alertHistory.slice(-5).reverse().map(h => {
917
- const breakdown = alertFileBreakdown(h.files);
918
- return `<div class="alert-history-row text-sm text-muted">
919
- <span class="alert-history-time">${esc(formatTime(h.timestamp))}</span>
920
- <span>${t('alert.detail', { count: h.fileCount, window: h.windowSeconds, threshold: h.threshold })}</span>
921
- ${breakdown ? `<span class="alert-history-breakdown">${esc(breakdown)}</span>` : ''}
922
- <span class="badge badge-expired">${t('alert.expired')}</span>
923
- </div>`;
924
- }).join('');
925
922
  return `
926
923
  <div class="alert-history-toggle-wrap">
927
- <button class="alert-history-toggle-btn text-sm text-muted" data-alert-history-toggle>${t('alert.historyCount', { n: count })}</button>
928
- </div>
929
- <div class="alert-history alert-history-collapsed">
930
- <div class="alert-history-label text-sm">${t('alert.history')}</div>${rows}
924
+ <button class="alert-history-toggle-btn text-sm text-muted" data-alert-history-modal>${t('alert.historyCount', { n: count })}</button>
931
925
  </div>`;
932
926
  }
933
927
 
928
+ function openAlertHistoryModal() {
929
+ const list = [...state.alertHistory].reverse();
930
+ if (list.length === 0) return;
931
+ $('#file-modal-title').textContent = t('alert.history');
932
+ const body = $('#file-modal-body');
933
+
934
+ const rows = list.map((h, i) => {
935
+ const breakdown = alertFileBreakdown(h.files);
936
+ const fileCount = Array.isArray(h.files) ? h.files.length : 0;
937
+ return `<tr>
938
+ <td class="text-mono">${esc(formatTime(h.timestamp))}</td>
939
+ <td>${t('alert.detail', { count: h.fileCount, window: h.windowSeconds, threshold: h.threshold })}</td>
940
+ <td>${breakdown ? esc(breakdown) : '-'}</td>
941
+ <td>${fileCount > 0 ? `<button class="modal-restore-btn" data-history-files="${i}">${t('alert.viewFiles', { n: fileCount })}</button>` : '-'}</td>
942
+ </tr>`;
943
+ }).join('');
944
+
945
+ body.innerHTML = `<table>
946
+ <thead><tr>
947
+ <th>${t('alert.triggered')}</th>
948
+ <th>${t('alert.col.detail')}</th>
949
+ <th>${t('alert.col.breakdown')}</th>
950
+ <th>${t('alert.col.files')}</th>
951
+ </tr></thead>
952
+ <tbody>${rows}</tbody>
953
+ </table>`;
954
+
955
+ body.addEventListener('click', (e) => {
956
+ const btn = e.target.closest('[data-history-files]');
957
+ if (btn) {
958
+ const idx = parseInt(btn.dataset.historyFiles);
959
+ const h = list[idx];
960
+ if (h?.files?.length > 0) {
961
+ const proj = state.pageData?.dashboard?.watcher?.path || '';
962
+ openFileModal(t('modal.alertFiles'), h.files, proj, '');
963
+ }
964
+ }
965
+ });
966
+
967
+ $('#file-modal-overlay').classList.add('active');
968
+ document.body.style.overflow = 'hidden';
969
+ }
970
+
934
971
  function renderAlertCard(alerts) {
935
972
  const el = $('#card-alert');
936
973
  if (!alerts?.active) {
@@ -1573,13 +1610,11 @@ function setupEvents() {
1573
1610
  if (backup) openRestoreDrawer(backup);
1574
1611
  });
1575
1612
 
1576
- // Alert history toggle + file modal (event delegation)
1613
+ // Alert history modal + file modal (event delegation)
1577
1614
  $('#card-alert').addEventListener('click', (e) => {
1578
- const historyToggle = e.target.closest('[data-alert-history-toggle]');
1579
- if (historyToggle) {
1580
- const card = historyToggle.closest('#card-alert');
1581
- const history = card?.querySelector('.alert-history');
1582
- if (history) history.classList.toggle('alert-history-collapsed');
1615
+ const historyBtn = e.target.closest('[data-alert-history-modal]');
1616
+ if (historyBtn) {
1617
+ openAlertHistoryModal();
1583
1618
  return;
1584
1619
  }
1585
1620
  const modalBtn = e.target.closest('[data-alert-files-modal]');