rulesync 6.6.2 → 6.7.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.
Files changed (3) hide show
  1. package/dist/index.cjs +73 -131
  2. package/dist/index.js +73 -131
  3. package/package.json +13 -13
package/dist/index.cjs CHANGED
@@ -321,16 +321,22 @@ var FeatureProcessor = class {
321
321
  * Returns the number of files written.
322
322
  */
323
323
  async writeAiFiles(aiFiles) {
324
+ let changedCount = 0;
324
325
  for (const aiFile of aiFiles) {
325
326
  const filePath = aiFile.getFilePath();
327
+ const contentWithNewline = addTrailingNewline(aiFile.getFileContent());
328
+ const existingContent = await readFileContentOrNull(filePath);
329
+ if (existingContent === contentWithNewline) {
330
+ continue;
331
+ }
326
332
  if (this.dryRun) {
327
333
  logger.info(`[DRY RUN] Would write: ${filePath}`);
328
334
  } else {
329
- const contentWithNewline = addTrailingNewline(aiFile.getFileContent());
330
335
  await writeFileContent(filePath, contentWithNewline);
331
336
  }
337
+ changedCount++;
332
338
  }
333
- return aiFiles.length;
339
+ return changedCount;
334
340
  }
335
341
  async removeAiFiles(aiFiles) {
336
342
  for (const aiFile of aiFiles) {
@@ -352,6 +358,7 @@ var FeatureProcessor = class {
352
358
  await removeFile(filePath);
353
359
  }
354
360
  }
361
+ return orphanFiles.length;
355
362
  }
356
363
  };
357
364
 
@@ -6424,35 +6431,60 @@ var DirFeatureProcessor = class {
6424
6431
  * Returns the number of directories written.
6425
6432
  */
6426
6433
  async writeAiDirs(aiDirs) {
6434
+ let changedCount = 0;
6427
6435
  for (const aiDir of aiDirs) {
6428
6436
  const dirPath = aiDir.getDirPath();
6437
+ let dirHasChanges = false;
6438
+ const mainFile = aiDir.getMainFile();
6439
+ let mainFileContent;
6440
+ if (mainFile) {
6441
+ const mainFilePath = (0, import_node_path56.join)(dirPath, mainFile.name);
6442
+ const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter);
6443
+ mainFileContent = addTrailingNewline(content);
6444
+ const existingContent = await readFileContentOrNull(mainFilePath);
6445
+ if (existingContent !== mainFileContent) {
6446
+ dirHasChanges = true;
6447
+ }
6448
+ }
6449
+ const otherFiles = aiDir.getOtherFiles();
6450
+ const otherFileContents = [];
6451
+ for (const file of otherFiles) {
6452
+ const contentWithNewline = addTrailingNewline(file.fileBuffer.toString("utf-8"));
6453
+ otherFileContents.push(contentWithNewline);
6454
+ if (!dirHasChanges) {
6455
+ const filePath = (0, import_node_path56.join)(dirPath, file.relativeFilePathToDirPath);
6456
+ const existingContent = await readFileContentOrNull(filePath);
6457
+ if (existingContent !== contentWithNewline) {
6458
+ dirHasChanges = true;
6459
+ }
6460
+ }
6461
+ }
6462
+ if (!dirHasChanges) {
6463
+ continue;
6464
+ }
6429
6465
  if (this.dryRun) {
6430
6466
  logger.info(`[DRY RUN] Would create directory: ${dirPath}`);
6431
- const mainFile = aiDir.getMainFile();
6432
6467
  if (mainFile) {
6433
6468
  logger.info(`[DRY RUN] Would write: ${(0, import_node_path56.join)(dirPath, mainFile.name)}`);
6434
6469
  }
6435
- for (const file of aiDir.getOtherFiles()) {
6470
+ for (const file of otherFiles) {
6436
6471
  logger.info(`[DRY RUN] Would write: ${(0, import_node_path56.join)(dirPath, file.relativeFilePathToDirPath)}`);
6437
6472
  }
6438
6473
  } else {
6439
6474
  await ensureDir(dirPath);
6440
- const mainFile = aiDir.getMainFile();
6441
- if (mainFile) {
6475
+ if (mainFile && mainFileContent) {
6442
6476
  const mainFilePath = (0, import_node_path56.join)(dirPath, mainFile.name);
6443
- const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter);
6444
- const contentWithNewline = addTrailingNewline(content);
6445
- await writeFileContent(mainFilePath, contentWithNewline);
6477
+ await writeFileContent(mainFilePath, mainFileContent);
6446
6478
  }
6447
- const otherFiles = aiDir.getOtherFiles();
6448
- for (const file of otherFiles) {
6479
+ for (const [i, file] of otherFiles.entries()) {
6449
6480
  const filePath = (0, import_node_path56.join)(dirPath, file.relativeFilePathToDirPath);
6450
- const contentWithNewline = addTrailingNewline(file.fileBuffer.toString("utf-8"));
6451
- await writeFileContent(filePath, contentWithNewline);
6481
+ const content = otherFileContents[i] ?? "";
6482
+ await writeFileContent(filePath, content);
6452
6483
  }
6453
6484
  }
6485
+ changedCount++;
6454
6486
  }
6455
- return aiDirs.length;
6487
+ return changedCount;
6456
6488
  }
6457
6489
  async removeAiDirs(aiDirs) {
6458
6490
  for (const aiDir of aiDirs) {
@@ -6474,6 +6506,7 @@ var DirFeatureProcessor = class {
6474
6506
  await removeDirectory(dirPath);
6475
6507
  }
6476
6508
  }
6509
+ return orphanDirs.length;
6477
6510
  }
6478
6511
  };
6479
6512
 
@@ -14701,19 +14734,13 @@ async function generateRulesCore(params) {
14701
14734
  });
