jjb-cmd 2.5.6 → 2.5.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/package.json +1 -1
- package/src/ai-pull.js +103 -67
package/package.json
CHANGED
package/src/ai-pull.js
CHANGED
|
@@ -18,7 +18,7 @@ const CURSOR_DB_PATH = path.join(
|
|
|
18
18
|
// Git 仓库地址
|
|
19
19
|
const AI_REPO_URL = 'http://192.168.1.242:10985/root/jjb-ai.git';
|
|
20
20
|
// Git 分支/标签(默认值)
|
|
21
|
-
const DEFAULT_BRANCH = '
|
|
21
|
+
const DEFAULT_BRANCH = 'v_2.0.0';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* 删除目录(回调方式,使用递归删除)
|
|
@@ -241,40 +241,76 @@ module.exports = (branch) => {
|
|
|
241
241
|
});
|
|
242
242
|
console.log(`✓ 仓库代码拉取成功(分支: ${targetBranch})`);
|
|
243
243
|
|
|
244
|
-
// 步骤2:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
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');
|
|
248
252
|
|
|
249
|
-
if (!fs.existsSync(
|
|
250
|
-
console.log('【Warning】:仓库中未找到
|
|
253
|
+
if (!fs.existsSync(adminRootPath)) {
|
|
254
|
+
console.log('【Warning】:仓库中未找到 admin 文件夹');
|
|
251
255
|
step3();
|
|
252
256
|
} else {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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) => {
|
|
258
297
|
if (err) {
|
|
259
|
-
console.error(
|
|
298
|
+
console.error(`【Error】:复制 ${syncSourceLabel}/${name} 失败`, err.message);
|
|
260
299
|
cleanupAndExit(1);
|
|
261
300
|
return;
|
|
262
301
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
console.error('【Error】:复制 .ai 文件夹失败', err.message);
|
|
272
|
-
cleanupAndExit(1);
|
|
273
|
-
return;
|
|
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);
|
|
274
310
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
copyAdminDirAt(0);
|
|
278
314
|
}
|
|
279
315
|
}
|
|
280
316
|
} catch (error) {
|
|
@@ -283,26 +319,26 @@ module.exports = (branch) => {
|
|
|
283
319
|
}
|
|
284
320
|
});
|
|
285
321
|
|
|
286
|
-
// 步骤3:
|
|
322
|
+
// 步骤3: 将 admin/rules/PROJECT.md 写入 Cursor user rules (SQLite 数据库)
|
|
287
323
|
function step3() {
|
|
288
324
|
console.log('步骤3: 正在更新 Cursor user rules (SQLite 数据库)...');
|
|
289
|
-
const
|
|
325
|
+
const projectRulesPath = path.join(cloneDir, 'admin', 'rules', 'PROJECT.md');
|
|
290
326
|
|
|
291
327
|
try {
|
|
292
|
-
if (!fs.existsSync(
|
|
293
|
-
console.log('【Warning】:仓库中未找到
|
|
328
|
+
if (!fs.existsSync(projectRulesPath)) {
|
|
329
|
+
console.log('【Warning】:仓库中未找到 admin/rules/PROJECT.md 文件');
|
|
294
330
|
step4();
|
|
295
331
|
return;
|
|
296
332
|
}
|
|
297
333
|
|
|
298
|
-
// 读取
|
|
299
|
-
const
|
|
334
|
+
// 读取 PROJECT.md 内容
|
|
335
|
+
const rulesContent = fs.readFileSync(projectRulesPath, 'utf8');
|
|
300
336
|
|
|
301
337
|
// 检查数据库文件是否存在
|
|
302
338
|
if (!fs.existsSync(CURSOR_DB_PATH)) {
|
|
303
339
|
console.log('【Warning】:Cursor 数据库文件不存在,可能 Cursor 未安装或路径不正确');
|
|
304
340
|
console.log(`【路径】:${CURSOR_DB_PATH}`);
|
|
305
|
-
console.log('【建议】:请确保已安装 Cursor 编辑器,或手动复制
|
|
341
|
+
console.log('【建议】:请确保已安装 Cursor 编辑器,或手动复制 admin/rules/PROJECT.md 内容');
|
|
306
342
|
step4();
|
|
307
343
|
return;
|
|
308
344
|
}
|
|
@@ -348,7 +384,7 @@ module.exports = (branch) => {
|
|
|
348
384
|
try {
|
|
349
385
|
const sqlite3 = require('sqlite3');
|
|
350
386
|
// sqlite3 是异步的,需要使用回调或 Promise
|
|
351
|
-
console.log(`【调试】:准备更新数据库,内容长度: ${
|
|
387
|
+
console.log(`【调试】:准备更新数据库,内容长度: ${rulesContent.length} 字符`);
|
|
352
388
|
|
|
353
389
|
const db = new sqlite3.Database(CURSOR_DB_PATH, (err) => {
|
|
354
390
|
if (err) {
|
|
@@ -379,8 +415,8 @@ module.exports = (branch) => {
|
|
|
379
415
|
oldContent = String(row.value);
|
|
380
416
|
}
|
|
381
417
|
|
|
382
|
-
if (oldContent ===
|
|
383
|
-
console.log('✓
|
|
418
|
+
if (oldContent === rulesContent) {
|
|
419
|
+
console.log('✓ admin/rules/PROJECT.md 内容未变化,无需更新');
|
|
384
420
|
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
385
421
|
db.close();
|
|
386
422
|
step4();
|
|
@@ -388,7 +424,7 @@ module.exports = (branch) => {
|
|
|
388
424
|
}
|
|
389
425
|
|
|
390
426
|
// 更新现有记录
|
|
391
|
-
db.run("UPDATE ItemTable SET value = ? WHERE key = ?", [
|
|
427
|
+
db.run("UPDATE ItemTable SET value = ? WHERE key = ?", [rulesContent, 'aicontext.personalContext'], function(err) {
|
|
392
428
|
if (err) {
|
|
393
429
|
console.error('【Error】:更新数据库失败', err.message);
|
|
394
430
|
if (err.code === 'SQLITE_BUSY' || err.message.includes('locked')) {
|
|
@@ -422,15 +458,15 @@ module.exports = (branch) => {
|
|
|
422
458
|
verifyContent = String(verifyRow.value);
|
|
423
459
|
}
|
|
424
460
|
|
|
425
|
-
if (verifyContent ===
|
|
426
|
-
console.log(`✓
|
|
461
|
+
if (verifyContent === rulesContent) {
|
|
462
|
+
console.log(`✓ PROJECT.md 已更新到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
427
463
|
// 显示前几行内容确认
|
|
428
464
|
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
429
465
|
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
430
466
|
} else {
|
|
431
467
|
console.error(`【Error】:更新后内容不匹配!`);
|
|
432
|
-
console.error(` 期望长度: ${
|
|
433
|
-
console.error(` 期望前100字符: ${
|
|
468
|
+
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
469
|
+
console.error(` 期望前100字符: ${rulesContent.substring(0, 100)}`);
|
|
434
470
|
console.error(` 实际前100字符: ${verifyContent.substring(0, 100)}`);
|
|
435
471
|
}
|
|
436
472
|
} else {
|
|
@@ -445,7 +481,7 @@ module.exports = (branch) => {
|
|
|
445
481
|
} else {
|
|
446
482
|
console.log('【调试】:记录不存在,将插入新记录');
|
|
447
483
|
// 插入新记录
|
|
448
|
-
db.run("INSERT INTO ItemTable (key, value) VALUES (?, ?)", ['aicontext.personalContext',
|
|
484
|
+
db.run("INSERT INTO ItemTable (key, value) VALUES (?, ?)", ['aicontext.personalContext', rulesContent], function(err) {
|
|
449
485
|
if (err) {
|
|
450
486
|
console.error('【Error】:插入数据库失败', err.message);
|
|
451
487
|
if (err.code === 'SQLITE_BUSY' || err.message.includes('locked')) {
|
|
@@ -478,14 +514,14 @@ module.exports = (branch) => {
|
|
|
478
514
|
verifyContent = String(verifyRow.value);
|
|
479
515
|
}
|
|
480
516
|
|
|
481
|
-
if (verifyContent ===
|
|
482
|
-
console.log(`✓
|
|
517
|
+
if (verifyContent === rulesContent) {
|
|
518
|
+
console.log(`✓ PROJECT.md 已添加到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
483
519
|
// 显示前几行内容确认
|
|
484
520
|
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
485
521
|
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
486
522
|
} else {
|
|
487
523
|
console.error(`【Error】:插入后内容不匹配!`);
|
|
488
|
-
console.error(` 期望长度: ${
|
|
524
|
+
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
489
525
|
}
|
|
490
526
|
} else {
|
|
491
527
|
console.error('【Error】:插入后验证失败,值为空');
|
|
@@ -513,7 +549,7 @@ module.exports = (branch) => {
|
|
|
513
549
|
const db = new Database(CURSOR_DB_PATH, { readonly: false });
|
|
514
550
|
|
|
515
551
|
try {
|
|
516
|
-
console.log(`【调试】:准备更新数据库,内容长度: ${
|
|
552
|
+
console.log(`【调试】:准备更新数据库,内容长度: ${rulesContent.length} 字符`);
|
|
517
553
|
|
|
518
554
|
// 先查询是否存在该键
|
|
519
555
|
const row = db.prepare("SELECT value, length(value) as len FROM ItemTable WHERE key = ?").get('aicontext.personalContext');
|
|
@@ -529,8 +565,8 @@ module.exports = (branch) => {
|
|
|
529
565
|
oldContent = String(row.value);
|
|
530
566
|
}
|
|
531
567
|
|
|
532
|
-
if (oldContent ===
|
|
533
|
-
console.log('✓
|
|
568
|
+
if (oldContent === rulesContent) {
|
|
569
|
+
console.log('✓ admin/rules/PROJECT.md 内容未变化,无需更新');
|
|
534
570
|
console.log('【提示】:请重启 Cursor 编辑器以使规则生效');
|
|
535
571
|
db.close();
|
|
536
572
|
step4();
|
|
@@ -539,7 +575,7 @@ module.exports = (branch) => {
|
|
|
539
575
|
|
|
540
576
|
// 更新现有记录
|
|
541
577
|
const updateStmt = db.prepare("UPDATE ItemTable SET value = ? WHERE key = ?");
|
|
542
|
-
const result = updateStmt.run(
|
|
578
|
+
const result = updateStmt.run(rulesContent, 'aicontext.personalContext');
|
|
543
579
|
console.log(`【调试】:更新影响行数: ${result.changes}`);
|
|
544
580
|
|
|
545
581
|
if (result.changes === 0) {
|
|
@@ -560,15 +596,15 @@ module.exports = (branch) => {
|
|
|
560
596
|
verifyContent = String(verifyRow.value);
|
|
561
597
|
}
|
|
562
598
|
|
|
563
|
-
if (verifyContent ===
|
|
564
|
-
console.log(`✓
|
|
599
|
+
if (verifyContent === rulesContent) {
|
|
600
|
+
console.log(`✓ PROJECT.md 已更新到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
565
601
|
// 显示前几行内容确认
|
|
566
602
|
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
567
603
|
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
568
604
|
} else {
|
|
569
605
|
console.error(`【Error】:更新后内容不匹配!`);
|
|
570
|
-
console.error(` 期望长度: ${
|
|
571
|
-
console.error(` 期望前100字符: ${
|
|
606
|
+
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
607
|
+
console.error(` 期望前100字符: ${rulesContent.substring(0, 100)}`);
|
|
572
608
|
console.error(` 实际前100字符: ${verifyContent.substring(0, 100)}`);
|
|
573
609
|
}
|
|
574
610
|
} else {
|
|
@@ -578,7 +614,7 @@ module.exports = (branch) => {
|
|
|
578
614
|
console.log('【调试】:记录不存在,将插入新记录');
|
|
579
615
|
// 插入新记录
|
|
580
616
|
const insertStmt = db.prepare("INSERT INTO ItemTable (key, value) VALUES (?, ?)");
|
|
581
|
-
const result = insertStmt.run('aicontext.personalContext',
|
|
617
|
+
const result = insertStmt.run('aicontext.personalContext', rulesContent);
|
|
582
618
|
console.log(`【调试】:插入结果,最后插入ID: ${result.lastInsertRowid}`);
|
|
583
619
|
|
|
584
620
|
if (!result.lastInsertRowid) {
|
|
@@ -598,14 +634,14 @@ module.exports = (branch) => {
|
|
|
598
634
|
verifyContent = String(verifyRow.value);
|
|
599
635
|
}
|
|
600
636
|
|
|
601
|
-
if (verifyContent ===
|
|
602
|
-
console.log(`✓
|
|
637
|
+
if (verifyContent === rulesContent) {
|
|
638
|
+
console.log(`✓ PROJECT.md 已添加到 Cursor user rules (${verifyRow.len} 字节)`);
|
|
603
639
|
// 显示前几行内容确认
|
|
604
640
|
const previewLines = verifyContent.split('\n').slice(0, 3).join('\n');
|
|
605
641
|
console.log(`【预览】:内容前3行:\n${previewLines}${verifyContent.split('\n').length > 3 ? '...' : ''}`);
|
|
606
642
|
} else {
|
|
607
643
|
console.error(`【Error】:插入后内容不匹配!`);
|
|
608
|
-
console.error(` 期望长度: ${
|
|
644
|
+
console.error(` 期望长度: ${rulesContent.length}, 实际长度: ${verifyContent.length}`);
|
|
609
645
|
}
|
|
610
646
|
} else {
|
|
611
647
|
console.error('【Error】:插入后验证失败,值为空');
|
|
@@ -630,8 +666,8 @@ module.exports = (branch) => {
|
|
|
630
666
|
|
|
631
667
|
step4();
|
|
632
668
|
} catch (error) {
|
|
633
|
-
console.error('【Error】:处理
|
|
634
|
-
console.log('【Warning】:可能 Cursor 未安装或路径不正确,请手动复制
|
|
669
|
+
console.error('【Error】:处理 admin/rules/PROJECT.md 失败', error.message);
|
|
670
|
+
console.log('【Warning】:可能 Cursor 未安装或路径不正确,请手动复制 admin/rules/PROJECT.md 内容');
|
|
635
671
|
step4();
|
|
636
672
|
}
|
|
637
673
|
}
|
|
@@ -644,23 +680,23 @@ module.exports = (branch) => {
|
|
|
644
680
|
try {
|
|
645
681
|
if (fs.existsSync(gitignorePath)) {
|
|
646
682
|
let gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
|
|
647
|
-
const
|
|
683
|
+
const cursorIgnorePattern = /^\.cursor\/?\s*$/m;
|
|
648
684
|
|
|
649
|
-
if (!
|
|
685
|
+
if (!cursorIgnorePattern.test(gitignoreContent)) {
|
|
650
686
|
// 如果文件末尾没有换行,先添加换行
|
|
651
687
|
if (!gitignoreContent.endsWith('\n')) {
|
|
652
688
|
gitignoreContent += '\n';
|
|
653
689
|
}
|
|
654
|
-
gitignoreContent += '.
|
|
690
|
+
gitignoreContent += '.cursor/\n';
|
|
655
691
|
fs.writeFileSync(gitignorePath, gitignoreContent, 'utf8');
|
|
656
|
-
console.log('✓ 已在 .gitignore 中添加 .
|
|
692
|
+
console.log('✓ 已在 .gitignore 中添加 .cursor/ 忽略规则');
|
|
657
693
|
} else {
|
|
658
|
-
console.log('✓ .gitignore 中已存在 .
|
|
694
|
+
console.log('✓ .gitignore 中已存在 .cursor 忽略规则');
|
|
659
695
|
}
|
|
660
696
|
} else {
|
|
661
697
|
// 如果 .gitignore 不存在,创建它
|
|
662
|
-
fs.writeFileSync(gitignorePath, '.
|
|
663
|
-
console.log('✓ 已创建 .gitignore 并添加 .
|
|
698
|
+
fs.writeFileSync(gitignorePath, '.cursor/\n', 'utf8');
|
|
699
|
+
console.log('✓ 已创建 .gitignore 并添加 .cursor/ 忽略规则');
|
|
664
700
|
}
|
|
665
701
|
} catch (error) {
|
|
666
702
|
console.error('【Error】:更新 .gitignore 失败', error.message);
|