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.
- package/README.md +697 -697
- package/README.zh-CN.md +696 -696
- package/ROADMAP.md +1775 -1720
- package/SKILL.md +631 -629
- package/docs/RELEASE.md +197 -196
- package/docs/SNAPSHOT-BOOKMARK.md +47 -0
- package/package.json +70 -69
- package/references/dashboard/public/app.js +2079 -1832
- package/references/dashboard/public/style.css +1660 -1573
- package/references/dashboard/server.js +197 -4
- package/references/lib/core/backups.js +509 -492
- package/references/lib/core/core.test.js +1761 -1616
- package/references/lib/core/snapshot.js +441 -369
- package/references/mcp/mcp.test.js +381 -362
- package/references/mcp/server.js +404 -347
- package/references/vscode-extension/dist/{cursor-guard-ide-4.9.9.vsix → cursor-guard-ide-4.9.15.vsix} +0 -0
- package/references/vscode-extension/dist/dashboard/public/app.js +2079 -1832
- package/references/vscode-extension/dist/dashboard/public/style.css +1660 -1573
- package/references/vscode-extension/dist/dashboard/server.js +197 -4
- package/references/vscode-extension/dist/extension.js +780 -704
- package/references/vscode-extension/dist/guard-version.json +1 -1
- package/references/vscode-extension/dist/lib/auto-setup.js +201 -192
- package/references/vscode-extension/dist/lib/core/backups.js +509 -492
- package/references/vscode-extension/dist/lib/core/snapshot.js +441 -369
- package/references/vscode-extension/dist/lib/poller.js +161 -21
- package/references/vscode-extension/dist/lib/sidebar-webview.js +22 -0
- package/references/vscode-extension/dist/mcp/server.js +152 -35
- package/references/vscode-extension/dist/package.json +7 -1
- package/references/vscode-extension/dist/skill/ROADMAP.md +1775 -1720
- package/references/vscode-extension/dist/skill/SKILL.md +631 -629
- package/references/vscode-extension/extension.js +780 -704
- package/references/vscode-extension/lib/auto-setup.js +201 -192
- package/references/vscode-extension/lib/poller.js +161 -21
- package/references/vscode-extension/lib/sidebar-webview.js +22 -0
- package/references/vscode-extension/package.json +146 -140
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"4.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
|
-
|
|
54
|
-
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
+
};
|