14702
14735
  const rulesyncFiles = await processor.loadRulesyncFiles();
14703
14736
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14704
- if (isPreviewMode) {
14705
- const fileDiff = await detectFileDiff(toolFiles);
14706
- if (fileDiff) hasDiff = true;
14707
- }
14708
14737
  const writtenCount = await processor.writeAiFiles(toolFiles);
14709
14738
  totalCount += writtenCount;
14739
+ if (writtenCount > 0) hasDiff = true;
14710
14740
  if (config.getDelete()) {
14711
14741
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14712
- if (isPreviewMode) {
14713
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14714
- if (orphanDiff) hasDiff = true;
14715
- }
14716
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14742
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14743
+ if (orphanCount > 0) hasDiff = true;
14717
14744
  }
14718
14745
  }
14719
14746
  }
@@ -14741,26 +14768,18 @@ async function generateIgnoreCore(params) {
14741
14768
  const rulesyncFiles = await processor.loadRulesyncFiles();
14742
14769
  if (rulesyncFiles.length > 0) {
14743
14770
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14744
- if (isPreviewMode) {
14745
- const fileDiff = await detectFileDiff(toolFiles);
14746
- if (fileDiff) hasDiff = true;
14747
- }
14748
14771
  const writtenCount = await processor.writeAiFiles(toolFiles);
14749
14772
  totalCount += writtenCount;
14773
+ if (writtenCount > 0) hasDiff = true;
14750
14774
  if (config.getDelete()) {
14751
14775
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14752
- if (isPreviewMode) {
14753
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14754
- if (orphanDiff) hasDiff = true;
14755
- }
14756
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14776
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14777
+ if (orphanCount > 0) hasDiff = true;
14757
14778
  }
14758
14779
  } else if (config.getDelete()) {
14759
14780
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14760
- if (isPreviewMode && existingToolFiles.length > 0) {
14761
- hasDiff = true;
14762
- }
14763
- await processor.removeOrphanAiFiles(existingToolFiles, []);
14781
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, []);
14782
+ if (orphanCount > 0) hasDiff = true;
14764
14783
  }
14765
14784
  } catch (error) {
14766
14785
  logger.warn(
@@ -14795,19 +14814,13 @@ async function generateMcpCore(params) {
14795
14814
  });
14796
14815
  const rulesyncFiles = await processor.loadRulesyncFiles();
14797
14816
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14798
- if (isPreviewMode) {
14799
- const fileDiff = await detectFileDiff(toolFiles);
14800
- if (fileDiff) hasDiff = true;
14801
- }
14802
14817
  const writtenCount = await processor.writeAiFiles(toolFiles);
14803
14818
  totalCount += writtenCount;
14819
+ if (writtenCount > 0) hasDiff = true;
14804
14820
  if (config.getDelete()) {
14805
14821
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14806
- if (isPreviewMode) {
14807
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14808
- if (orphanDiff) hasDiff = true;
14809
- }
14810
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14822
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14823
+ if (orphanCount > 0) hasDiff = true;
14811
14824
  }
14812
14825
  }
