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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/ai-pull.js +103 -67
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "env": "prod",
5
5
  "httpMethod": "http",
6
6
  "pushMessage": "yes",
7
- "version": "2.5.6",
7
+ "version": "2.5.8",
8
8
  "description": "jjb-cmd命令行工具",
9
9
  "main": "index.js",
10
10
  "scripts": {
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 = 'v_1.0.0';
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: 复制 .ai 文件夹到当前项目
245
- console.log('步骤2: 正在复制 .ai 文件夹...');
246
- const aiSourcePath = path.join(cloneDir, '.ai');
247
- const aiTargetPath = path.join(root_path, '.ai');
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(aiSourcePath)) {
250
- console.log('【Warning】:仓库中未找到 .ai 文件夹');
253
+ if (!fs.existsSync(adminRootPath)) {
254
+ console.log('【Warning】:仓库中未找到 admin 文件夹');
251
255
  step3();
252
256
  } else {
253
- // 如果目标目录已存在,先删除
254
- if (fs.existsSync(aiTargetPath)) {
255
- deleteDir(aiTargetPath, () => {
256
- // 复制 .ai 文件夹
257
- copyFolder(aiSourcePath, aiTargetPath, (err) => {
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('【Error】:复制 .ai 文件夹失败', err.message);
298
+ console.error(`【Error】:复制 ${syncSourceLabel}/${name} 失败`, err.message);
260
299
  cleanupAndExit(1);
261
300
  return;
262
301
  }
263
- console.log('✓ .ai 文件夹复制成功');
264
- step3();
265
- });
266
- });
267
- } else {
268
- // 复制 .ai 文件夹
269
- copyFolder(aiSourcePath, aiTargetPath, (err) => {
270
- if (err) {
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
- console.log('✓ .ai 文件夹复制成功');
276
- step3();
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: 复制 prompt.md Cursor user rules (SQLite 数据库)
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 promptSourcePath = path.join(cloneDir, 'prompt.md');
325
+ const projectRulesPath = path.join(cloneDir, 'admin', 'rules', 'PROJECT.md');
290
326
 
291
327
  try {
292
- if (!fs.existsSync(promptSourcePath)) {
293
- console.log('【Warning】:仓库中未找到 prompt.md 文件');
328
+ if (!fs.existsSync(projectRulesPath)) {
329
+ console.log('【Warning】:仓库中未找到 admin/rules/PROJECT.md 文件');
294
330
  step4();
295
331
  return;
296
332
  }
297
333
 
298
- // 读取 prompt.md 内容
299
- const promptContent = fs.readFileSync(promptSourcePath, 'utf8');
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 编辑器,或手动复制 prompt.md 内容');
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(`【调试】:准备更新数据库,内容长度: ${promptContent.length} 字符`);
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 === promptContent) {
383
- console.log('✓ prompt.md 内容未变化,无需更新');
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 = ?", [promptContent, 'aicontext.personalContext'], function(err) {
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 === promptContent) {
426
- console.log(`✓ prompt.md 已更新到 Cursor user rules (${verifyRow.len} 字节)`);
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(` 期望长度: ${promptContent.length}, 实际长度: ${verifyContent.length}`);
433
- console.error(` 期望前100字符: ${promptContent.substring(0, 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', promptContent], function(err) {
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 === promptContent) {
482
- console.log(`✓ prompt.md 已添加到 Cursor user rules (${verifyRow.len} 字节)`);
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(` 期望长度: ${promptContent.length}, 实际长度: ${verifyContent.length}`);
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(`【调试】:准备更新数据库,内容长度: ${promptContent.length} 字符`);
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 === promptContent) {
533
- console.log('✓ prompt.md 内容未变化,无需更新');
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(promptContent, 'aicontext.personalContext');
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 === promptContent) {
564
- console.log(`✓ prompt.md 已更新到 Cursor user rules (${verifyRow.len} 字节)`);
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(` 期望长度: ${promptContent.length}, 实际长度: ${verifyContent.length}`);
571
- console.error(` 期望前100字符: ${promptContent.substring(0, 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', promptContent);
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 === promptContent) {
602
- console.log(`✓ prompt.md 已添加到 Cursor user rules (${verifyRow.len} 字节)`);
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(` 期望长度: ${promptContent.length}, 实际长度: ${verifyContent.length}`);
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】:处理 prompt.md 失败', error.message);
634
- console.log('【Warning】:可能 Cursor 未安装或路径不正确,请手动复制 prompt.md');
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 aiIgnorePattern = /^\.ai\s*$/m;
683
+ const cursorIgnorePattern = /^\.cursor\/?\s*$/m;
648
684
 
649
- if (!aiIgnorePattern.test(gitignoreContent)) {
685
+ if (!cursorIgnorePattern.test(gitignoreContent)) {
650
686
  // 如果文件末尾没有换行,先添加换行
651
687
  if (!gitignoreContent.endsWith('\n')) {
652
688
  gitignoreContent += '\n';
653
689
  }
654
- gitignoreContent += '.ai\n';
690
+ gitignoreContent += '.cursor/\n';
655
691
  fs.writeFileSync(gitignorePath, gitignoreContent, 'utf8');
656
- console.log('✓ 已在 .gitignore 中添加 .ai 忽略规则');
692
+ console.log('✓ 已在 .gitignore 中添加 .cursor/ 忽略规则');
657
693
  } else {
658
- console.log('✓ .gitignore 中已存在 .ai 忽略规则');
694
+ console.log('✓ .gitignore 中已存在 .cursor 忽略规则');
659
695
  }
660
696
  } else {
661
697
  // 如果 .gitignore 不存在,创建它
662
- fs.writeFileSync(gitignorePath, '.ai\n', 'utf8');
663
- console.log('✓ 已创建 .gitignore 并添加 .ai 忽略规则');
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);