cursor-guard 4.9.6 → 4.9.8
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 +114 -60
- package/README.zh-CN.md +111 -57
- package/ROADMAP.md +41 -20
- package/SKILL.md +1 -1
- package/package.json +3 -2
- package/references/vscode-extension/build-vsix.js +7 -5
- package/references/vscode-extension/dist/{cursor-guard-ide-4.9.6.vsix → cursor-guard-ide-4.9.8.vsix} +0 -0
- package/references/vscode-extension/dist/extension.js +697 -498
- package/references/vscode-extension/dist/guard-version.json +1 -1
- package/references/vscode-extension/dist/lib/dashboard-manager.js +102 -52
- package/references/vscode-extension/dist/lib/locale.js +36 -0
- package/references/vscode-extension/dist/lib/sidebar-webview.js +1193 -502
- package/references/vscode-extension/dist/mcp/server.js +3 -2
- package/references/vscode-extension/dist/media/brand-placeholder.png +0 -0
- package/references/vscode-extension/dist/package.json +1 -1
- package/references/vscode-extension/dist/skill/ROADMAP.md +41 -20
- package/references/vscode-extension/dist/skill/SKILL.md +1 -1
- package/references/vscode-extension/extension.js +697 -498
- package/references/vscode-extension/lib/dashboard-manager.js +102 -52
- package/references/vscode-extension/lib/locale.js +36 -0
- package/references/vscode-extension/lib/sidebar-webview.js +1193 -502
- package/references/vscode-extension/media/brand-placeholder.png +0 -0
- package/references/vscode-extension/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"4.9.
|
|
1
|
+
{"version":"4.9.8"}
|
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const http = require('http');
|
|
6
|
-
const { spawn } = require('child_process');
|
|
7
|
-
const { guardPath } = require('./paths');
|
|
8
|
-
|
|
9
|
-
const CONFIG_FILE = '.cursor-guard.json';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
this.
|
|
15
|
-
|
|
6
|
+
const { spawn } = require('child_process');
|
|
7
|
+
const { guardPath } = require('./paths');
|
|
8
|
+
|
|
9
|
+
const CONFIG_FILE = '.cursor-guard.json';
|
|
10
|
+
const WATCHER_START_GRACE_MS = 8000;
|
|
11
|
+
|
|
12
|
+
class DashboardManager {
|
|
13
|
+
constructor() {
|
|
14
|
+
this._instance = null;
|
|
15
|
+
this._serverModule = null;
|
|
16
|
+
this._startingWatchers = new Map();
|
|
17
|
+
}
|
|
16
18
|
|
|
17
19
|
get running() { return !!this._instance; }
|
|
18
20
|
get port() { return this._instance?.port; }
|
|
@@ -83,7 +85,7 @@ class DashboardManager {
|
|
|
83
85
|
return this.fetchApi(`/api/backup-files?id=${projectId}&hash=${hash}`);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
async snapshotNow(projectPath) {
|
|
88
|
+
async snapshotNow(projectPath) {
|
|
87
89
|
if (!projectPath) return;
|
|
88
90
|
try {
|
|
89
91
|
const { createGitSnapshot } = require(guardPath('lib', 'core', 'snapshot'));
|
|
@@ -93,50 +95,98 @@ class DashboardManager {
|
|
|
93
95
|
} catch (e) {
|
|
94
96
|
return { status: 'error', error: e.message };
|
|
95
97
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_getWatcherLockPath(projectPath) {
|
|
101
|
+
try {
|
|
102
|
+
const { gitAvailable, isGitRepo, gitDir: getGitDir } = require(guardPath('lib', 'utils'));
|
|
103
|
+
const repo = gitAvailable() && isGitRepo(projectPath);
|
|
104
|
+
if (repo) {
|
|
105
|
+
const gDir = getGitDir(projectPath);
|
|
106
|
+
if (gDir) return path.join(gDir, 'cursor-guard.lock');
|
|
107
|
+
}
|
|
108
|
+
} catch { /* ignore */ }
|
|
109
|
+
return path.join(projectPath, '.cursor-guard-backup', 'cursor-guard.lock');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_getPendingWatcherPid(projectPath) {
|
|
113
|
+
const pending = this._startingWatchers.get(projectPath);
|
|
114
|
+
if (!pending) return null;
|
|
115
|
+
try {
|
|
116
|
+
process.kill(pending.pid, 0);
|
|
117
|
+
return pending.pid;
|
|
118
|
+
} catch {
|
|
119
|
+
this._startingWatchers.delete(projectPath);
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
_clearPendingWatcher(projectPath, pid) {
|
|
125
|
+
const pending = this._startingWatchers.get(projectPath);
|
|
126
|
+
if (!pending) return;
|
|
127
|
+
if (pid == null || pending.pid === pid) {
|
|
128
|
+
this._startingWatchers.delete(projectPath);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
startWatcher(projectPath) {
|
|
133
|
+
if (!projectPath) return null;
|
|
134
|
+
const existingPid = this.getWatcherPid(projectPath);
|
|
135
|
+
if (existingPid) return existingPid;
|
|
136
|
+
const cliScript = guardPath('bin', 'cursor-guard-backup.js');
|
|
103
137
|
const child = spawn(process.execPath, [cliScript, '--path', projectPath], {
|
|
104
138
|
cwd: projectPath,
|
|
105
139
|
stdio: 'ignore',
|
|
106
|
-
detached: true,
|
|
107
|
-
env: { ...process.env, GUARD_SPAWNED_BY_EXT: '1' },
|
|
108
|
-
});
|
|
109
|
-
child.
|
|
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
|
+
detached: true,
|
|
141
|
+
env: { ...process.env, GUARD_SPAWNED_BY_EXT: '1' },
|
|
142
|
+
});
|
|
143
|
+
this._startingWatchers.set(projectPath, { pid: child.pid, startedAt: Date.now() });
|
|
144
|
+
const clearPending = () => this._clearPendingWatcher(projectPath, child.pid);
|
|
145
|
+
child.once('exit', clearPending);
|
|
146
|
+
child.once('error', clearPending);
|
|
147
|
+
setTimeout(clearPending, WATCHER_START_GRACE_MS);
|
|
148
|
+
child.unref();
|
|
149
|
+
return child.pid;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
stopWatcher(projectPath) {
|
|
153
|
+
if (!projectPath) return false;
|
|
154
|
+
const pendingPid = this._getPendingWatcherPid(projectPath);
|
|
155
|
+
if (pendingPid) {
|
|
156
|
+
try { process.kill(pendingPid, 'SIGTERM'); } catch { /* ignore */ }
|
|
157
|
+
this._clearPendingWatcher(projectPath, pendingPid);
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const lockPath = this._getWatcherLockPath(projectPath);
|
|
161
|
+
if (!fs.existsSync(lockPath)) return false;
|
|
162
|
+
const content = fs.readFileSync(lockPath, 'utf-8');
|
|
163
|
+
const pidMatch = content.match(/pid=(\d+)/);
|
|
164
|
+
if (pidMatch) {
|
|
165
|
+
process.kill(parseInt(pidMatch[1], 10), 'SIGTERM');
|
|
166
|
+
}
|
|
167
|
+
try { fs.unlinkSync(lockPath); } catch { /* ok */ }
|
|
168
|
+
return true;
|
|
169
|
+
} catch { /* ok */ }
|
|
170
|
+
return !!pendingPid;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getWatcherPid(projectPath) {
|
|
174
|
+
const pendingPid = this._getPendingWatcherPid(projectPath);
|
|
175
|
+
if (pendingPid) return pendingPid;
|
|
176
|
+
try {
|
|
177
|
+
const lockPath = this._getWatcherLockPath(projectPath);
|
|
178
|
+
if (!fs.existsSync(lockPath)) return null;
|
|
179
|
+
const content = fs.readFileSync(lockPath, 'utf-8');
|
|
180
|
+
const pidMatch = content.match(/pid=(\d+)/);
|
|
181
|
+
if (pidMatch) {
|
|
182
|
+
const pid = parseInt(pidMatch[1], 10);
|
|
183
|
+
process.kill(pid, 0);
|
|
184
|
+
this._clearPendingWatcher(projectPath, pid);
|
|
185
|
+
return pid;
|
|
186
|
+
}
|
|
187
|
+
} catch { /* not running */ }
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
140
190
|
|
|
141
191
|
dispose() {
|
|
142
192
|
this._instance = null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const vscode = require('vscode');
|
|
4
|
+
|
|
5
|
+
const EXTENSION_LOCALE_KEY = 'cursorGuard.locale';
|
|
6
|
+
|
|
7
|
+
function normalizeLocale(locale) {
|
|
8
|
+
return locale === 'zh-CN' ? 'zh-CN' : 'en-US';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function detectLocale() {
|
|
12
|
+
return normalizeLocale(
|
|
13
|
+
(vscode.env.language || '').toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US'
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getLocale(storage) {
|
|
18
|
+
if (!storage || typeof storage.get !== 'function') return detectLocale();
|
|
19
|
+
return normalizeLocale(storage.get(EXTENSION_LOCALE_KEY) || detectLocale());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function setLocale(storage, locale) {
|
|
23
|
+
const normalized = normalizeLocale(locale);
|
|
24
|
+
if (storage && typeof storage.update === 'function') {
|
|
25
|
+
await storage.update(EXTENSION_LOCALE_KEY, normalized);
|
|
26
|
+
}
|
|
27
|
+
return normalized;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
EXTENSION_LOCALE_KEY,
|
|
32
|
+
normalizeLocale,
|
|
33
|
+
detectLocale,
|
|
34
|
+
getLocale,
|
|
35
|
+
setLocale,
|
|
36
|
+
};
|