14813
14826
  }
@@ -14838,19 +14851,13 @@ async function generateCommandsCore(params) {
14838
14851
  });
14839
14852
  const rulesyncFiles = await processor.loadRulesyncFiles();
14840
14853
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14841
- if (isPreviewMode) {
14842
- const fileDiff = await detectFileDiff(toolFiles);
14843
- if (fileDiff) hasDiff = true;
14844
- }
14845
14854
  const writtenCount = await processor.writeAiFiles(toolFiles);
14846
14855
  totalCount += writtenCount;
14856
+ if (writtenCount > 0) hasDiff = true;
14847
14857
  if (config.getDelete()) {
14848
14858
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14849
- if (isPreviewMode) {
14850
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14851
- if (orphanDiff) hasDiff = true;
14852
- }
14853
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14859
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14860
+ if (orphanCount > 0) hasDiff = true;
14854
14861
  }
14855
14862
  }
14856
14863
  }
@@ -14881,19 +14888,13 @@ async function generateSubagentsCore(params) {
14881
14888
  });
14882
14889
  const rulesyncFiles = await processor.loadRulesyncFiles();
14883
14890
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14884
- if (isPreviewMode) {
14885
- const fileDiff = await detectFileDiff(toolFiles);
14886
- if (fileDiff) hasDiff = true;
14887
- }
14888
14891
  const writtenCount = await processor.writeAiFiles(toolFiles);
14889
14892
  totalCount += writtenCount;
14893
+ if (writtenCount > 0) hasDiff = true;
14890
14894
  if (config.getDelete()) {
14891
14895
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14892
- if (isPreviewMode) {
14893
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14894
- if (orphanDiff) hasDiff = true;
14895
- }
14896
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14896
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14897
+ if (orphanCount > 0) hasDiff = true;
14897
14898
  }
14898
14899
  }
14899
14900
  }
@@ -14930,19 +14931,13 @@ async function generateSkillsCore(params) {
14930
14931
  }
14931
14932
  }
14932
14933
  const toolDirs = await processor.convertRulesyncDirsToToolDirs(rulesyncDirs);
14933
- if (isPreviewMode) {
14934
- const dirDiff = await detectDirDiff(toolDirs);
14935
- if (dirDiff) hasDiff = true;
14936
- }
14937
14934
  const writtenCount = await processor.writeAiDirs(toolDirs);
14938
14935
  totalCount += writtenCount;
14936
+ if (writtenCount > 0) hasDiff = true;
14939
14937
  if (config.getDelete()) {
14940
14938
  const existingToolDirs = await processor.loadToolDirsToDelete();
14941
- if (isPreviewMode) {
14942
- const orphanDiff = await detectOrphanDirDiff(existingToolDirs, toolDirs);
14943
- if (orphanDiff) hasDiff = true;
14944
- }
14945
- await processor.removeOrphanAiDirs(existingToolDirs, toolDirs);
14939
+ const orphanCount = await processor.removeOrphanAiDirs(existingToolDirs, toolDirs);
14940
+ if (orphanCount > 0) hasDiff = true;
14946
14941
  }
14947
14942
  }
14948
14943
  }
@@ -14972,77 +14967,24 @@ async function generateHooksCore(params) {
14972
14967
  if (rulesyncFiles.length === 0) {
14973
14968
  if (config.getDelete()) {
14974
14969
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14975
- if (isPreviewMode && existingToolFiles.length > 0) {
14976
- hasDiff = true;
14977
- }
14978
- await processor.removeOrphanAiFiles(existingToolFiles, []);
14970
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, []);
14971
+ if (orphanCount > 0) hasDiff = true;
14979
14972
  }
14980
14973
  continue;
14981
14974
  }
14982
14975
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14983
- if (isPreviewMode) {
14984
- const fileDiff = await detectFileDiff(toolFiles);
14985
- if (fileDiff) hasDiff = true;
14986
- }
14987
14976
  const writtenCount = await processor.writeAiFiles(toolFiles);
14988
14977
  totalCount += writtenCount;
14978
+ if (writtenCount > 0) hasDiff = true;
14989
14979
  if (config.getDelete()) {
14990
14980
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14991
- if (isPreviewMode) {
14992
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14993
- if (orphanDiff) hasDiff = true;
14994
- }
14995
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14981
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14982
+ if (orphanCount > 0) hasDiff = true;
14996
14983
  }
