cursor-guard 4.9.9 → 4.9.15

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.
Files changed (35) hide show
  1. package/README.md +697 -697
  2. package/README.zh-CN.md +696 -696
  3. package/ROADMAP.md +1775 -1720
  4. package/SKILL.md +631 -629
  5. package/docs/RELEASE.md +197 -196
  6. package/docs/SNAPSHOT-BOOKMARK.md +47 -0
  7. package/package.json +70 -69
  8. package/references/dashboard/public/app.js +2079 -1832
  9. package/references/dashboard/public/style.css +1660 -1573
  10. package/references/dashboard/server.js +197 -4
  11. package/references/lib/core/backups.js +509 -492
  12. package/references/lib/core/core.test.js +1761 -1616
  13. package/references/lib/core/snapshot.js +441 -369
  14. package/references/mcp/mcp.test.js +381 -362
  15. package/references/mcp/server.js +404 -347
  16. package/references/vscode-extension/dist/{cursor-guard-ide-4.9.9.vsix → cursor-guard-ide-4.9.15.vsix} +0 -0
  17. package/references/vscode-extension/dist/dashboard/public/app.js +2079 -1832
  18. package/references/vscode-extension/dist/dashboard/public/style.css +1660 -1573
  19. package/references/vscode-extension/dist/dashboard/server.js +197 -4
  20. package/references/vscode-extension/dist/extension.js +780 -704
  21. package/references/vscode-extension/dist/guard-version.json +1 -1
  22. package/references/vscode-extension/dist/lib/auto-setup.js +201 -192
  23. package/references/vscode-extension/dist/lib/core/backups.js +509 -492
  24. package/references/vscode-extension/dist/lib/core/snapshot.js +441 -369
  25. package/references/vscode-extension/dist/lib/poller.js +161 -21
  26. package/references/vscode-extension/dist/lib/sidebar-webview.js +22 -0
  27. package/references/vscode-extension/dist/mcp/server.js +152 -35
  28. package/references/vscode-extension/dist/package.json +7 -1
  29. package/references/vscode-extension/dist/skill/ROADMAP.md +1775 -1720
  30. package/references/vscode-extension/dist/skill/SKILL.md +631 -629
  31. package/references/vscode-extension/extension.js +780 -704
  32. package/references/vscode-extension/lib/auto-setup.js +201 -192
  33. package/references/vscode-extension/lib/poller.js +161 -21
  34. package/references/vscode-extension/lib/sidebar-webview.js +22 -0
  35. package/references/vscode-extension/package.json +146 -140
