jjb-cmd 2.5.8 → 2.6.0
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/package.json +1 -1
- package/src/ai-pull.js +1 -715
- package/src/auth.js +1 -71
- package/src/code-optimization.js +1 -46
- package/src/config.js +1 -122
- package/src/crypto-utils.js +1 -183
- package/src/password-input.js +1 -79
- package/src/publish.js +1 -307
- package/src/push.js +1 -417
- package/src/rm-rf.js +1 -49
- package/src/utils.js +1 -228
- package/SECURITY.md +0 -71
- package/build.js +0 -20
- package/obf.config.json +0 -3
package/src/ai-pull.js
CHANGED
|
@@ -1,715 +1 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const child_process = require('child_process');
|
|
5
|
-
|
|
6
|
-
// Cursor user rules SQLite 数据库路径
|
|
7
|
-
// Windows: C:\Users\<username>\AppData\Roaming\Cursor\User\globalStorage\state.vscdb
|
|
8
|
-
const CURSOR_DB_PATH = path.join(
|
|
9
|
-
os.homedir(),
|
|
10
|
-
'AppData',
|
|
11
|
-
'Roaming',
|
|
12
|
-
'Cursor',
|
|
13
|
-
'User',
|
|
14
|
-
'globalStorage',
|
|
15
|
-
'state.vscdb'
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
// Git 仓库地址
|
|
19
|
-
const AI_REPO_URL = 'http://192.168.1.242:10985/root/jjb-ai.git';
|
|
20
|
-
// Git 分支/标签(默认值)
|
|
21
|
-
const DEFAULT_BRANCH = 'v_2.0.0';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 删除目录(回调方式,使用递归删除)
|
|
25
|
-
*/
|
|
26
|
-
function deleteDir(dirPath, callback) {
|
|
27
|
-
if (!fs.existsSync(dirPath)) {
|
|
28
|
-
callback && callback();
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// 递归删除目录和文件
|
|
33
|
-
function deleteRecursive(dir) {
|
|
34
|
-
if (!fs.existsSync(dir)) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
const files = fs.readdirSync(dir);
|
|
40
|
-
for (let i = 0; i < files.length; i++) {
|
|
41
|
-
const file = files[i];
|
|
42
|
-
const curPath = path.join(dir, file);
|
|
43
|
-
const stat = fs.statSync(curPath);
|
|
44
|
-
|
|
45
|
-
if (stat.isDirectory()) {
|
|
46
|
-
deleteRecursive(curPath);
|
|
47
|
-
// 删除空目录
|
|
48
|
-
try {
|
|
49
|
-
fs.rmdirSync(curPath);
|
|
50
|
-
} catch (e) {
|
|
51
|
-
// 忽略错误,可能目录不为空
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
try {
|
|
55
|
-
fs.unlinkSync(curPath);
|
|
56
|
-
} catch (e) {
|
|
57
|
-
// 忽略删除文件错误
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 最后删除根目录
|
|
63
|
-
try {
|
|
64
|
-
fs.rmdirSync(dir);
|
|
65
|
-
} catch (e) {
|
|
66
|
-
// 忽略错误,可能目录不为空或正在使用
|
|
67
|
-
}
|
|
68
|
-
} catch (e) {
|
|
69
|
-
// 忽略错误
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
deleteRecursive(dirPath);
|
|
74
|
-
|
|
75
|
-
// 延迟回调,确保删除完成
|
|
76
|
-
setTimeout(() => {
|
|
77
|
-
callback && callback();
|
|
78
|
-
}, 300);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 复制文件夹(回调方式,改进错误处理)
|
|
83
|
-
*/
|
|
84
|
-
function copyFolder(srcDir, tarDir, callback) {
|
|
85
|
-
if (!fs.existsSync(srcDir)) {
|
|
86
|
-
callback && callback(new Error(`源目录不存在: ${srcDir}`));
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 确保目标目录存在
|
|
91
|
-
if (!fs.existsSync(tarDir)) {
|
|
92
|
-
try {
|
|
93
|
-
fs.mkdirSync(tarDir, { recursive: true });
|
|
94
|
-
} catch (e) {
|
|
95
|
-
callback && callback(e);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// 使用改进的复制函数
|
|
101
|
-
copyFolderRecursive(srcDir, tarDir, callback);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* 递归复制文件夹(带错误处理)
|
|
106
|
-
*/
|
|
107
|
-
function copyFolderRecursive(srcDir, tarDir, callback) {
|
|
108
|
-
if (!fs.existsSync(srcDir)) {
|
|
109
|
-
callback && callback(new Error(`源目录不存在: ${srcDir}`));
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const files = fs.readdirSync(srcDir);
|
|
115
|
-
let completed = 0;
|
|
116
|
-
let hasError = false;
|
|
117
|
-
|
|
118
|
-
if (files.length === 0) {
|
|
119
|
-
callback && callback();
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
files.forEach((file) => {
|
|
124
|
-
const srcPath = path.join(srcDir, file);
|
|
125
|
-
const tarPath = path.join(tarDir, file);
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
const stat = fs.statSync(srcPath);
|
|
129
|
-
|
|
130
|
-
if (stat.isDirectory()) {
|
|
131
|
-
// 确保目标目录存在
|
|
132
|
-
if (!fs.existsSync(tarPath)) {
|
|
133
|
-
fs.mkdirSync(tarPath, { recursive: true });
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
copyFolderRecursive(srcPath, tarPath, (err) => {
|
|
137
|
-
completed++;
|
|
138
|
-
if (err && !hasError) {
|
|
139
|
-
hasError = true;
|
|
140
|
-
console.log(`【Warning】:复制目录失败 ${srcPath}: ${err.message}`);
|
|
141
|
-
}
|
|
142
|
-
if (completed === files.length) {
|
|
143
|
-
callback && callback(hasError ? new Error('部分文件复制失败') : null);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
} else {
|
|
147
|
-
// 复制文件,带重试机制
|
|
148
|
-
copyFileWithRetry(srcPath, tarPath, 3, (err) => {
|
|
149
|
-
completed++;
|
|
150
|
-
if (err && !hasError) {
|
|
151
|
-
hasError = true;
|
|
152
|
-
console.log(`【Warning】:复制文件失败 ${srcPath}: ${err.message}`);
|
|
153
|
-
}
|
|
154
|
-
if (completed === files.length) {
|
|
155
|
-
callback && callback(hasError ? new Error('部分文件复制失败') : null);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
} catch (e) {
|
|
160
|
-
completed++;
|
|
161
|
-
if (!hasError) {
|
|
162
|
-
hasError = true;
|
|
163
|
-
console.log(`【Warning】:处理文件失败 ${srcPath}: ${e.message}`);
|
|
164
|
-
}
|
|
165
|
-
if (completed === files.length) {
|
|
166
|
-
callback && callback(hasError ? new Error('部分文件复制失败') : null);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
} catch (e) {
|
|
171
|
-
callback && callback(e);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 复制文件(带重试机制)
|
|
177
|
-
*/
|
|
178
|
-
function copyFileWithRetry(srcPath, tarPath, retries, callback) {
|
|
179
|
-
if (retries <= 0) {
|
|
180
|
-
callback && callback(new Error(`复制文件失败,已重试多次: ${srcPath}`));
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// 确保目标目录存在
|
|
185
|
-
const tarDir = path.dirname(tarPath);
|
|
186
|
-
if (!fs.existsSync(tarDir)) {
|
|
187
|
-
try {
|
|
188
|
-
fs.mkdirSync(tarDir, { recursive: true });
|
|
189
|
-
} catch (e) {
|
|
190
|
-
callback && callback(e);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const rs = fs.createReadStream(srcPath);
|
|
196
|
-
const ws = fs.createWriteStream(tarPath);
|
|
197
|
-
|
|
198
|
-
rs.on('error', (err) => {
|
|
199
|
-
callback && callback(err);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
ws.on('error', (err) => {
|
|
203
|
-
// 如果是文件被占用或其他临时错误,尝试重试
|
|
204
|
-
if (retries > 1 && (err.code === 'EBUSY' || err.code === 'EPERM' || err.code === 'EACCES')) {
|
|
205
|
-
setTimeout(() => {
|
|
206
|
-
copyFileWithRetry(srcPath, tarPath, retries - 1, callback);
|
|
207
|
-
}, 100);
|
|
208
|
-
} else {
|
|
209
|
-
callback && callback(err);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
ws.on('close', () => {
|
|
214
|
-
callback && callback();
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
rs.pipe(ws);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
module.exports = (branch) => {
|
|
221
|
-
const root_path = path.resolve('./');
|
|
222
|
-
const tmpDir = os.tmpdir();
|
|
223
|
-
const cloneDir = path.join(tmpDir, 'jjb-ai-temp');
|
|
224
|
-
|
|
225
|
-
// 使用传入的分支参数,如果没有则使用默认值
|
|
226
|
-
const targetBranch = branch || DEFAULT_BRANCH;
|
|
227
|
-
|
|
228
|
-
console.log('【jjb-cmd ai-pull】:开始执行...');
|
|
229
|
-
console.log(`【分支】:${targetBranch}`);
|
|
230
|
-
|
|
231
|
-
// 步骤1: 拉取或更新仓库代码
|
|
232
|
-
console.log(`步骤1: 正在拉取 jjb-ai 仓库代码(分支: ${targetBranch})...`);
|
|
233
|
-
|
|
234
|
-
// 如果临时目录已存在,先删除
|
|
235
|
-
deleteDir(cloneDir, () => {
|
|
236
|
-
try {
|
|
237
|
-
// 克隆仓库指定分支/标签
|
|
238
|
-
child_process.execSync(`git clone -b ${targetBranch} ${AI_REPO_URL} "${cloneDir}"`, {
|
|
239
|
-
stdio: 'inherit',
|
|
240
|
-
cwd: tmpDir
|
|
241
|
-
});
|
|
242
|
-
console.log(`✓ 仓库代码拉取成功(分支: ${targetBranch})`);
|
|
243
|
-
|
|
244
|
-
// 步骤2: 将仓库 admin 下的 Cursor 配置同步到当前项目 .cursor/
|
|
245
|
-
// 优先使用 admin/.cursor 下的一级子目录(避免复制成 .cursor/.cursor);否则回退为 admin 下的一级子目录
|
|
246
|
-
console.log('步骤2: 正在复制 admin 内 Cursor 资源到 .cursor/...');
|
|
247
|
-
const adminRootPath = path.join(cloneDir, 'admin');
|
|
248
|
-
const adminCursorPath = path.join(adminRootPath, '.cursor');
|
|
249
|
-
const syncSourcePath = fs.existsSync(adminCursorPath) ? adminCursorPath : adminRootPath;
|
|
250
|
-
const syncSourceLabel = fs.existsSync(adminCursorPath) ? 'admin/.cursor' : 'admin';
|
|
251
|
-
const cursorDir = path.join(root_path, '.cursor');
|
|
252
|
-
|
|
253
|
-
if (!fs.existsSync(adminRootPath)) {
|
|
254
|
-
console.log('【Warning】:仓库中未找到 admin 文件夹');
|
|
255
|
-
step3();
|
|
256
|
-
} else {
|
|
257
|
-
let subdirs;
|
|
258
|
-
try {
|
|
259
|
-
subdirs = fs.readdirSync(syncSourcePath).filter((name) => {
|
|
260
|
-
const p = path.join(syncSourcePath, name);
|
|
261
|
-
try {
|
|
262
|
-
return fs.statSync(p).isDirectory();
|
|
263
|
-
} catch (e) {
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
} catch (e) {
|
|
268
|
-
console.error(`【Error】:读取 ${syncSourceLabel} 目录失败`, e.message);
|
|
269
|
-
cleanupAndExit(1);
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (subdirs.length === 0) {
|
|
274
|
-
console.log(`【Warning】:${syncSourceLabel} 下没有子文件夹可同步`);
|
|
275
|
-
step3();
|
|
276
|
-
} else {
|
|
277
|
-
try {
|
|
278
|
-
if (!fs.existsSync(cursorDir)) {
|
|
279
|
-
fs.mkdirSync(cursorDir, { recursive: true });
|
|
280
|
-
}
|
|
281
|
-
} catch (e) {
|
|
282
|
-
console.error('【Error】:创建 .cursor 目录失败', e.message);
|
|
283
|
-
cleanupAndExit(1);
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function copyAdminDirAt(i) {
|
|
288
|
-
if (i >= subdirs.length) {
|
|
289
|
-
console.log(`✓ 已将 ${syncSourceLabel} 下 ${subdirs.length} 个文件夹复制到 .cursor/(${subdirs.join(', ')})`);
|
|
290
|
-
step3();
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const name = subdirs[i];
|
|
294
|
-
const srcPath = path.join(syncSourcePath, name);
|
|
295
|
-
const destPath = path.join(cursorDir, name);
|
|
296
|
-
const afterCopy = (err) => {
|
|
297
|
-
if (err) {
|
|
298
|
-
console.error(`【Error】:复制 ${syncSourceLabel}/${name} 失败`, err.message);
|
|
299
|
-
cleanupAndExit(1);
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
copyAdminDirAt(i + 1);
|
|
303
|
-
};
|
|
304
|
-
if (fs.existsSync(destPath)) {
|
|
305
|
-
deleteDir(destPath, () => {
|
|
306
|
-
copyFolder(srcPath, destPath, afterCopy);
|
|
307
|
-
});
|
|
308
|
-
} else {
|
|
309
|
-
copyFolder(srcPath, destPath, afterCopy);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
copyAdminDirAt(0);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
} catch (error) {
|
|
317
|
-
console.error('【Error】:拉取仓库失败', error.message);
|
|
318
|
-
cleanupAndExit(1);
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// 步骤3: 将 admin/rules/PROJECT.md 写入 Cursor user rules (SQLite 数据库)
|
|
323
|
-
function step3() {
|
|
324
|
-
console.log('步骤3: 正在更新 Cursor user rules (SQLite 数据库)...');
|
|
325
|
-
const projectRulesPath = path.join(cloneDir, 'admin', 'rules', 'PROJECT.md');
|
|
326
|
-
|
|
327
|
-
try {
|
|
328
|
-
if (!fs.existsSync(projectRulesPath)) {
|
|
329
|
-
console.log('【Warning】:仓库中未找到 admin/rules/PROJECT.md 文件');
|
|
330
|
-
step4();
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// 读取 PROJECT.md 内容
|
|
335
|
-
const rulesContent = fs.readFileSync(projectRulesPath, 'utf8');
|
|
336
|
-
|
|
337
|
-
// 检查数据库文件是否存在
|
|
338
|
-
if (!fs.existsSync(CURSOR_DB_PATH)) {
|
|
339
|
-
console.log('【Warning】:Cursor 数据库文件不存在,可能 Cursor 未安装或路径不正确');
|
|
340
|
-
console.log(`【路径】:${CURSOR_DB_PATH}`);
|
|
341
|
-
console.log('【建议】:请确保已安装 Cursor 编辑器,或手动复制 admin/rules/PROJECT.md 内容');
|
|
342
|
-
step4();
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// 备份数据库文件
|
|
347
|
-
try {
|
|
348
|
-
const dbDir = path.dirname(CURSOR_DB_PATH);
|
|
349
|
-
const dbFileName = path.basename(CURSOR_DB_PATH);
|
|
350
|
-
|
|
351
|
-
// 查找所有备份文件
|
|
352
|
-
const files = fs.existsSync(dbDir) ? fs.readdirSync(dbDir) : [];
|
|
353
|
-
const backupFiles = files.filter(file =>
|
|
354
|
-
file.startsWith(dbFileName + '.backup.')
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
// 删除所有旧的备份文件
|
|
358
|
-
backupFiles.forEach(backupFile => {
|
|
359
|
-
try {
|
|
360
|
-
const backupFilePath = path.join(dbDir, backupFile);
|
|
361
|
-
fs.unlinkSync(backupFilePath);
|
|
362
|
-
console.log(`✓ 已删除旧备份文件: ${backupFile}`);
|
|
363
|
-
} catch (e) {
|
|
364
|
-
// 忽略删除错误
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
// 创建新的备份文件
|
|
369
|
-
const backupPath = CURSOR_DB_PATH + '.backup.' + Date.now();
|
|
370
|
-
fs.copyFileSync(CURSOR_DB_PATH, backupPath);
|
|
371
|
-
console.log(`✓ 已备份数据库文件到 ${path.basename(backupPath)}`);
|
|
372
|
-
} catch (e) {
|
|
373
|
-
console.log('【Warning】:备份数据库文件失败', e.message);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// 使用 better-sqlite3 或 sqlite3 更新数据库
|
|
377
|
-
try {
|
|
378
|
-
// 尝试使用 better-sqlite3 (同步 API,更简单)
|
|
379
|
-
let Database;
|
|
380
|
-
try {
|
|
381
|
-
Database = require('better-sqlite3');
|
|
382
|
-
} catch (e) {
|
|
383
|
-
// 如果 better-sqlite3 不存在,尝试使用 sqlite3
|
|
384
|
-
try {
|
|
385
|
-
const sqlite3 = require('sqlite3');
|
|
386
|
-
// sqlite3 是异步的,需要使用回调或 Promise
|
|
387
|
-
console.log(`【调试】:准备更新数据库,内容长度: ${rulesContent.length} 字符`);
|
|
388
|
-
|
|
389
|
-
const db = new sqlite3.Database(CURSOR_DB_PATH, (err) => {
|
|
390
|
-
if (err) {
|
|
391
|
-
console.error('【Error】:无法打开数据库', err.message);
|
|
392
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
393
|
-
step4();
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// 先查询是否存在该键
|
|
398
|
-
db.get("SELECT value, length(value) as len FROM ItemTable WHERE key = ?", ['aicontext.personalContext'], (err, row) => {
|
|
399
|
-
if (err) {
|
|
400
|
-
console.error('【Error】:查询数据库失败', err.message);
|
|
401
|
-
db.close();
|
|
402
|
-
step4();
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// 更新或插入数据
|
|
407
|
-
if (row) {
|
|
408
|
-
console.log(`【调试】:找到现有记录,当前长度: ${row.len} 字节`);
|
|
409
|
-
|
|
410
|
-
// 检查内容是否已经相同
|
|
411
|
-
let oldContent = '';
|
|
412
|
-
if (Buffer.isBuffer(row.value)) {
|
|
413
|
-
oldContent = row.value.toString('utf8');
|
|
414
|
-
} else {
|
|
415
|
-
oldContent = String(row.value);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (oldContent === rulesContent) {
|
|
419
|
-
console.log('✓ admin/rules/PROJECT.md 内容未变化,无需更新');
|
|
420
|
-
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
421
|
-
db.close();
|
|
422
|
-
step4();
|
|
423
|
-
return;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// 更新现有记录
|
|
427
|
-
db.run("UPDATE ItemTable SET value = ? WHERE key = ?", [rulesContent, 'aicontext.personalContext'], function(err) {
|
|
428
|
-
if (err) {
|
|
429
|
-
console.error('【Error】:更新数据库失败', err.message);
|
|
430
|
-
if (err.code === 'SQLITE_BUSY' || err.message.includes('locked')) {
|
|
431
|
-
console.error('【Error】:数据库被锁定,可能是 Cursor 正在使用');
|
|
432
|
-
}
|
|
433
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
434
|
-
db.close();
|
|
435
|
-
step4();
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
console.log(`【调试】:更新影响行数: ${this.changes}`);
|
|
440
|
-
|
|
441
|
-
if (this.changes === 0) {
|
|
442
|
-
console.error('【Error】:更新失败,影响行数为 0,可能数据库被锁定');
|
|
443
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
444
|
-
db.close();
|
|
445
|
-
step4();
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// 验证更新是否成功
|
|
450
|
-
db.get("SELECT value, length(value) as len FROM ItemTable WHERE key = ?", ['aicontext.personalContext'], (err, verifyRow) => {
|
|
451
|
-
if (err) {
|
|
452
|
-
console.error('【Error】:验证更新失败', err.message);
|
|
453
|
-
} else if (verifyRow && verifyRow.value) {
|
|
454
|
-
let verifyContent = '';
|
|
455
|
-
if (Buffer.isBuffer(verifyRow.value)) {
|
|
456
|
-
verifyContent = verifyRow.value.toString('utf8');
|
|
457
|
-
} else {
|
|
458
|
-
verifyContent = String(verifyRow.value);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (verifyContent === rulesContent) {
|
|
462
|
-
console.log(`✓ PROJECT.md 已更新到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
463
|
-
// 显示前几行内容确认
|
|
464
|
-
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
465
|
-
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
466
|
-
} else {
|
|
467
|
-
console.error(`【Error】:更新后内容不匹配!`);
|
|
468
|
-
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
469
|
-
console.error(` 期望前100字符: ${rulesContent.substring(0, 100)}`);
|
|
470
|
-
console.error(` 实际前100字符: ${verifyContent.substring(0, 100)}`);
|
|
471
|
-
}
|
|
472
|
-
} else {
|
|
473
|
-
console.error('【Error】:更新后验证失败,值为空');
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
477
|
-
db.close();
|
|
478
|
-
step4();
|
|
479
|
-
});
|
|
480
|
-
});
|
|
481
|
-
} else {
|
|
482
|
-
console.log('【调试】:记录不存在,将插入新记录');
|
|
483
|
-
// 插入新记录
|
|
484
|
-
db.run("INSERT INTO ItemTable (key, value) VALUES (?, ?)", ['aicontext.personalContext', rulesContent], function(err) {
|
|
485
|
-
if (err) {
|
|
486
|
-
console.error('【Error】:插入数据库失败', err.message);
|
|
487
|
-
if (err.code === 'SQLITE_BUSY' || err.message.includes('locked')) {
|
|
488
|
-
console.error('【Error】:数据库被锁定,可能是 Cursor 正在使用');
|
|
489
|
-
}
|
|
490
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
491
|
-
db.close();
|
|
492
|
-
step4();
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
console.log(`【调试】:插入结果,最后插入ID: ${this.lastInsertRowid}`);
|
|
497
|
-
|
|
498
|
-
if (!this.lastInsertRowid) {
|
|
499
|
-
console.error('【Error】:插入失败,未返回插入ID');
|
|
500
|
-
db.close();
|
|
501
|
-
step4();
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// 验证插入是否成功
|
|
506
|
-
db.get("SELECT value, length(value) as len FROM ItemTable WHERE key = ?", ['aicontext.personalContext'], (err, verifyRow) => {
|
|
507
|
-
if (err) {
|
|
508
|
-
console.error('【Error】:验证插入失败', err.message);
|
|
509
|
-
} else if (verifyRow && verifyRow.value) {
|
|
510
|
-
let verifyContent = '';
|
|
511
|
-
if (Buffer.isBuffer(verifyRow.value)) {
|
|
512
|
-
verifyContent = verifyRow.value.toString('utf8');
|
|
513
|
-
} else {
|
|
514
|
-
verifyContent = String(verifyRow.value);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
if (verifyContent === rulesContent) {
|
|
518
|
-
console.log(`✓ PROJECT.md 已添加到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
519
|
-
// 显示前几行内容确认
|
|
520
|
-
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
521
|
-
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
522
|
-
} else {
|
|
523
|
-
console.error(`【Error】:插入后内容不匹配!`);
|
|
524
|
-
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
525
|
-
}
|
|
526
|
-
} else {
|
|
527
|
-
console.error('【Error】:插入后验证失败,值为空');
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
531
|
-
db.close();
|
|
532
|
-
step4();
|
|
533
|
-
});
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
});
|
|
537
|
-
});
|
|
538
|
-
return; // 异步操作,提前返回
|
|
539
|
-
} catch (e2) {
|
|
540
|
-
console.error('【Error】:未找到 SQLite 模块 (better-sqlite3 或 sqlite3)');
|
|
541
|
-
console.log('【建议】:请运行 npm install better-sqlite3 或 npm install sqlite3');
|
|
542
|
-
console.log('【或者】:使用命令行工具手动更新数据库');
|
|
543
|
-
step4();
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// 使用 better-sqlite3 (同步 API)
|
|
549
|
-
const db = new Database(CURSOR_DB_PATH, { readonly: false });
|
|
550
|
-
|
|
551
|
-
try {
|
|
552
|
-
console.log(`【调试】:准备更新数据库,内容长度: ${rulesContent.length} 字符`);
|
|
553
|
-
|
|
554
|
-
// 先查询是否存在该键
|
|
555
|
-
const row = db.prepare("SELECT value, length(value) as len FROM ItemTable WHERE key = ?").get('aicontext.personalContext');
|
|
556
|
-
|
|
557
|
-
if (row) {
|
|
558
|
-
console.log(`【调试】:找到现有记录,当前长度: ${row.len} 字节`);
|
|
559
|
-
|
|
560
|
-
// 检查内容是否已经相同
|
|
561
|
-
let oldContent = '';
|
|
562
|
-
if (Buffer.isBuffer(row.value)) {
|
|
563
|
-
oldContent = row.value.toString('utf8');
|
|
564
|
-
} else {
|
|
565
|
-
oldContent = String(row.value);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (oldContent === rulesContent) {
|
|
569
|
-
console.log('✓ admin/rules/PROJECT.md 内容未变化,无需更新');
|
|
570
|
-
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
571
|
-
db.close();
|
|
572
|
-
step4();
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// 更新现有记录
|
|
577
|
-
const updateStmt = db.prepare("UPDATE ItemTable SET value = ? WHERE key = ?");
|
|
578
|
-
const result = updateStmt.run(rulesContent, 'aicontext.personalContext');
|
|
579
|
-
console.log(`【调试】:更新影响行数: ${result.changes}`);
|
|
580
|
-
|
|
581
|
-
if (result.changes === 0) {
|
|
582
|
-
console.error('【Error】:更新失败,影响行数为 0,可能数据库被锁定');
|
|
583
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
584
|
-
db.close();
|
|
585
|
-
step4();
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// 验证更新是否成功
|
|
590
|
-
const verifyRow = db.prepare("SELECT value, length(value) as len FROM ItemTable WHERE key = ?").get('aicontext.personalContext');
|
|
591
|
-
if (verifyRow && verifyRow.value) {
|
|
592
|
-
let verifyContent = '';
|
|
593
|
-
if (Buffer.isBuffer(verifyRow.value)) {
|
|
594
|
-
verifyContent = verifyRow.value.toString('utf8');
|
|
595
|
-
} else {
|
|
596
|
-
verifyContent = String(verifyRow.value);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (verifyContent === rulesContent) {
|
|
600
|
-
console.log(`✓ PROJECT.md 已更新到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
601
|
-
// 显示前几行内容确认
|
|
602
|
-
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
603
|
-
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
604
|
-
} else {
|
|
605
|
-
console.error(`【Error】:更新后内容不匹配!`);
|
|
606
|
-
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
607
|
-
console.error(` 期望前100字符: ${rulesContent.substring(0, 100)}`);
|
|
608
|
-
console.error(` 实际前100字符: ${verifyContent.substring(0, 100)}`);
|
|
609
|
-
}
|
|
610
|
-
} else {
|
|
611
|
-
console.error('【Error】:更新后验证失败,值为空');
|
|
612
|
-
}
|
|
613
|
-
} else {
|
|
614
|
-
console.log('【调试】:记录不存在,将插入新记录');
|
|
615
|
-
// 插入新记录
|
|
616
|
-
const insertStmt = db.prepare("INSERT INTO ItemTable (key, value) VALUES (?, ?)");
|
|
617
|
-
const result = insertStmt.run('aicontext.personalContext', rulesContent);
|
|
618
|
-
console.log(`【调试】:插入结果,最后插入ID: ${result.lastInsertRowid}`);
|
|
619
|
-
|
|
620
|
-
if (!result.lastInsertRowid) {
|
|
621
|
-
console.error('【Error】:插入失败,未返回插入ID');
|
|
622
|
-
db.close();
|
|
623
|
-
step4();
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// 验证插入是否成功
|
|
628
|
-
const verifyRow = db.prepare("SELECT value, length(value) as len FROM ItemTable WHERE key = ?").get('aicontext.personalContext');
|
|
629
|
-
if (verifyRow && verifyRow.value) {
|
|
630
|
-
let verifyContent = '';
|
|
631
|
-
if (Buffer.isBuffer(verifyRow.value)) {
|
|
632
|
-
verifyContent = verifyRow.value.toString('utf8');
|
|
633
|
-
} else {
|
|
634
|
-
verifyContent = String(verifyRow.value);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
if (verifyContent === rulesContent) {
|
|
638
|
-
console.log(`✓ PROJECT.md 已添加到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
639
|
-
// 显示前几行内容确认
|
|
640
|
-
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
641
|
-
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
642
|
-
} else {
|
|
643
|
-
console.error(`【Error】:插入后内容不匹配!`);
|
|
644
|
-
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
645
|
-
}
|
|
646
|
-
} else {
|
|
647
|
-
console.error('【Error】:插入后验证失败,值为空');
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
652
|
-
} catch (dbError) {
|
|
653
|
-
console.error('【Error】:操作数据库失败', dbError.message);
|
|
654
|
-
if (dbError.code === 'SQLITE_BUSY' || dbError.message.includes('locked')) {
|
|
655
|
-
console.error('【Error】:数据库被锁定,可能是 Cursor 正在使用');
|
|
656
|
-
}
|
|
657
|
-
console.error('【Error】:错误堆栈', dbError.stack);
|
|
658
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
659
|
-
} finally {
|
|
660
|
-
db.close();
|
|
661
|
-
}
|
|
662
|
-
} catch (dbError) {
|
|
663
|
-
console.error('【Error】:无法打开数据库', dbError.message);
|
|
664
|
-
console.log('【建议】:请关闭 Cursor 编辑器后重试');
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
step4();
|
|
668
|
-
} catch (error) {
|
|
669
|
-
console.error('【Error】:处理 admin/rules/PROJECT.md 失败', error.message);
|
|
670
|
-
console.log('【Warning】:可能 Cursor 未安装或路径不正确,请手动复制 admin/rules/PROJECT.md 内容');
|
|
671
|
-
step4();
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// 步骤4: 检查并更新 .gitignore
|
|
676
|
-
function step4() {
|
|
677
|
-
console.log('步骤4: 正在检查 .gitignore 文件...');
|
|
678
|
-
const gitignorePath = path.join(root_path, '.gitignore');
|
|
679
|
-
|
|
680
|
-
try {
|
|
681
|
-
if (fs.existsSync(gitignorePath)) {
|
|
682
|
-
let gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
683
|
-
const cursorIgnorePattern = /^\.cursor\/?\s*$/m;
|
|
684
|
-
|
|
685
|
-
if (!cursorIgnorePattern.test(gitignoreContent)) {
|
|
686
|
-
// 如果文件末尾没有换行,先添加换行
|
|
687
|
-
if (!gitignoreContent.endsWith('\n')) {
|
|
688
|
-
gitignoreContent += '\n';
|
|
689
|
-
}
|
|
690
|
-
gitignoreContent += '.cursor/\n';
|
|
691
|
-
fs.writeFileSync(gitignorePath, gitignoreContent, 'utf8');
|
|
692
|
-
console.log('✓ 已在 .gitignore 中添加 .cursor/ 忽略规则');
|
|
693
|
-
} else {
|
|
694
|
-
console.log('✓ .gitignore 中已存在 .cursor 忽略规则');
|
|
695
|
-
}
|
|
696
|
-
} else {
|
|
697
|
-
// 如果 .gitignore 不存在,创建它
|
|
698
|
-
fs.writeFileSync(gitignorePath, '.cursor/\n', 'utf8');
|
|
699
|
-
console.log('✓ 已创建 .gitignore 并添加 .cursor/ 忽略规则');
|
|
700
|
-
}
|
|
701
|
-
} catch (error) {
|
|
702
|
-
console.error('【Error】:更新 .gitignore 失败', error.message);
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
cleanupAndExit(0);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// 清理临时目录并退出
|
|
709
|
-
function cleanupAndExit(exitCode) {
|
|
710
|
-
deleteDir(cloneDir, () => {
|
|
711
|
-
console.log('【jjb-cmd ai-pull】:执行完成!');
|
|
712
|
-
process.exit(exitCode);
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
};
|
|
1
|
+
const a0_0x565690=a0_0x1a1d;(function(_0x30bf96,_0x461620){const _0x13c989=a0_0x1a1d,_0x42433b=_0x30bf96();while(!![]){try{const _0xdf7e5c=-parseInt(_0x13c989(0xfb))/0x1*(parseInt(_0x13c989(0xaa))/0x2)+-parseInt(_0x13c989(0xc1))/0x3*(parseInt(_0x13c989(0x78))/0x4)+-parseInt(_0x13c989(0xea))/0x5*(-parseInt(_0x13c989(0xf2))/0x6)+parseInt(_0x13c989(0xba))/0x7+parseInt(_0x13c989(0x92))/0x8+-parseInt(_0x13c989(0xb1))/0x9*(-parseInt(_0x13c989(0xbf))/0xa)+parseInt(_0x13c989(0xfc))/0xb;if(_0xdf7e5c===_0x461620)break;else _0x42433b['push'](_0x42433b['shift']());}catch(_0x533789){_0x42433b['push'](_0x42433b['shift']());}}}(a0_0x407c,0x5a3ea));const fs=require('fs'),os=require('os'),path=require(a0_0x565690(0xa0)),child_process=require('child_process');function getCursorDbPath(){const _0x3c4d17=a0_0x565690,_0x540bee=os['homedir'](),_0xd271e0=os[_0x3c4d17(0x9f)]();if(_0xd271e0==='win32')return path['join'](_0x540bee,'AppData',_0x3c4d17(0x8a),_0x3c4d17(0xf3),_0x3c4d17(0xd7),'globalStorage',_0x3c4d17(0xd8));else return _0xd271e0==='darwin'?path[_0x3c4d17(0xd1)](_0x540bee,_0x3c4d17(0xfd),'Application\x20Support',_0x3c4d17(0xf3),'User',_0x3c4d17(0x9e),_0x3c4d17(0xd8)):path['join'](_0x540bee,_0x3c4d17(0x9c),_0x3c4d17(0xf3),_0x3c4d17(0xd7),_0x3c4d17(0x9e),_0x3c4d17(0xd8));}const CURSOR_DB_PATH=getCursorDbPath(),AI_REPO_URL=a0_0x565690(0xd9),DEFAULT_BRANCH=a0_0x565690(0x81);function deleteDir(_0x52b4b1,_0x3ec077){const _0x1aeebe=a0_0x565690;if(!fs[_0x1aeebe(0xbd)](_0x52b4b1)){_0x3ec077&&_0x3ec077();return;}function _0x1b067d(_0x1f782f){const _0x315642=_0x1aeebe;if(!fs[_0x315642(0xbd)](_0x1f782f))return;try{const _0x146c14=fs[_0x315642(0x103)](_0x1f782f);for(let _0x269dec=0x0;_0x269dec<_0x146c14['length'];_0x269dec++){const _0x316fcc=_0x146c14[_0x269dec],_0x5b43ee=path[_0x315642(0xd1)](_0x1f782f,_0x316fcc),_0x549b09=fs[_0x315642(0xf9)](_0x5b43ee);if(_0x549b09[_0x315642(0xe1)]()){_0x1b067d(_0x5b43ee);try{fs[_0x315642(0x86)](_0x5b43ee);}catch(_0x2128f6){}}else try{fs[_0x315642(0x88)](_0x5b43ee);}catch(_0x4ce132){}}try{fs[_0x315642(0x86)](_0x1f782f);}catch(_0xf2ec5e){}}catch(_0xcbc7ee){}}_0x1b067d(_0x52b4b1),setTimeout(()=>{_0x3ec077&&_0x3ec077();},0x12c);}function a0_0x1a1d(_0x32f367,_0x2be6b6){_0x32f367=_0x32f367-0x78;const _0x407ccf=a0_0x407c();let _0x1a1d0f=_0x407ccf[_0x32f367];return _0x1a1d0f;}function copyFolder(_0x3fd4d1,_0x44ef2a,_0x1131b4){const _0x2ec0de=a0_0x565690;if(!fs[_0x2ec0de(0xbd)](_0x3fd4d1)){_0x1131b4&&_0x1131b4(new Error('源目录不存在:\x20'+_0x3fd4d1));return;}if(!fs[_0x2ec0de(0xbd)](_0x44ef2a))try{fs[_0x2ec0de(0xdf)](_0x44ef2a,{'recursive':!![]});}catch(_0x4631ae){_0x1131b4&&_0x1131b4(_0x4631ae);return;}copyFolderRecursive(_0x3fd4d1,_0x44ef2a,_0x1131b4);}function copyFolderRecursive(_0x47b981,_0x355c6f,_0x3bad52){const _0x36d7db=a0_0x565690;if(!fs[_0x36d7db(0xbd)](_0x47b981)){_0x3bad52&&_0x3bad52(new Error(_0x36d7db(0xdb)+_0x47b981));return;}try{const _0x2d75c8=fs['readdirSync'](_0x47b981);let _0x1631fc=0x0,_0xb1ed83=![];if(_0x2d75c8[_0x36d7db(0x8e)]===0x0){_0x3bad52&&_0x3bad52();return;}_0x2d75c8[_0x36d7db(0x8d)](_0x45bdae=>{const _0x2d3c5c=_0x36d7db,_0x3e72a5=path[_0x2d3c5c(0xd1)](_0x47b981,_0x45bdae),_0x484428=path[_0x2d3c5c(0xd1)](_0x355c6f,_0x45bdae);try{const _0x398723=fs['statSync'](_0x3e72a5);_0x398723[_0x2d3c5c(0xe1)]()?(!fs[_0x2d3c5c(0xbd)](_0x484428)&&fs[_0x2d3c5c(0xdf)](_0x484428,{'recursive':!![]}),copyFolderRecursive(_0x3e72a5,_0x484428,_0x25b999=>{const _0x2ca5d9=_0x2d3c5c;_0x1631fc++,_0x25b999&&!_0xb1ed83&&(_0xb1ed83=!![],console[_0x2ca5d9(0xf5)](_0x2ca5d9(0xa7)+_0x3e72a5+':\x20'+_0x25b999[_0x2ca5d9(0xce)])),_0x1631fc===_0x2d75c8['length']&&(_0x3bad52&&_0x3bad52(_0xb1ed83?new Error(_0x2ca5d9(0xb2)):null));})):copyFileWithRetry(_0x3e72a5,_0x484428,0x3,_0x15f1b3=>{const _0x5188f7=_0x2d3c5c;_0x1631fc++,_0x15f1b3&&!_0xb1ed83&&(_0xb1ed83=!![],console[_0x5188f7(0xf5)]('【Warning】:复制文件失败\x20'+_0x3e72a5+':\x20'+_0x15f1b3['message'])),_0x1631fc===_0x2d75c8[_0x5188f7(0x8e)]&&(_0x3bad52&&_0x3bad52(_0xb1ed83?new Error('部分文件复制失败'):null));});}catch(_0x4f7c3a){_0x1631fc++,!_0xb1ed83&&(_0xb1ed83=!![],console['log'](_0x2d3c5c(0x9d)+_0x3e72a5+':\x20'+_0x4f7c3a['message'])),_0x1631fc===_0x2d75c8[_0x2d3c5c(0x8e)]&&(_0x3bad52&&_0x3bad52(_0xb1ed83?new Error('部分文件复制失败'):null));}});}catch(_0x4361e8){_0x3bad52&&_0x3bad52(_0x4361e8);}}function a0_0x407c(){const _0x16be89=['【建议】:请运行\x20npm\x20install\x20better-sqlite3\x20或\x20npm\x20install\x20sqlite3','readdirSync','【Error】:创建\x20.cursor\x20目录失败','44quvFce','SELECT\x20value,\x20length(value)\x20as\x20len\x20FROM\x20ItemTable\x20WHERE\x20key\x20=\x20?','【Error】:未找到\x20SQLite\x20模块\x20(better-sqlite3\x20或\x20sqlite3)','【Error】:读取\x20','\x20\x20期望长度:\x20','filter','endsWith','copyFileSync','✓\x20已在\x20.gitignore\x20中添加\x20.cursor/\x20忽略规则','v_2.0.0','split','rules','exit','createReadStream','rmdirSync','【调试】:插入结果,最后插入ID:\x20','unlinkSync','run','Roaming','【分支】:','✓\x20admin/rules/PROJECT.md\x20内容未变化,无需更新','forEach','length','✓\x20已将\x20','步骤3:\x20正在更新\x20Cursor\x20user\x20rules\x20(SQLite\x20数据库)...','code','2226128cLMgRo','.cursor/\x0a','【Error】:复制\x20','【Error】:更新后内容不匹配!','slice','includes','【Error】:插入失败,未返回插入ID','\x20下\x20','【Warning】:仓库中未找到\x20admin/rules/PROJECT.md\x20文件','【预览】:内容前3行:\x0a','.config','【Warning】:处理文件失败\x20','globalStorage','platform','path','SQLITE_BUSY','\x20字节','execSync','writeFileSync','get','【Error】:插入后验证失败,值为空','【Warning】:复制目录失败\x20','.gitignore','toString','452258glVCui','复制文件失败,已重试多次:\x20','dirname','✓\x20已备份数据库文件到\x20','admin/.cursor','PROJECT.md','len','22023WHAXOl','部分文件复制失败','步骤2:\x20正在复制\x20admin\x20内\x20Cursor\x20资源到\x20.cursor/...','lastInsertRowid','【Error】:处理\x20admin/rules/PROJECT.md\x20失败','isBuffer','【Error】:查询数据库失败','aicontext.personalContext','startsWith','3292737HGmQxB',',\x20实际长度:\x20','resolve','existsSync','【Warning】:','530zFInVE','【Error】:无法打开数据库','127311ygTNWJ','【Error】:更新失败,影响行数为\x200,可能数据库被锁定','【调试】:找到现有记录,当前长度:\x20','\x20字节)','\x20\x20期望前100字符:\x20','...','【提示】:请重启\x20Cursor\x20编辑器以使规则生效','\x20个文件夹复制到\x20.cursor/(','error','INSERT\x20INTO\x20ItemTable\x20(key,\x20value)\x20VALUES\x20(?,\x20?)','【调试】:更新影响行数:\x20','【建议】:请确保已安装\x20Cursor\x20编辑器,或手动复制\x20admin/rules/PROJECT.md\x20内容','✓\x20仓库代码拉取成功(分支:\x20','message','changes','\x20目录失败','join','【Warning】:备份数据库文件失败','locked','【Error】:插入数据库失败','UPDATE\x20ItemTable\x20SET\x20value\x20=\x20?\x20WHERE\x20key\x20=\x20?','✓\x20PROJECT.md\x20已更新到\x20Cursor\x20user\x20rules\x20(','User','state.vscdb','http://192.168.1.242:10985/root/jjb-ai.git','close','源目录不存在:\x20','【Error】:更新后验证失败,值为空','【调试】:准备更新数据库,内容长度:\x20','stack','mkdirSync','✓\x20已删除旧备份文件:\x20','isDirectory','.backup.','【Error】:更新\x20.gitignore\x20失败','【Error】:更新数据库失败','EACCES','【Error】:插入后内容不匹配!','readFileSync','【Error】:拉取仓库失败','substring','354765doTrRe','【调试】:记录不存在,将插入新记录','\x20\x20实际前100字符:\x20','admin','【建议】:请关闭\x20Cursor\x20编辑器后重试','【Warning】:可能\x20Cursor\x20未安装或路径不正确,请手动复制\x20admin/rules/PROJECT.md\x20内容','basename','utf8','6KkLkfn','Cursor','value','log','git\x20clone\x20-b\x20','tmpdir','【Error】:验证插入失败','statSync','【或者】:使用命令行工具手动更新数据库','3wEOqyW','6220885LOIDvY','Library','jjb-ai-temp','✓\x20.gitignore\x20中已存在\x20.cursor\x20忽略规则','\x20失败','prepare'];a0_0x407c=function(){return _0x16be89;};return a0_0x407c();}function copyFileWithRetry(_0xaaf209,_0x3cbcda,_0x4092c4,_0x5433e9){const _0x412e44=a0_0x565690;if(_0x4092c4<=0x0){_0x5433e9&&_0x5433e9(new Error(_0x412e44(0xab)+_0xaaf209));return;}const _0xbb0407=path[_0x412e44(0xac)](_0x3cbcda);if(!fs[_0x412e44(0xbd)](_0xbb0407))try{fs[_0x412e44(0xdf)](_0xbb0407,{'recursive':!![]});}catch(_0x2cec4b){_0x5433e9&&_0x5433e9(_0x2cec4b);return;}const _0x3347ba=fs[_0x412e44(0x85)](_0xaaf209),_0x5262b2=fs['createWriteStream'](_0x3cbcda);_0x3347ba['on']('error',_0x45ba96=>{_0x5433e9&&_0x5433e9(_0x45ba96);}),_0x5262b2['on'](_0x412e44(0xc9),_0x239740=>{const _0x51bcd3=_0x412e44;_0x4092c4>0x1&&(_0x239740[_0x51bcd3(0x91)]==='EBUSY'||_0x239740[_0x51bcd3(0x91)]==='EPERM'||_0x239740[_0x51bcd3(0x91)]===_0x51bcd3(0xe5))?setTimeout(()=>{copyFileWithRetry(_0xaaf209,_0x3cbcda,_0x4092c4-0x1,_0x5433e9);},0x64):_0x5433e9&&_0x5433e9(_0x239740);}),_0x5262b2['on'](_0x412e44(0xda),()=>{_0x5433e9&&_0x5433e9();}),_0x3347ba['pipe'](_0x5262b2);}module['exports']=_0x3eee94=>{const _0x400263=a0_0x565690,_0x2d8db0=path[_0x400263(0xbc)]('./'),_0x53033e=os[_0x400263(0xf7)](),_0x3bf3e3=path[_0x400263(0xd1)](_0x53033e,_0x400263(0xfe)),_0x211c98=_0x3eee94||DEFAULT_BRANCH;console['log']('【jjb-cmd\x20ai-pull】:开始执行...'),console[_0x400263(0xf5)](_0x400263(0x8b)+_0x211c98),console['log']('步骤1:\x20正在拉取\x20jjb-ai\x20仓库代码(分支:\x20'+_0x211c98+')...'),deleteDir(_0x3bf3e3,()=>{const _0x14e14c=_0x400263;try{child_process[_0x14e14c(0xa3)](_0x14e14c(0xf6)+_0x211c98+'\x20'+AI_REPO_URL+'\x20\x22'+_0x3bf3e3+'\x22',{'stdio':'inherit','cwd':_0x53033e}),console['log'](_0x14e14c(0xcd)+_0x211c98+')'),console[_0x14e14c(0xf5)](_0x14e14c(0xb3));const _0x1ea649=path[_0x14e14c(0xd1)](_0x3bf3e3,_0x14e14c(0xed)),_0x42e8a1=path[_0x14e14c(0xd1)](_0x1ea649,'.cursor'),_0x2052da=fs[_0x14e14c(0xbd)](_0x42e8a1)?_0x42e8a1:_0x1ea649,_0x5d46c1=fs[_0x14e14c(0xbd)](_0x42e8a1)?_0x14e14c(0xae):_0x14e14c(0xed),_0x31a73b=path[_0x14e14c(0xd1)](_0x2d8db0,'.cursor');if(!fs[_0x14e14c(0xbd)](_0x1ea649))console[_0x14e14c(0xf5)]('【Warning】:仓库中未找到\x20admin\x20文件夹'),_0x3e14cd();else{let _0x470d90;try{_0x470d90=fs[_0x14e14c(0x103)](_0x2052da)[_0x14e14c(0x7d)](_0x1de68b=>{const _0x4cc741=_0x14e14c,_0x58f002=path[_0x4cc741(0xd1)](_0x2052da,_0x1de68b);try{return fs[_0x4cc741(0xf9)](_0x58f002)[_0x4cc741(0xe1)]();}catch(_0x1e4924){return![];}});}catch(_0x2b174c){console[_0x14e14c(0xc9)](_0x14e14c(0x7b)+_0x5d46c1+_0x14e14c(0xd0),_0x2b174c[_0x14e14c(0xce)]),_0x36d85b(0x1);return;}if(_0x470d90[_0x14e14c(0x8e)]===0x0)console[_0x14e14c(0xf5)](_0x14e14c(0xbe)+_0x5d46c1+'\x20下没有子文件夹可同步'),_0x3e14cd();else{try{!fs[_0x14e14c(0xbd)](_0x31a73b)&&fs[_0x14e14c(0xdf)](_0x31a73b,{'recursive':!![]});}catch(_0x101798){console['error'](_0x14e14c(0x104),_0x101798[_0x14e14c(0xce)]),_0x36d85b(0x1);return;}function _0x1d3328(_0x233c56){const _0x151070=_0x14e14c;if(_0x233c56>=_0x470d90['length']){console[_0x151070(0xf5)](_0x151070(0x8f)+_0x5d46c1+_0x151070(0x99)+_0x470d90[_0x151070(0x8e)]+_0x151070(0xc8)+_0x470d90[_0x151070(0xd1)](',\x20')+')'),_0x3e14cd();return;}const _0x4e2591=_0x470d90[_0x233c56],_0x5b6bb4=path[_0x151070(0xd1)](_0x2052da,_0x4e2591),_0x552807=path[_0x151070(0xd1)](_0x31a73b,_0x4e2591),_0x500fc1=_0x30ebeb=>{const _0x5ba42=_0x151070;if(_0x30ebeb){console[_0x5ba42(0xc9)](_0x5ba42(0x94)+_0x5d46c1+'/'+_0x4e2591+_0x5ba42(0x100),_0x30ebeb[_0x5ba42(0xce)]),_0x36d85b(0x1);return;}_0x1d3328(_0x233c56+0x1);};fs[_0x151070(0xbd)](_0x552807)?deleteDir(_0x552807,()=>{copyFolder(_0x5b6bb4,_0x552807,_0x500fc1);}):copyFolder(_0x5b6bb4,_0x552807,_0x500fc1);}_0x1d3328(0x0);}}}catch(_0x22ce1a){console[_0x14e14c(0xc9)](_0x14e14c(0xe8),_0x22ce1a['message']),_0x36d85b(0x1);}});function _0x3e14cd(){const _0x118fb8=_0x400263;console[_0x118fb8(0xf5)](_0x118fb8(0x90));const _0x1d4bdb=path[_0x118fb8(0xd1)](_0x3bf3e3,'admin',_0x118fb8(0x83),_0x118fb8(0xaf));try{if(!fs['existsSync'](_0x1d4bdb)){console[_0x118fb8(0xf5)](_0x118fb8(0x9a)),_0x22caa8();return;}const _0x3bdb03=fs[_0x118fb8(0xe7)](_0x1d4bdb,'utf8');if(!fs[_0x118fb8(0xbd)](CURSOR_DB_PATH)){console[_0x118fb8(0xf5)]('【Warning】:Cursor\x20数据库文件不存在,可能\x20Cursor\x20未安装或路径不正确'),console[_0x118fb8(0xf5)]('【路径】:'+CURSOR_DB_PATH),console['log'](_0x118fb8(0xcc)),_0x22caa8();return;}try{const _0x3f7bfd=path[_0x118fb8(0xac)](CURSOR_DB_PATH),_0x31c372=path[_0x118fb8(0xf0)](CURSOR_DB_PATH),_0x160773=fs['existsSync'](_0x3f7bfd)?fs[_0x118fb8(0x103)](_0x3f7bfd):[],_0xf2b255=_0x160773['filter'](_0xb842d6=>_0xb842d6[_0x118fb8(0xb9)](_0x31c372+_0x118fb8(0xe2)));_0xf2b255[_0x118fb8(0x8d)](_0x12bd90=>{const _0x26938c=_0x118fb8;try{const _0x5b5c56=path[_0x26938c(0xd1)](_0x3f7bfd,_0x12bd90);fs[_0x26938c(0x88)](_0x5b5c56),console[_0x26938c(0xf5)](_0x26938c(0xe0)+_0x12bd90);}catch(_0x5ea8af){}});const _0x2936ad=CURSOR_DB_PATH+_0x118fb8(0xe2)+Date['now']();fs[_0x118fb8(0x7f)](CURSOR_DB_PATH,_0x2936ad),console[_0x118fb8(0xf5)](_0x118fb8(0xad)+path['basename'](_0x2936ad));}catch(_0x589805){console[_0x118fb8(0xf5)](_0x118fb8(0xd2),_0x589805[_0x118fb8(0xce)]);}try{let _0x5b035e;try{_0x5b035e=require('better-sqlite3');}catch(_0x5c454d){try{const _0x4f53e6=require('sqlite3');console[_0x118fb8(0xf5)](_0x118fb8(0xdd)+_0x3bdb03[_0x118fb8(0x8e)]+'\x20字符');const _0x220ee8=new _0x4f53e6['Database'](CURSOR_DB_PATH,_0x37280e=>{const _0x427169=_0x118fb8;if(_0x37280e){console[_0x427169(0xc9)](_0x427169(0xc0),_0x37280e[_0x427169(0xce)]),console[_0x427169(0xf5)](_0x427169(0xee)),_0x22caa8();return;}_0x220ee8[_0x427169(0xa5)](_0x427169(0x79),[_0x427169(0xb8)],(_0x17b095,_0x3a98ae)=>{const _0x3a42b1=_0x427169;if(_0x17b095){console[_0x3a42b1(0xc9)](_0x3a42b1(0xb7),_0x17b095[_0x3a42b1(0xce)]),_0x220ee8[_0x3a42b1(0xda)](),_0x22caa8();return;}if(_0x3a98ae){console['log'](_0x3a42b1(0xc3)+_0x3a98ae[_0x3a42b1(0xb0)]+_0x3a42b1(0xa2));let _0x212486='';Buffer['isBuffer'](_0x3a98ae[_0x3a42b1(0xf4)])?_0x212486=_0x3a98ae[_0x3a42b1(0xf4)]['toString'](_0x3a42b1(0xf1)):_0x212486=String(_0x3a98ae[_0x3a42b1(0xf4)]);if(_0x212486===_0x3bdb03){console[_0x3a42b1(0xf5)](_0x3a42b1(0x8c)),console[_0x3a42b1(0xf5)](_0x3a42b1(0xc7)),_0x220ee8[_0x3a42b1(0xda)](),_0x22caa8();return;}_0x220ee8[_0x3a42b1(0x89)]('UPDATE\x20ItemTable\x20SET\x20value\x20=\x20?\x20WHERE\x20key\x20=\x20?',[_0x3bdb03,_0x3a42b1(0xb8)],function(_0x3f0b96){const _0x5661fd=_0x3a42b1;if(_0x3f0b96){console[_0x5661fd(0xc9)](_0x5661fd(0xe4),_0x3f0b96[_0x5661fd(0xce)]);(_0x3f0b96[_0x5661fd(0x91)]==='SQLITE_BUSY'||_0x3f0b96[_0x5661fd(0xce)][_0x5661fd(0x97)](_0x5661fd(0xd3)))&&console[_0x5661fd(0xc9)]('【Error】:数据库被锁定,可能是\x20Cursor\x20正在使用');console[_0x5661fd(0xf5)](_0x5661fd(0xee)),_0x220ee8[_0x5661fd(0xda)](),_0x22caa8();return;}console[_0x5661fd(0xf5)]('【调试】:更新影响行数:\x20'+this[_0x5661fd(0xcf)]);if(this[_0x5661fd(0xcf)]===0x0){console[_0x5661fd(0xc9)]('【Error】:更新失败,影响行数为\x200,可能数据库被锁定'),console[_0x5661fd(0xf5)](_0x5661fd(0xee)),_0x220ee8[_0x5661fd(0xda)](),_0x22caa8();return;}_0x220ee8[_0x5661fd(0xa5)](_0x5661fd(0x79),[_0x5661fd(0xb8)],(_0x24307e,_0x60e4b2)=>{const _0x536547=_0x5661fd;if(_0x24307e)console[_0x536547(0xc9)]('【Error】:验证更新失败',_0x24307e[_0x536547(0xce)]);else{if(_0x60e4b2&&_0x60e4b2[_0x536547(0xf4)]){let _0x331fb0='';Buffer[_0x536547(0xb6)](_0x60e4b2[_0x536547(0xf4)])?_0x331fb0=_0x60e4b2[_0x536547(0xf4)][_0x536547(0xa9)]('utf8'):_0x331fb0=String(_0x60e4b2[_0x536547(0xf4)]);if(_0x331fb0===_0x3bdb03){console[_0x536547(0xf5)](_0x536547(0xd6)+_0x60e4b2[_0x536547(0xb0)]+_0x536547(0xc4));const _0x2ccb5e=_0x331fb0['split']('\x0a')['slice'](0x0,0x3)[_0x536547(0xd1)]('\x0a');console[_0x536547(0xf5)](_0x536547(0x9b)+_0x2ccb5e+(_0x331fb0[_0x536547(0x82)]('\x0a')[_0x536547(0x8e)]>0x3?_0x536547(0xc6):''));}else console[_0x536547(0xc9)]('【Error】:更新后内容不匹配!'),console[_0x536547(0xc9)](_0x536547(0x7c)+_0x3bdb03[_0x536547(0x8e)]+_0x536547(0xbb)+_0x331fb0[_0x536547(0x8e)]),console[_0x536547(0xc9)](_0x536547(0xc5)+_0x3bdb03[_0x536547(0xe9)](0x0,0x64)),console[_0x536547(0xc9)](_0x536547(0xec)+_0x331fb0[_0x536547(0xe9)](0x0,0x64));}else console['error'](_0x536547(0xdc));}console[_0x536547(0xf5)](_0x536547(0xc7)),_0x220ee8['close'](),_0x22caa8();});});}else console['log'](_0x3a42b1(0xeb)),_0x220ee8[_0x3a42b1(0x89)](_0x3a42b1(0xca),[_0x3a42b1(0xb8),_0x3bdb03],function(_0x6e0a3b){const _0x1559ac=_0x3a42b1;if(_0x6e0a3b){console[_0x1559ac(0xc9)](_0x1559ac(0xd4),_0x6e0a3b[_0x1559ac(0xce)]);(_0x6e0a3b['code']==='SQLITE_BUSY'||_0x6e0a3b['message'][_0x1559ac(0x97)](_0x1559ac(0xd3)))&&console[_0x1559ac(0xc9)]('【Error】:数据库被锁定,可能是\x20Cursor\x20正在使用');console[_0x1559ac(0xf5)](_0x1559ac(0xee)),_0x220ee8[_0x1559ac(0xda)](),_0x22caa8();return;}console['log'](_0x1559ac(0x87)+this[_0x1559ac(0xb4)]);if(!this['lastInsertRowid']){console[_0x1559ac(0xc9)](_0x1559ac(0x98)),_0x220ee8[_0x1559ac(0xda)](),_0x22caa8();return;}_0x220ee8[_0x1559ac(0xa5)]('SELECT\x20value,\x20length(value)\x20as\x20len\x20FROM\x20ItemTable\x20WHERE\x20key\x20=\x20?',['aicontext.personalContext'],(_0x2e8fcd,_0x3a2812)=>{const _0x416f94=_0x1559ac;if(_0x2e8fcd)console[_0x416f94(0xc9)](_0x416f94(0xf8),_0x2e8fcd[_0x416f94(0xce)]);else{if(_0x3a2812&&_0x3a2812[_0x416f94(0xf4)]){let _0x2d3cd3='';Buffer[_0x416f94(0xb6)](_0x3a2812[_0x416f94(0xf4)])?_0x2d3cd3=_0x3a2812['value'][_0x416f94(0xa9)](_0x416f94(0xf1)):_0x2d3cd3=String(_0x3a2812[_0x416f94(0xf4)]);if(_0x2d3cd3===_0x3bdb03){console[_0x416f94(0xf5)]('✓\x20PROJECT.md\x20已添加到\x20Cursor\x20user\x20rules\x20('+_0x3a2812[_0x416f94(0xb0)]+'\x20字节)');const _0x1da9f0=_0x2d3cd3[_0x416f94(0x82)]('\x0a')[_0x416f94(0x96)](0x0,0x3)['join']('\x0a');console[_0x416f94(0xf5)](_0x416f94(0x9b)+_0x1da9f0+(_0x2d3cd3[_0x416f94(0x82)]('\x0a')[_0x416f94(0x8e)]>0x3?_0x416f94(0xc6):''));}else console[_0x416f94(0xc9)](_0x416f94(0xe6)),console[_0x416f94(0xc9)](_0x416f94(0x7c)+_0x3bdb03[_0x416f94(0x8e)]+_0x416f94(0xbb)+_0x2d3cd3[_0x416f94(0x8e)]);}else console[_0x416f94(0xc9)](_0x416f94(0xa6));}console[_0x416f94(0xf5)](_0x416f94(0xc7)),_0x220ee8[_0x416f94(0xda)](),_0x22caa8();});});});});return;}catch(_0x5e668){console[_0x118fb8(0xc9)](_0x118fb8(0x7a)),console['log'](_0x118fb8(0x102)),console[_0x118fb8(0xf5)](_0x118fb8(0xfa)),_0x22caa8();return;}}const _0x59de77=new _0x5b035e(CURSOR_DB_PATH,{'readonly':![]});try{console['log'](_0x118fb8(0xdd)+_0x3bdb03[_0x118fb8(0x8e)]+'\x20字符');const _0x58ec4b=_0x59de77['prepare'](_0x118fb8(0x79))['get']('aicontext.personalContext');if(_0x58ec4b){console[_0x118fb8(0xf5)]('【调试】:找到现有记录,当前长度:\x20'+_0x58ec4b['len']+_0x118fb8(0xa2));let _0x409471='';Buffer[_0x118fb8(0xb6)](_0x58ec4b[_0x118fb8(0xf4)])?_0x409471=_0x58ec4b['value']['toString']('utf8'):_0x409471=String(_0x58ec4b[_0x118fb8(0xf4)]);if(_0x409471===_0x3bdb03){console[_0x118fb8(0xf5)]('✓\x20admin/rules/PROJECT.md\x20内容未变化,无需更新'),console[_0x118fb8(0xf5)](_0x118fb8(0xc7)),_0x59de77[_0x118fb8(0xda)](),_0x22caa8();return;}const _0x3d0597=_0x59de77['prepare'](_0x118fb8(0xd5)),_0x31490a=_0x3d0597['run'](_0x3bdb03,_0x118fb8(0xb8));console[_0x118fb8(0xf5)](_0x118fb8(0xcb)+_0x31490a[_0x118fb8(0xcf)]);if(_0x31490a[_0x118fb8(0xcf)]===0x0){console['error'](_0x118fb8(0xc2)),console[_0x118fb8(0xf5)](_0x118fb8(0xee)),_0x59de77[_0x118fb8(0xda)](),_0x22caa8();return;}const _0x3d178c=_0x59de77[_0x118fb8(0x101)](_0x118fb8(0x79))[_0x118fb8(0xa5)](_0x118fb8(0xb8));if(_0x3d178c&&_0x3d178c[_0x118fb8(0xf4)]){let _0x49b7a6='';Buffer[_0x118fb8(0xb6)](_0x3d178c[_0x118fb8(0xf4)])?_0x49b7a6=_0x3d178c[_0x118fb8(0xf4)][_0x118fb8(0xa9)](_0x118fb8(0xf1)):_0x49b7a6=String(_0x3d178c[_0x118fb8(0xf4)]);if(_0x49b7a6===_0x3bdb03){console[_0x118fb8(0xf5)]('✓\x20PROJECT.md\x20已更新到\x20Cursor\x20user\x20rules\x20('+_0x3d178c[_0x118fb8(0xb0)]+_0x118fb8(0xc4));const _0x5849ee=_0x49b7a6['split']('\x0a')[_0x118fb8(0x96)](0x0,0x3)[_0x118fb8(0xd1)]('\x0a');console[_0x118fb8(0xf5)](_0x118fb8(0x9b)+_0x5849ee+(_0x49b7a6[_0x118fb8(0x82)]('\x0a')[_0x118fb8(0x8e)]>0x3?'...':''));}else console[_0x118fb8(0xc9)](_0x118fb8(0x95)),console[_0x118fb8(0xc9)]('\x20\x20期望长度:\x20'+_0x3bdb03[_0x118fb8(0x8e)]+_0x118fb8(0xbb)+_0x49b7a6[_0x118fb8(0x8e)]),console[_0x118fb8(0xc9)](_0x118fb8(0xc5)+_0x3bdb03[_0x118fb8(0xe9)](0x0,0x64)),console[_0x118fb8(0xc9)](_0x118fb8(0xec)+_0x49b7a6[_0x118fb8(0xe9)](0x0,0x64));}else console['error']('【Error】:更新后验证失败,值为空');}else{console[_0x118fb8(0xf5)](_0x118fb8(0xeb));const _0x30a5bc=_0x59de77['prepare'](_0x118fb8(0xca)),_0xfb9c5b=_0x30a5bc['run'](_0x118fb8(0xb8),_0x3bdb03);console['log'](_0x118fb8(0x87)+_0xfb9c5b['lastInsertRowid']);if(!_0xfb9c5b[_0x118fb8(0xb4)]){console[_0x118fb8(0xc9)](_0x118fb8(0x98)),_0x59de77[_0x118fb8(0xda)](),_0x22caa8();return;}const _0x440b28=_0x59de77[_0x118fb8(0x101)](_0x118fb8(0x79))[_0x118fb8(0xa5)](_0x118fb8(0xb8));if(_0x440b28&&_0x440b28[_0x118fb8(0xf4)]){let _0x2ff44d='';Buffer[_0x118fb8(0xb6)](_0x440b28['value'])?_0x2ff44d=_0x440b28[_0x118fb8(0xf4)]['toString']('utf8'):_0x2ff44d=String(_0x440b28['value']);if(_0x2ff44d===_0x3bdb03){console[_0x118fb8(0xf5)]('✓\x20PROJECT.md\x20已添加到\x20Cursor\x20user\x20rules\x20('+_0x440b28['len']+'\x20字节)');const _0x589da3=_0x2ff44d['split']('\x0a')['slice'](0x0,0x3)[_0x118fb8(0xd1)]('\x0a');console[_0x118fb8(0xf5)](_0x118fb8(0x9b)+_0x589da3+(_0x2ff44d[_0x118fb8(0x82)]('\x0a')[_0x118fb8(0x8e)]>0x3?'...':''));}else console[_0x118fb8(0xc9)](_0x118fb8(0xe6)),console[_0x118fb8(0xc9)](_0x118fb8(0x7c)+_0x3bdb03[_0x118fb8(0x8e)]+_0x118fb8(0xbb)+_0x2ff44d[_0x118fb8(0x8e)]);}else console[_0x118fb8(0xc9)](_0x118fb8(0xa6));}console[_0x118fb8(0xf5)]('【提示】:请重启\x20Cursor\x20编辑器以使规则生效');}catch(_0x4404b5){console['error']('【Error】:操作数据库失败',_0x4404b5[_0x118fb8(0xce)]),(_0x4404b5[_0x118fb8(0x91)]===_0x118fb8(0xa1)||_0x4404b5[_0x118fb8(0xce)]['includes'](_0x118fb8(0xd3)))&&console['error']('【Error】:数据库被锁定,可能是\x20Cursor\x20正在使用'),console[_0x118fb8(0xc9)]('【Error】:错误堆栈',_0x4404b5[_0x118fb8(0xde)]),console['log'](_0x118fb8(0xee));}finally{_0x59de77[_0x118fb8(0xda)]();}}catch(_0x425c84){console[_0x118fb8(0xc9)](_0x118fb8(0xc0),_0x425c84[_0x118fb8(0xce)]),console[_0x118fb8(0xf5)](_0x118fb8(0xee));}_0x22caa8();}catch(_0x3ddb08){console[_0x118fb8(0xc9)](_0x118fb8(0xb5),_0x3ddb08[_0x118fb8(0xce)]),console[_0x118fb8(0xf5)](_0x118fb8(0xef)),_0x22caa8();}}function _0x22caa8(){const _0x5998b7=_0x400263;console[_0x5998b7(0xf5)]('步骤4:\x20正在检查\x20.gitignore\x20文件...');const _0x4d029d=path[_0x5998b7(0xd1)](_0x2d8db0,_0x5998b7(0xa8));try{if(fs[_0x5998b7(0xbd)](_0x4d029d)){let _0x3c36a8=fs['readFileSync'](_0x4d029d,_0x5998b7(0xf1));const _0x1032cd=/^\.cursor\/?\s*$/m;!_0x1032cd['test'](_0x3c36a8)?(!_0x3c36a8[_0x5998b7(0x7e)]('\x0a')&&(_0x3c36a8+='\x0a'),_0x3c36a8+='.cursor/\x0a',fs[_0x5998b7(0xa4)](_0x4d029d,_0x3c36a8,_0x5998b7(0xf1)),console[_0x5998b7(0xf5)](_0x5998b7(0x80))):console[_0x5998b7(0xf5)](_0x5998b7(0xff));}else fs[_0x5998b7(0xa4)](_0x4d029d,_0x5998b7(0x93),_0x5998b7(0xf1)),console['log']('✓\x20已创建\x20.gitignore\x20并添加\x20.cursor/\x20忽略规则');}catch(_0xe8dfe3){console[_0x5998b7(0xc9)](_0x5998b7(0xe3),_0xe8dfe3['message']);}_0x36d85b(0x0);}function _0x36d85b(_0x54cf2a){deleteDir(_0x3bf3e3,()=>{const _0x3da943=a0_0x1a1d;console['log']('【jjb-cmd\x20ai-pull】:执行完成!'),process[_0x3da943(0x84)](_0x54cf2a);});}};
|