14997
14984
  }
14998
14985
  }
14999
14986
  return { count: totalCount, hasDiff };
15000
14987
  }
15001
- async function detectFileDiff(aiFiles) {
15002
- for (const aiFile of aiFiles) {
15003
- const filePath = aiFile.getFilePath();
15004
- const newContent = addTrailingNewline(aiFile.getFileContent());
15005
- const existingContent = await readFileContentOrNull(filePath);
15006
- if (existingContent !== newContent) {
15007
- return true;
15008
- }
15009
- }
15010
- return false;
15011
- }
15012
- async function detectOrphanFileDiff(existingFiles, generatedFiles) {
15013
- const generatedPaths = new Set(generatedFiles.map((f) => f.getFilePath()));
15014
- const orphanFiles = existingFiles.filter((f) => !generatedPaths.has(f.getFilePath()));
15015
- return orphanFiles.length > 0;
15016
- }
15017
- async function detectDirDiff(aiDirs) {
15018
- for (const aiDir of aiDirs) {
15019
- const mainFile = aiDir.getMainFile();
15020
- if (mainFile) {
15021
- const mainFilePath = (0, import_node_path109.join)(aiDir.getDirPath(), mainFile.name);
15022
- const newContent = addTrailingNewline(
15023
- stringifyFrontmatter(mainFile.body, mainFile.frontmatter)
15024
- );
15025
- const existingContent = await readFileContentOrNull(mainFilePath);
15026
- if (existingContent !== newContent) {
15027
- return true;
15028
- }
15029
- }
15030
- for (const file of aiDir.getOtherFiles()) {
15031
- const filePath = (0, import_node_path109.join)(aiDir.getDirPath(), file.relativeFilePathToDirPath);
15032
- const newContent = addTrailingNewline(file.fileBuffer.toString("utf-8"));
15033
- const existingContent = await readFileContentOrNull(filePath);
15034
- if (existingContent !== newContent) {
15035
- return true;
15036
- }
15037
- }
15038
- }
15039
- return false;
15040
- }
15041
- async function detectOrphanDirDiff(existingDirs, generatedDirs) {
15042
- const generatedPaths = new Set(generatedDirs.map((d) => d.getDirPath()));
15043
- const orphanDirs = existingDirs.filter((d) => !generatedPaths.has(d.getDirPath()));
15044
- return orphanDirs.length > 0;
15045
- }
15046
14988
 
15047
14989
  // src/utils/result.ts