@@ -1 +1 @@
1
- {"version":"4.9.9"}
1
+ {"version":"4.9.15"}
@@ -1,192 +1,201 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- function detectIdeDir(vscode) {
7
- const appName = (vscode.env.appName || '').toLowerCase();
8
- const home = process.env.USERPROFILE || process.env.HOME || '';
9
-
10
- const ideDirs = [];
11
-
12
- if (appName.includes('cursor')) {
13
- ideDirs.push('.cursor');
14
- } else if (appName.includes('windsurf')) {
15
- ideDirs.push('.windsurf');
16
- } else if (appName.includes('trae')) {
17
- ideDirs.push('.trae');
18
- }
19
-
20
- ideDirs.push('.cursor', '.windsurf', '.vscode');
21
-
22
- const seen = new Set();
23
- for (const dir of ideDirs) {
24
- if (seen.has(dir)) continue;
25
- seen.add(dir);
26
- const full = path.join(home, dir);
27
- if (fs.existsSync(full)) return { dirName: dir, homePath: full };
28
- }
29
-
30
- return { dirName: ideDirs[0], homePath: path.join(home, ideDirs[0]) };
31
- }
32
-
33
- function getExtensionRoot(context) {
34
- return context.extensionPath;
35
- }
36
-
37
- function findBundledSkill(extRoot) {
38
- const skillDir = path.join(extRoot, 'skill');
39
- if (fs.existsSync(path.join(skillDir, 'SKILL.md'))) return skillDir;
40
- const fromRefs = path.resolve(extRoot, '..', '..', 'SKILL.md');
41
- if (fs.existsSync(fromRefs)) return path.resolve(extRoot, '..', '..');
42
- return null;
43
- }
44
-
45
- async function autoSetup(context, vscode) {
46
- const extRoot = getExtensionRoot(context);
47
- const { dirName, homePath } = detectIdeDir(vscode);
48
- const workspaceFolders = vscode.workspace.workspaceFolders;
49
- const wsRoot = workspaceFolders?.[0]?.uri.fsPath;
50
-
51
- const actions = [];
52
-
53
- try { actions.push(...autoInstallSkill(extRoot, homePath, dirName)); } catch { /* non-critical */ }
54
- try { actions.push(...autoRegisterMcp(extRoot, homePath, wsRoot)); } catch { /* non-critical */ }
55
- if (wsRoot) {
56
- try { actions.push(...autoCreateConfig(extRoot, wsRoot)); } catch { /* non-critical */ }
57
- }
58
-
59
- if (actions.length > 0) {
60
- vscode.window.showInformationMessage(`Cursor Guard: auto-setup complete — ${actions.join(', ')}`);
61
- }
62
- }
63
-
64
- function autoInstallSkill(extRoot, homePath, dirName) {
65
- const actions = [];
66
- const skillSrc = findBundledSkill(extRoot);
67
- if (!skillSrc) return actions;
68
-
69
- const skillTarget = path.join(homePath, 'skills', 'cursor-guard');
70
- fs.mkdirSync(skillTarget, { recursive: true });
71
-
72
- // ── Install/update SKILL.md and ROADMAP.md ──
73
- const skillMdSrc = path.join(skillSrc, 'SKILL.md');
74
- const skillMdTarget = path.join(skillTarget, 'SKILL.md');
75
- if (fs.existsSync(skillMdSrc) && !fs.existsSync(skillMdTarget)) {
76
- fs.copyFileSync(skillMdSrc, skillMdTarget);
77
- actions.push('SKILL.md installed');
78
- }
79
-
80
- const roadmapSrc = path.join(skillSrc, 'ROADMAP.md');
81
- const roadmapDst = path.join(skillTarget, 'ROADMAP.md');
82
- if (fs.existsSync(roadmapSrc) && !fs.existsSync(roadmapDst)) {
83
- fs.copyFileSync(roadmapSrc, roadmapDst);
84
- }
85
-
86
- // ── Ensure references/ junction exists (runs even for existing installations) ──
87
- const refsTarget = path.join(skillTarget, 'references');
88
- const refsIsJunction = _isSymlinkOrJunction(refsTarget);
89
- const refsIsPlainDir = !refsIsJunction && fs.existsSync(refsTarget);
90
- const refsMissingRuntime = refsIsPlainDir && !fs.existsSync(path.join(refsTarget, 'mcp'));
91
-
92
- if (!fs.existsSync(refsTarget) || refsMissingRuntime) {
93
- // Remove old plain directory if it only has docs (no runtime)
94
- if (refsMissingRuntime) {
95
- try { fs.rmSync(refsTarget, { recursive: true, force: true }); } catch { /* ok */ }
96
- }
97
- try {
98
- fs.symlinkSync(extRoot, refsTarget, 'junction');
99
- actions.push('references/ linked');
100
- } catch {
101
- fs.mkdirSync(refsTarget, { recursive: true });
102
- _copyDocFiles(skillSrc, refsTarget);
103
- }
104
- }
105
-
106
- // ── Ensure package.json exists ──
107
- const pkgDst = path.join(skillTarget, 'package.json');
108
- if (!fs.existsSync(pkgDst)) {
109
- const pkgSrc = path.join(extRoot, '..', '..', 'package.json');
110
- const guardVer = path.join(extRoot, 'guard-version.json');
111
- if (fs.existsSync(pkgSrc)) {
112
- fs.copyFileSync(pkgSrc, pkgDst);
113
- } else if (fs.existsSync(guardVer)) {
114
- fs.copyFileSync(guardVer, pkgDst);
115
- }
116
- }
117
-
118
- return actions;
119
- }
120
-
121
- function _isSymlinkOrJunction(p) {
122
- try {
123
- const stat = fs.lstatSync(p);
124
- return stat.isSymbolicLink();
125
- } catch { return false; }
126
- }
127
-
128
- function _copyDocFiles(skillSrc, refsTarget) {
129
- const docs = [
130
- 'config-reference.md', 'config-reference.zh-CN.md',
131
- 'recovery.md', 'cursor-guard.schema.json', 'cursor-guard.example.json',
132
- ];
133
- for (const f of docs) {
134
- const src = path.join(skillSrc, f);
135
- if (fs.existsSync(src)) fs.copyFileSync(src, path.join(refsTarget, f));
136
- }
137
- }
138
-
139
- function autoRegisterMcp(extRoot, homePath, wsRoot) {
140
- const actions = [];
141
- const mcpServerPath = path.join(extRoot, 'mcp', 'server.js');
142
- if (!fs.existsSync(mcpServerPath)) return actions;
143
-
144
- const mcpJsonPaths = [
145
- wsRoot ? path.join(wsRoot, '.cursor', 'mcp.json') : null,
146
- wsRoot ? path.join(wsRoot, '.windsurf', 'mcp.json') : null,
147
- path.join(homePath, 'mcp.json'),
148
- ].filter(Boolean);
149
-
150
- for (const mcpJsonPath of mcpJsonPaths) {
151
- const dir = path.dirname(mcpJsonPath);
152
- if (!fs.existsSync(dir)) continue;
153
-
154
- let mcpConfig = { mcpServers: {} };
155
- if (fs.existsSync(mcpJsonPath)) {
156
- try { mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8')); } catch { continue; }
157
- }
158
-
159
- if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
160
- if (mcpConfig.mcpServers['cursor-guard']) return actions;
161
-
162
- mcpConfig.mcpServers['cursor-guard'] = {
163
- command: 'node',
164
- args: [mcpServerPath.replace(/\\/g, '/')],
165
- };
166
-
167
- fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
168
- actions.push('MCP registered');
169
- return actions;
170
- }
171
-
172
- return actions;
173
- }
174
-
175
- function autoCreateConfig(extRoot, wsRoot) {
176
- const actions = [];
177
- const configTarget = path.join(wsRoot, '.cursor-guard.json');
178
- if (fs.existsSync(configTarget)) return actions;
179
-
180
- const exampleSrc = path.join(extRoot, 'skill', 'cursor-guard.example.json');
181
- const exampleFromRefs = path.join(extRoot, '..', 'cursor-guard.example.json');
182
- const src = fs.existsSync(exampleSrc) ? exampleSrc : fs.existsSync(exampleFromRefs) ? exampleFromRefs : null;
183
-
184
- if (src) {
185
- fs.copyFileSync(src, configTarget);
186
- actions.push('.cursor-guard.json created');
187
- }
188
-
189
- return actions;
190
- }
191
-
192
- module.exports = { autoSetup, detectIdeDir };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ function detectIdeDir(vscode) {
7
+ const appName = (vscode.env.appName || '').toLowerCase();
8
+ const home = process.env.USERPROFILE || process.env.HOME || '';
9
+
10
+ const ideDirs = [];
11
+
12
+ if (appName.includes('cursor')) {
13
+ ideDirs.push('.cursor');
14
+ } else if (appName.includes('windsurf')) {
15
+ ideDirs.push('.windsurf');
16
+ } else if (appName.includes('trae')) {
17
+ ideDirs.push('.trae');
18
+ }
19
+
20
+ ideDirs.push('.cursor', '.windsurf', '.vscode');
21
+
22
+ const seen = new Set();
23
+ for (const dir of ideDirs) {
24
+ if (seen.has(dir)) continue;
25
+ seen.add(dir);
26
+ const full = path.join(home, dir);
27
+ if (fs.existsSync(full)) return { dirName: dir, homePath: full };
28
+ }
29
+
30
+ return { dirName: ideDirs[0], homePath: path.join(home, ideDirs[0]) };
31
+ }
32
+
33
+ function getExtensionRoot(context) {
34
+ return context.extensionPath;
35
+ }
36
+
37
+ function findBundledSkill(extRoot) {
38
+ const skillDir = path.join(extRoot, 'skill');
39
+ if (fs.existsSync(path.join(skillDir, 'SKILL.md'))) return skillDir;
40
+ const fromRefs = path.resolve(extRoot, '..', '..', 'SKILL.md');
41
+ if (fs.existsSync(fromRefs)) return path.resolve(extRoot, '..', '..');
42
+ return null;
43
+ }
44
+
45
+ async function autoSetup(context, vscode) {
46
+ const extRoot = getExtensionRoot(context);
47
+ const { dirName, homePath } = detectIdeDir(vscode);
48
+ const workspaceFolders = vscode.workspace.workspaceFolders;
49
+ const wsRoot = workspaceFolders?.[0]?.uri.fsPath;
50
+
51
+ const actions = [];
52
+ let skillPath = null;
53
+
54
+ try {
55
+ const skillResult = installAgentSkill(extRoot, homePath, dirName);
56
+ actions.push(...skillResult.actions);
57
+ skillPath = skillResult.skillPath;
58
+ } catch { /* non-critical */ }
59
+ try { actions.push(...autoRegisterMcp(extRoot, homePath, wsRoot)); } catch { /* non-critical */ }
60
+ if (wsRoot) {
61
+ try { actions.push(...autoCreateConfig(extRoot, wsRoot)); } catch { /* non-critical */ }
62
+ }
63
+
64
+ return { actions, skillPath };
65
+ }
66
+
67
+ /** Copy / link bundled Agent Skill into ~/.cursor/skills/cursor-guard (or IDE-specific home). */
68
+ function installAgentSkill(extRoot, homePath, dirName) {
69
+ const actions = [];
70
+ const skillSrc = findBundledSkill(extRoot);
71
+ if (!skillSrc) return { actions, skillPath: null };
72
+
73
+ const skillTarget = path.join(homePath, 'skills', 'cursor-guard');
74
+ fs.mkdirSync(skillTarget, { recursive: true });
75
+
76
+ // ── Install/update SKILL.md and ROADMAP.md ──
77
+ const skillMdSrc = path.join(skillSrc, 'SKILL.md');
78
+ const skillMdTarget = path.join(skillTarget, 'SKILL.md');
79
+ if (fs.existsSync(skillMdSrc) && !fs.existsSync(skillMdTarget)) {
80
+ fs.copyFileSync(skillMdSrc, skillMdTarget);
81
+ actions.push('SKILL.md installed');
82
+ }
83
+
84
+ const roadmapSrc = path.join(skillSrc, 'ROADMAP.md');
85
+ const roadmapDst = path.join(skillTarget, 'ROADMAP.md');
86
+ if (fs.existsSync(roadmapSrc) && !fs.existsSync(roadmapDst)) {
87
+ fs.copyFileSync(roadmapSrc, roadmapDst);
88
+ }
89
+
90
+ // ── Ensure references/ junction exists (runs even for existing installations) ──
91
+ const refsTarget = path.join(skillTarget, 'references');
92
+ const refsIsJunction = _isSymlinkOrJunction(refsTarget);
93
+ const refsIsPlainDir = !refsIsJunction && fs.existsSync(refsTarget);
94
+ const refsMissingRuntime = refsIsPlainDir && !fs.existsSync(path.join(refsTarget, 'mcp'));
95
+
96
+ if (!fs.existsSync(refsTarget) || refsMissingRuntime) {
97
+ // Remove old plain directory if it only has docs (no runtime)
98
+ if (refsMissingRuntime) {
99
+ try { fs.rmSync(refsTarget, { recursive: true, force: true }); } catch { /* ok */ }
100
+ }
101
+ try {
102
+ fs.symlinkSync(extRoot, refsTarget, 'junction');
103
+ actions.push('references/ linked');
104
+ } catch {
105
+ fs.mkdirSync(refsTarget, { recursive: true });
106
+ _copyDocFiles(skillSrc, refsTarget);
107
+ }
108
+ }
109
+
110
+ // ── Ensure package.json exists ──
111
+ const pkgDst = path.join(skillTarget, 'package.json');
112
+ if (!fs.existsSync(pkgDst)) {
113
+ const pkgSrc = path.join(extRoot, '..', '..', 'package.json');
114
+ const guardVer = path.join(extRoot, 'guard-version.json');
115
+ if (fs.existsSync(pkgSrc)) {
116
+ fs.copyFileSync(pkgSrc, pkgDst);
117
+ } else if (fs.existsSync(guardVer)) {
118
+ fs.copyFileSync(guardVer, pkgDst);
119
+ }
120
+ }
121
+
122
+ return { actions, skillPath: skillTarget };
123
+ }
124
+
125
+ function _isSymlinkOrJunction(p) {
126
+ try {
127
+ const stat = fs.lstatSync(p);
128
+ return stat.isSymbolicLink();
129
+ } catch { return false; }
130
+ }
131
+
132
+ function _copyDocFiles(skillSrc, refsTarget) {
133
+ const docs = [
134
+ 'config-reference.md', 'config-reference.zh-CN.md',
135
+ 'recovery.md', 'cursor-guard.schema.json', 'cursor-guard.example.json',
136
+ ];
137
+ for (const f of docs) {
138
+ const src = path.join(skillSrc, f);
139
+ if (fs.existsSync(src)) fs.copyFileSync(src, path.join(refsTarget, f));
140
+ }
141
+ }
142
+
143
+ function autoRegisterMcp(extRoot, homePath, wsRoot) {
144
+ const actions = [];
145
+ const mcpServerPath = path.join(extRoot, 'mcp', 'server.js');
146
+ if (!fs.existsSync(mcpServerPath)) return actions;
147
+
148
+ const mcpJsonPaths = [
149
+ wsRoot ? path.join(wsRoot, '.cursor', 'mcp.json') : null,
150
+ wsRoot ? path.join(wsRoot, '.windsurf', 'mcp.json') : null,
151
+ path.join(homePath, 'mcp.json'),
152
+ ].filter(Boolean);
153
+
154
+ for (const mcpJsonPath of mcpJsonPaths) {
155
+ const dir = path.dirname(mcpJsonPath);
156
+ if (!fs.existsSync(dir)) continue;
157
+
158
+ let mcpConfig = { mcpServers: {} };
159
+ if (fs.existsSync(mcpJsonPath)) {
160
+ try { mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8')); } catch { continue; }
161
+ }
162
+
163
+ if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
164
+ if (mcpConfig.mcpServers['cursor-guard']) return actions;
165
+
166
+ mcpConfig.mcpServers['cursor-guard'] = {
167
+ command: 'node',
168
+ args: [mcpServerPath.replace(/\\/g, '/')],
169
+ };
170
+
171
+ fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
172
+ actions.push('MCP registered');
173
+ return actions;
174
+ }
175
+
176
+ return actions;
177
+ }
178
+
179
+ function autoCreateConfig(extRoot, wsRoot) {
180
+ const actions = [];
181
+ const configTarget = path.join(wsRoot, '.cursor-guard.json');
182
+ if (fs.existsSync(configTarget)) return actions;
183
+
184
+ const exampleSrc = path.join(extRoot, 'skill', 'cursor-guard.example.json');
185
+ const exampleFromRefs = path.join(extRoot, '..', 'cursor-guard.example.json');
186
+ const src = fs.existsSync(exampleSrc) ? exampleSrc : fs.existsSync(exampleFromRefs) ? exampleFromRefs : null;
187
+
188
+ if (src) {
189
+ fs.copyFileSync(src, configTarget);
190
+ actions.push('.cursor-guard.json created');
191
+ }
192
+
193
+ return actions;
194
+ }
195
+
196
+ module.exports = {
197
+ autoSetup,
198
+ detectIdeDir,
199
+ installAgentSkill,
200
+ getExtensionRoot,
201
+ };