15048
14990
  function calculateTotalCount(result) {
@@ -17593,7 +17535,7 @@ async function updateCommand(currentVersion, options) {
17593
17535
  }
17594
17536
 
17595
17537
  // src/cli/index.ts
17596
- var getVersion = () => "6.6.2";
17538
+ var getVersion = () => "6.7.0";
17597
17539
  var main = async () => {
17598
17540
  const program = new import_commander.Command();
17599
17541
  const version = getVersion();
package/dist/index.js CHANGED
@@ -298,16 +298,22 @@ var FeatureProcessor = class {
298
298
  * Returns the number of files written.
299
299
  */
300
300
  async writeAiFiles(aiFiles) {
301
+ let changedCount = 0;
301
302
  for (const aiFile of aiFiles) {
302
303
  const filePath = aiFile.getFilePath();
304
+ const contentWithNewline = addTrailingNewline(aiFile.getFileContent());
305
+ const existingContent = await readFileContentOrNull(filePath);
306
+ if (existingContent === contentWithNewline) {
307
+ continue;
308
+ }
303
309
  if (this.dryRun) {
304
310
  logger.info(`[DRY RUN] Would write: ${filePath}`);
305
311
  } else {
306
- const contentWithNewline = addTrailingNewline(aiFile.getFileContent());
307
312
  await writeFileContent(filePath, contentWithNewline);
308
313
  }
314
+ changedCount++;
309
315
  }
310
- return aiFiles.length;
316
+ return changedCount;
311
317
  }
312
318
  async removeAiFiles(aiFiles) {
313
319
  for (const aiFile of aiFiles) {
@@ -329,6 +335,7 @@ var FeatureProcessor = class {
329
335
  await removeFile(filePath);
330
336
  }
331
337
  }
338
+ return orphanFiles.length;
332
339
  }
333
340
  };
334
341
 
@@ -6401,35 +6408,60 @@ var DirFeatureProcessor = class {
6401
6408
  * Returns the number of directories written.
6402
6409
  */
6403
6410
  async writeAiDirs(aiDirs) {
6411
+ let changedCount = 0;
6404
6412
  for (const aiDir of aiDirs) {
6405
6413
  const dirPath = aiDir.getDirPath();
6414
+ let dirHasChanges = false;
6415
+ const mainFile = aiDir.getMainFile();
6416
+ let mainFileContent;
6417
+ if (mainFile) {
6418
+ const mainFilePath = join55(dirPath, mainFile.name);
6419
+ const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter);
6420
+ mainFileContent = addTrailingNewline(content);
6421
+ const existingContent = await readFileContentOrNull(mainFilePath);
6422
+ if (existingContent !== mainFileContent) {
6423
+ dirHasChanges = true;
6424
+ }
6425
+ }
6426
+ const otherFiles = aiDir.getOtherFiles();
6427
+ const otherFileContents = [];
6428
+ for (const file of otherFiles) {
6429
+ const contentWithNewline = addTrailingNewline(file.fileBuffer.toString("utf-8"));
6430
+ otherFileContents.push(contentWithNewline);
6431
+ if (!dirHasChanges) {
6432
+ const filePath = join55(dirPath, file.relativeFilePathToDirPath);
6433
+ const existingContent = await readFileContentOrNull(filePath);
6434
+ if (existingContent !== contentWithNewline) {
6435
+ dirHasChanges = true;
6436
+ }
6437
+ }
6438
+ }
6439
+ if (!dirHasChanges) {
6440
+ continue;
6441
+ }
6406
6442
  if (this.dryRun) {
6407
6443
  logger.info(`[DRY RUN] Would create directory: ${dirPath}`);
6408
- const mainFile = aiDir.getMainFile();
6409
6444
  if (mainFile) {
6410
6445
  logger.info(`[DRY RUN] Would write: ${join55(dirPath, mainFile.name)}`);
6411
6446
  }
6412
- for (const file of aiDir.getOtherFiles()) {
6447
+ for (const file of otherFiles) {
6413
6448
  logger.info(`[DRY RUN] Would write: ${join55(dirPath, file.relativeFilePathToDirPath)}`);
6414
6449
  }
6415
6450
  } else {
6416
6451
  await ensureDir(dirPath);
6417
- const mainFile = aiDir.getMainFile();
6418
- if (mainFile) {
6452
+ if (mainFile && mainFileContent) {
6419
6453
  const mainFilePath = join55(dirPath, mainFile.name);
6420
- const content = stringifyFrontmatter(mainFile.body, mainFile.frontmatter);
6421
- const contentWithNewline = addTrailingNewline(content);
6422
- await writeFileContent(mainFilePath, contentWithNewline);
6454
+ await writeFileContent(mainFilePath, mainFileContent);
6423
6455
  }
6424
- const otherFiles = aiDir.getOtherFiles();
6425
- for (const file of otherFiles) {
6456
+ for (const [i, file] of otherFiles.entries()) {
6426
6457
  const filePath = join55(dirPath, file.relativeFilePathToDirPath);
6427
- const contentWithNewline = addTrailingNewline(file.fileBuffer.toString("utf-8"));
6428
- await writeFileContent(filePath, contentWithNewline);
6458
+ const content = otherFileContents[i] ?? "";
6459
+ await writeFileContent(filePath, content);
6429
6460
  }
6430
6461
  }
6462
+ changedCount++;
6431
6463
  }
6432
- return aiDirs.length;
6464
+ return changedCount;
6433
6465
  }
6434
6466
  async removeAiDirs(aiDirs) {
6435
6467
  for (const aiDir of aiDirs) {
@@ -6451,6 +6483,7 @@ var DirFeatureProcessor = class {
6451
6483
  await removeDirectory(dirPath);
6452
6484
  }
6453
6485
  }
6486
+ return orphanDirs.length;
6454
6487
  }
6455
6488
  };
6456
6489
 
@@ -14678,19 +14711,13 @@ async function generateRulesCore(params) {
14678
14711
  });
14679
14712
  const rulesyncFiles = await processor.loadRulesyncFiles();
14680
14713
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14681
- if (isPreviewMode) {
14682
- const fileDiff = await detectFileDiff(toolFiles);
14683
- if (fileDiff) hasDiff = true;
14684
- }
14685
14714
  const writtenCount = await processor.writeAiFiles(toolFiles);
14686
14715
  totalCount += writtenCount;
14716
+ if (writtenCount > 0) hasDiff = true;
14687
14717
  if (config.getDelete()) {
14688
14718
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14689
- if (isPreviewMode) {
14690
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14691
- if (orphanDiff) hasDiff = true;
14692
- }
14693
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14719
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14720
+ if (orphanCount > 0) hasDiff = true;
14694
14721
  }
14695
14722
  }
14696
14723
  }
@@ -14718,26 +14745,18 @@ async function generateIgnoreCore(params) {
14718
14745
  const rulesyncFiles = await processor.loadRulesyncFiles();
14719
14746
  if (rulesyncFiles.length > 0) {
14720
14747
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14721
- if (isPreviewMode) {
14722
- const fileDiff = await detectFileDiff(toolFiles);
14723
- if (fileDiff) hasDiff = true;
14724
- }
14725
14748
  const writtenCount = await processor.writeAiFiles(toolFiles);
14726
14749
  totalCount += writtenCount;
14750
+ if (writtenCount > 0) hasDiff = true;
14727
14751
  if (config.getDelete()) {
14728
14752
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14729
- if (isPreviewMode) {
14730
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14731
- if (orphanDiff) hasDiff = true;
14732
- }
14733
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14753
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14754
+ if (orphanCount > 0) hasDiff = true;
14734
14755
  }
14735
14756
  } else if (config.getDelete()) {
14736
14757
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14737
- if (isPreviewMode && existingToolFiles.length > 0) {
14738
- hasDiff = true;
14739
- }
14740
- await processor.removeOrphanAiFiles(existingToolFiles, []);
14758
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, []);
14759
+ if (orphanCount > 0) hasDiff = true;
14741
14760
  }
14742
14761
  } catch (error) {
14743
14762
  logger.warn(
@@ -14772,19 +14791,13 @@ async function generateMcpCore(params) {
14772
14791
  });
14773
14792
  const rulesyncFiles = await processor.loadRulesyncFiles();
14774
14793
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14775
- if (isPreviewMode) {
14776
- const fileDiff = await detectFileDiff(toolFiles);
14777
- if (fileDiff) hasDiff = true;
14778
- }
14779
14794
  const writtenCount = await processor.writeAiFiles(toolFiles);
14780
14795
  totalCount += writtenCount;
14796
+ if (writtenCount > 0) hasDiff = true;
14781
14797
  if (config.getDelete()) {
14782
14798
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14783
- if (isPreviewMode) {
14784
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14785
- if (orphanDiff) hasDiff = true;
14786
- }
14787
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14799
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14800
+ if (orphanCount > 0) hasDiff = true;
14788
14801
  }
14789
14802
  }
14790
14803
  }
@@ -14815,19 +14828,13 @@ async function generateCommandsCore(params) {
14815
14828
  });
14816
14829
  const rulesyncFiles = await processor.loadRulesyncFiles();
14817
14830
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14818
- if (isPreviewMode) {
14819
- const fileDiff = await detectFileDiff(toolFiles);
14820
- if (fileDiff) hasDiff = true;
14821
- }
14822
14831
  const writtenCount = await processor.writeAiFiles(toolFiles);
14823
14832
  totalCount += writtenCount;
14833
+ if (writtenCount > 0) hasDiff = true;
14824
14834
  if (config.getDelete()) {
14825
14835
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14826
- if (isPreviewMode) {
14827
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14828
- if (orphanDiff) hasDiff = true;
14829
- }
14830
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14836
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14837
+ if (orphanCount > 0) hasDiff = true;
14831
14838
  }
14832
14839
  }
14833
14840
  }
@@ -14858,19 +14865,13 @@ async function generateSubagentsCore(params) {
14858
14865
  });
14859
14866
  const rulesyncFiles = await processor.loadRulesyncFiles();
14860
14867
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14861
- if (isPreviewMode) {
14862
- const fileDiff = await detectFileDiff(toolFiles);
14863
- if (fileDiff) hasDiff = true;
14864
- }
14865
14868
  const writtenCount = await processor.writeAiFiles(toolFiles);
14866
14869
  totalCount += writtenCount;
14870
+ if (writtenCount > 0) hasDiff = true;
14867
14871
  if (config.getDelete()) {
14868
14872
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14869
- if (isPreviewMode) {
14870
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14871
- if (orphanDiff) hasDiff = true;
14872
- }
14873
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14873
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14874
+ if (orphanCount > 0) hasDiff = true;
14874
14875
  }
14875
14876
  }
14876
14877
  }
@@ -14907,19 +14908,13 @@ async function generateSkillsCore(params) {
14907
14908
  }
14908
14909
  }
14909
14910
  const toolDirs = await processor.convertRulesyncDirsToToolDirs(rulesyncDirs);
14910
- if (isPreviewMode) {
14911
- const dirDiff = await detectDirDiff(toolDirs);
14912
- if (dirDiff) hasDiff = true;
14913
- }
14914
14911
  const writtenCount = await processor.writeAiDirs(toolDirs);
14915
14912
  totalCount += writtenCount;
14913
+ if (writtenCount > 0) hasDiff = true;
14916
14914
  if (config.getDelete()) {
14917
14915
  const existingToolDirs = await processor.loadToolDirsToDelete();
14918
- if (isPreviewMode) {
14919
- const orphanDiff = await detectOrphanDirDiff(existingToolDirs, toolDirs);
14920
- if (orphanDiff) hasDiff = true;
14921
- }
14922
- await processor.removeOrphanAiDirs(existingToolDirs, toolDirs);
14916
+ const orphanCount = await processor.removeOrphanAiDirs(existingToolDirs, toolDirs);
14917
+ if (orphanCount > 0) hasDiff = true;
14923
14918
  }
14924
14919
  }
14925
14920
  }
@@ -14949,77 +14944,24 @@ async function generateHooksCore(params) {
14949
14944
  if (rulesyncFiles.length === 0) {
14950
14945
  if (config.getDelete()) {
14951
14946
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14952
- if (isPreviewMode && existingToolFiles.length > 0) {
14953
- hasDiff = true;
14954
- }
14955
- await processor.removeOrphanAiFiles(existingToolFiles, []);
14947
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, []);
14948
+ if (orphanCount > 0) hasDiff = true;
14956
14949
  }
14957
14950
  continue;
14958
14951
  }
14959
14952
  const toolFiles = await processor.convertRulesyncFilesToToolFiles(rulesyncFiles);
14960
- if (isPreviewMode) {
14961
- const fileDiff = await detectFileDiff(toolFiles);
14962
- if (fileDiff) hasDiff = true;
14963
- }
14964
14953
  const writtenCount = await processor.writeAiFiles(toolFiles);
14965
14954
  totalCount += writtenCount;
14955
+ if (writtenCount > 0) hasDiff = true;
14966
14956
  if (config.getDelete()) {
14967
14957
  const existingToolFiles = await processor.loadToolFiles({ forDeletion: true });
14968
- if (isPreviewMode) {
14969
- const orphanDiff = await detectOrphanFileDiff(existingToolFiles, toolFiles);
14970
- if (orphanDiff) hasDiff = true;
14971
- }
14972
- await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14958
+ const orphanCount = await processor.removeOrphanAiFiles(existingToolFiles, toolFiles);
14959
+ if (orphanCount > 0) hasDiff = true;
14973
14960
  }
14974
14961
  }
14975
14962
  }
14976
14963
  return { count: totalCount, hasDiff };
14977
14964
  }
14978
- async function detectFileDiff(aiFiles) {
14979
- for (const aiFile of aiFiles) {
14980
- const filePath = aiFile.getFilePath();
14981
- const newContent = addTrailingNewline(aiFile.getFileContent());
14982
- const existingContent = await readFileContentOrNull(filePath);
14983
- if (existingContent !== newContent) {
14984
- return true;
14985
- }
14986
- }
14987
- return false;
14988
- }
14989
- async function detectOrphanFileDiff(existingFiles, generatedFiles) {
14990
- const generatedPaths = new Set(generatedFiles.map((f) => f.getFilePath()));
14991
- const orphanFiles = existingFiles.filter((f) => !generatedPaths.has(f.getFilePath()));
14992
- return orphanFiles.length > 0;
14993
- }
14994
- async function detectDirDiff(aiDirs) {
14995
- for (const aiDir of aiDirs) {
14996
- const mainFile = aiDir.getMainFile();
14997
- if (mainFile) {
14998
- const mainFilePath = join108(aiDir.getDirPath(), mainFile.name);
14999
- const newContent = addTrailingNewline(
15000
- stringifyFrontmatter(mainFile.body, mainFile.frontmatter)
15001
- );
15002
- const existingContent = await readFileContentOrNull(mainFilePath);
15003
- if (existingContent !== newContent) {
15004
- return true;
15005
- }
15006
- }
15007
- for (const file of aiDir.getOtherFiles()) {
15008
- const filePath = join108(aiDir.getDirPath(), file.relativeFilePathToDirPath);
15009
- const newContent = addTrailingNewline(file.fileBuffer.toString("utf-8"));
15010
- const existingContent = await readFileContentOrNull(filePath);
15011
- if (existingContent !== newContent) {
15012
- return true;
15013
- }
15014
- }
15015
- }
15016
- return false;
15017
- }
15018
- async function detectOrphanDirDiff(existingDirs, generatedDirs) {
15019
- const generatedPaths = new Set(generatedDirs.map((d) => d.getDirPath()));
15020
- const orphanDirs = existingDirs.filter((d) => !generatedPaths.has(d.getDirPath()));
15021
- return orphanDirs.length > 0;
15022
- }
15023
14965
 
15024
14966
  // src/utils/result.ts
15025
14967
  function calculateTotalCount(result) {
@@ -17570,7 +17512,7 @@ async function updateCommand(currentVersion, options) {
17570
17512
  }
17571
17513
 
17572
17514
  // src/cli/index.ts
17573
- var getVersion = () => "6.6.2";
17515
+ var getVersion = () => "6.7.0";
17574
17516
  var main = async () => {
17575
17517
  const program = new Command();
17576
17518
  const version = getVersion();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "6.6.2",
3
+ "version": "6.7.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",
@@ -36,16 +36,16 @@
36
36
  "pre-commit": "pnpm exec lint-staged"
37
37
  },
38
38
  "dependencies": {
39
- "@modelcontextprotocol/sdk": "1.25.3",
39
+ "@modelcontextprotocol/sdk": "1.26.0",
40
40
  "@octokit/request-error": "7.1.0",
41
41
  "@octokit/rest": "22.0.1",
42
42
  "@toon-format/toon": "2.1.0",
43
43
  "@valibot/to-json-schema": "1.5.0",
44
- "commander": "14.0.2",
44
+ "commander": "14.0.3",
45
45
  "consola": "3.4.2",
46
- "effect": "3.19.15",
46
+ "effect": "3.19.16",
47
47
  "es-toolkit": "1.44.0",
48
- "fastmcp": "3.30.1",
48
+ "fastmcp": "3.31.0",
49
49
  "globby": "16.1.0",
50
50
  "gray-matter": "4.0.3",
51
51
  "js-yaml": "4.1.1",
@@ -55,26 +55,26 @@
55
55
  "zod": "4.3.6"
56
56
  },
57
57
  "devDependencies": {
58
- "@anthropic-ai/claude-agent-sdk": "0.2.23",
58
+ "@anthropic-ai/claude-agent-sdk": "0.2.31",
59
59
  "@eslint/js": "9.39.2",
60
60
  "@secretlint/secretlint-rule-preset-recommend": "11.3.1",
61
61
  "@tsconfig/node24": "24.0.4",
62
62
  "@types/js-yaml": "4.0.9",
63
- "@types/node": "25.1.0",
64
- "@typescript/native-preview": "7.0.0-dev.20260128.1",
63
+ "@types/node": "25.2.0",
64
+ "@typescript/native-preview": "7.0.0-dev.20260204.1",
65
65
  "@vitest/coverage-v8": "4.0.18",
66
- "cspell": "9.6.2",
66
+ "cspell": "9.6.4",
67
67
  "eslint": "9.39.2",
68
68
  "eslint-plugin-import": "2.32.0",
69
69
  "eslint-plugin-no-type-assertion": "1.3.0",
70
- "eslint-plugin-oxlint": "1.42.0",
70
+ "eslint-plugin-oxlint": "1.43.0",
71
71
  "eslint-plugin-strict-dependencies": "1.3.30",
72
72
  "eslint-plugin-zod-import": "0.3.0",
73
- "knip": "5.82.1",
73
+ "knip": "5.83.0",
74
74
  "lint-staged": "16.2.7",
75
75
  "marked": "17.0.1",
76
- "oxfmt": "0.27.0",
77
- "oxlint": "1.42.0",
76
+ "oxfmt": "0.28.0",
77
+ "oxlint": "1.43.0",
78
78
  "repomix": "1.11.1",
79
79
  "secretlint": "11.3.1",
80
80
  "simple-git-hooks": "2.13.1",