rulesync 0.61.0 → 0.63.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/README.md +32 -9
- package/dist/{chunk-C5LFJFPS.js → chunk-2CW2KFB3.js} +1 -1
- package/dist/{chunk-DA3XULAD.js → chunk-4PSTOKKD.js} +1 -1
- package/dist/{chunk-2KYIOT5S.js → chunk-GQTMTBX4.js} +2 -1
- package/dist/{chunk-U63N3YDS.js → chunk-M7NL7G7A.js} +1 -1
- package/dist/{chunk-LRYVNLH5.js → chunk-MDYDKNXQ.js} +1 -1
- package/dist/{chunk-ICMPPX55.js → chunk-NETSYSMD.js} +1 -1
- package/dist/{chunk-3ZLMXJTX.js → chunk-U4PLVMCG.js} +1 -1
- package/dist/{chunk-74TYZWHJ.js → chunk-UEAYL4NT.js} +1 -1
- package/dist/{claudecode-XKHMZT7R.js → claudecode-YTEFACCT.js} +2 -2
- package/dist/{cline-FNWPJ7K4.js → cline-CKNUDEA3.js} +2 -2
- package/dist/{codexcli-FDFHY66P.js → codexcli-7SDGYI7D.js} +2 -2
- package/dist/{cursor-WWHUW5AD.js → cursor-YJGH7W24.js} +2 -2
- package/dist/{geminicli-7TIDQ62D.js → geminicli-E7KZTZ2G.js} +2 -2
- package/dist/index.cjs +533 -416
- package/dist/index.js +523 -408
- package/dist/{junie-VMNDWBNB.js → junie-5LEQU4BO.js} +2 -2
- package/dist/{windsurf-KOSK4MZJ.js → windsurf-4P6HEUBV.js} +2 -2
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -35,11 +35,11 @@ function isToolTarget(target) {
|
|
|
35
35
|
if (!target) return false;
|
|
36
36
|
return ALL_TOOL_TARGETS.some((validTarget) => validTarget === target);
|
|
37
37
|
}
|
|
38
|
-
var
|
|
38
|
+
var import_mini2, ALL_TOOL_TARGETS, ToolTargetSchema, ToolTargetsSchema, WildcardTargetSchema, RulesyncTargetsSchema;
|
|
39
39
|
var init_tool_targets = __esm({
|
|
40
40
|
"src/types/tool-targets.ts"() {
|
|
41
41
|
"use strict";
|
|
42
|
-
|
|
42
|
+
import_mini2 = require("zod/mini");
|
|
43
43
|
ALL_TOOL_TARGETS = [
|
|
44
44
|
"augmentcode",
|
|
45
45
|
"augmentcode-legacy",
|
|
@@ -54,10 +54,10 @@ var init_tool_targets = __esm({
|
|
|
54
54
|
"junie",
|
|
55
55
|
"windsurf"
|
|
56
56
|
];
|
|
57
|
-
ToolTargetSchema =
|
|
58
|
-
ToolTargetsSchema =
|
|
59
|
-
WildcardTargetSchema =
|
|
60
|
-
RulesyncTargetsSchema =
|
|
57
|
+
ToolTargetSchema = import_mini2.z.enum(ALL_TOOL_TARGETS);
|
|
58
|
+
ToolTargetsSchema = import_mini2.z.array(ToolTargetSchema);
|
|
59
|
+
WildcardTargetSchema = import_mini2.z.tuple([import_mini2.z.literal("*")]);
|
|
60
|
+
RulesyncTargetsSchema = import_mini2.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
61
61
|
}
|
|
62
62
|
});
|
|
63
63
|
|
|
@@ -257,7 +257,8 @@ function generateMcpConfigurationFilesFromRegistry(tool, mcpServers, baseDir = "
|
|
|
257
257
|
return generateMcpConfigurationFiles(mcpServers, generatorConfig, baseDir);
|
|
258
258
|
}
|
|
259
259
|
function generateJunieMcpConfigurationFiles(mcpServers, baseDir = "") {
|
|
260
|
-
const
|
|
260
|
+
const junieMcpPath = ".junie/mcp/mcp.json";
|
|
261
|
+
const filepath = baseDir ? `${baseDir}/${junieMcpPath}` : junieMcpPath;
|
|
261
262
|
const config = {
|
|
262
263
|
mcpServers: {}
|
|
263
264
|
};
|
|
@@ -1055,94 +1056,36 @@ var import_commander = require("commander");
|
|
|
1055
1056
|
var import_promises = require("fs/promises");
|
|
1056
1057
|
var path = __toESM(require("path"), 1);
|
|
1057
1058
|
|
|
1058
|
-
// src/utils/config.ts
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
return {
|
|
1062
|
-
aiRulesDir: ".rulesync",
|
|
1063
|
-
outputPaths: {
|
|
1064
|
-
augmentcode: ".",
|
|
1065
|
-
"augmentcode-legacy": ".",
|
|
1066
|
-
copilot: ".github/instructions",
|
|
1067
|
-
cursor: ".cursor/rules",
|
|
1068
|
-
cline: ".clinerules",
|
|
1069
|
-
claudecode: ".",
|
|
1070
|
-
codexcli: ".",
|
|
1071
|
-
roo: ".roo/rules",
|
|
1072
|
-
geminicli: ".gemini/memories",
|
|
1073
|
-
kiro: ".kiro/steering",
|
|
1074
|
-
junie: ".",
|
|
1075
|
-
windsurf: "."
|
|
1076
|
-
},
|
|
1077
|
-
watchEnabled: false,
|
|
1078
|
-
defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy")
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
function resolveTargets(targets, config) {
|
|
1082
|
-
if (targets.length === 1 && targets[0] === "*") {
|
|
1083
|
-
return config.defaultTargets;
|
|
1084
|
-
}
|
|
1085
|
-
const validatedTargets = ToolTargetsSchema.parse(targets);
|
|
1086
|
-
return validatedTargets;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// src/cli/commands/add.ts
|
|
1090
|
-
function sanitizeFilename(filename) {
|
|
1091
|
-
return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
|
|
1092
|
-
}
|
|
1093
|
-
function generateRuleTemplate(filename) {
|
|
1094
|
-
return `---
|
|
1095
|
-
root: false
|
|
1096
|
-
targets: ["*"]
|
|
1097
|
-
description: "Rules for ${filename}"
|
|
1098
|
-
globs: []
|
|
1099
|
-
---
|
|
1100
|
-
|
|
1101
|
-
# ${filename.charAt(0).toUpperCase() + filename.slice(1)} Rules
|
|
1102
|
-
|
|
1103
|
-
Add your rules here.
|
|
1104
|
-
`;
|
|
1105
|
-
}
|
|
1106
|
-
async function addCommand(filename) {
|
|
1107
|
-
try {
|
|
1108
|
-
const config = getDefaultConfig();
|
|
1109
|
-
const sanitizedFilename = sanitizeFilename(filename);
|
|
1110
|
-
const rulesDir = config.aiRulesDir;
|
|
1111
|
-
const filePath = path.join(rulesDir, `${sanitizedFilename}.md`);
|
|
1112
|
-
await (0, import_promises.mkdir)(rulesDir, { recursive: true });
|
|
1113
|
-
const template = generateRuleTemplate(sanitizedFilename);
|
|
1114
|
-
await (0, import_promises.writeFile)(filePath, template, "utf8");
|
|
1115
|
-
console.log(`\u2705 Created rule file: ${filePath}`);
|
|
1116
|
-
console.log(`\u{1F4DD} Edit the file to customize your rules.`);
|
|
1117
|
-
} catch (error) {
|
|
1118
|
-
console.error(
|
|
1119
|
-
`\u274C Failed to create rule file: ${error instanceof Error ? error.message : String(error)}`
|
|
1120
|
-
);
|
|
1121
|
-
process.exit(3);
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
// src/cli/commands/config.ts
|
|
1126
|
-
var import_node_fs = require("fs");
|
|
1127
|
-
var import_node_path2 = __toESM(require("path"), 1);
|
|
1059
|
+
// src/utils/config-loader.ts
|
|
1060
|
+
var import_c12 = require("c12");
|
|
1061
|
+
var import_core = require("zod/v4/core");
|
|
1128
1062
|
|
|
1129
1063
|
// src/types/claudecode.ts
|
|
1130
|
-
var
|
|
1131
|
-
var ClaudeSettingsSchema =
|
|
1132
|
-
permissions:
|
|
1133
|
-
|
|
1134
|
-
deny:
|
|
1064
|
+
var import_mini = require("zod/mini");
|
|
1065
|
+
var ClaudeSettingsSchema = import_mini.z.looseObject({
|
|
1066
|
+
permissions: import_mini.z._default(
|
|
1067
|
+
import_mini.z.looseObject({
|
|
1068
|
+
deny: import_mini.z._default(import_mini.z.array(import_mini.z.string()), [])
|
|
1135
1069
|
}),
|
|
1136
1070
|
{ deny: [] }
|
|
1137
1071
|
)
|
|
1138
1072
|
});
|
|
1139
1073
|
|
|
1140
|
-
// src/types/
|
|
1074
|
+
// src/types/shared.ts
|
|
1141
1075
|
var import_mini3 = require("zod/mini");
|
|
1142
|
-
|
|
1076
|
+
init_tool_targets();
|
|
1077
|
+
var OutputSchema = import_mini3.z.object({
|
|
1078
|
+
tool: ToolTargetSchema,
|
|
1079
|
+
filepath: import_mini3.z.string(),
|
|
1080
|
+
content: import_mini3.z.string()
|
|
1081
|
+
});
|
|
1082
|
+
var BaseFrontmatterSchema = import_mini3.z.object({
|
|
1143
1083
|
description: import_mini3.z.optional(import_mini3.z.string())
|
|
1144
1084
|
});
|
|
1145
1085
|
|
|
1086
|
+
// src/types/commands.ts
|
|
1087
|
+
var CommandFrontmatterSchema = BaseFrontmatterSchema;
|
|
1088
|
+
|
|
1146
1089
|
// src/types/config.ts
|
|
1147
1090
|
var import_mini4 = require("zod/mini");
|
|
1148
1091
|
init_tool_targets();
|
|
@@ -1152,7 +1095,8 @@ var ConfigSchema = import_mini4.z.object({
|
|
|
1152
1095
|
watchEnabled: import_mini4.z.boolean(),
|
|
1153
1096
|
defaultTargets: ToolTargetsSchema,
|
|
1154
1097
|
claudecodeCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
1155
|
-
geminicliCommands: import_mini4.z.optional(import_mini4.z.string())
|
|
1098
|
+
geminicliCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
1099
|
+
legacy: import_mini4.z.optional(import_mini4.z.boolean())
|
|
1156
1100
|
});
|
|
1157
1101
|
|
|
1158
1102
|
// src/types/config-options.ts
|
|
@@ -1182,6 +1126,7 @@ var ConfigOptionsSchema = import_mini5.z.object({
|
|
|
1182
1126
|
verbose: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1183
1127
|
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1184
1128
|
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
1129
|
+
legacy: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1185
1130
|
watch: import_mini5.z.optional(
|
|
1186
1131
|
import_mini5.z.object({
|
|
1187
1132
|
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
@@ -1201,6 +1146,7 @@ var MergedConfigSchema = import_mini5.z.object({
|
|
|
1201
1146
|
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1202
1147
|
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
1203
1148
|
configPath: import_mini5.z.optional(import_mini5.z.string()),
|
|
1149
|
+
legacy: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1204
1150
|
watch: import_mini5.z.optional(
|
|
1205
1151
|
import_mini5.z.object({
|
|
1206
1152
|
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
@@ -1256,11 +1202,6 @@ var RuleFrontmatterSchema = import_mini7.z.object({
|
|
|
1256
1202
|
windsurfOutputFormat: import_mini7.z.optional(import_mini7.z.enum(["single-file", "directory"])),
|
|
1257
1203
|
tags: import_mini7.z.optional(import_mini7.z.array(import_mini7.z.string()))
|
|
1258
1204
|
});
|
|
1259
|
-
var GeneratedOutputSchema = import_mini7.z.object({
|
|
1260
|
-
tool: ToolTargetSchema,
|
|
1261
|
-
filepath: import_mini7.z.string(),
|
|
1262
|
-
content: import_mini7.z.string()
|
|
1263
|
-
});
|
|
1264
1205
|
var GenerateOptionsSchema = import_mini7.z.object({
|
|
1265
1206
|
targetTools: import_mini7.z.optional(ToolTargetsSchema),
|
|
1266
1207
|
outputDir: import_mini7.z.optional(import_mini7.z.string()),
|
|
@@ -1270,9 +1211,39 @@ var GenerateOptionsSchema = import_mini7.z.object({
|
|
|
1270
1211
|
// src/types/index.ts
|
|
1271
1212
|
init_tool_targets();
|
|
1272
1213
|
|
|
1214
|
+
// src/utils/config.ts
|
|
1215
|
+
init_tool_targets();
|
|
1216
|
+
function getDefaultConfig() {
|
|
1217
|
+
return {
|
|
1218
|
+
aiRulesDir: ".rulesync",
|
|
1219
|
+
outputPaths: {
|
|
1220
|
+
augmentcode: ".",
|
|
1221
|
+
"augmentcode-legacy": ".",
|
|
1222
|
+
copilot: ".github/instructions",
|
|
1223
|
+
cursor: ".cursor/rules",
|
|
1224
|
+
cline: ".clinerules",
|
|
1225
|
+
claudecode: ".",
|
|
1226
|
+
codexcli: ".",
|
|
1227
|
+
roo: ".roo/rules",
|
|
1228
|
+
geminicli: ".gemini/memories",
|
|
1229
|
+
kiro: ".kiro/steering",
|
|
1230
|
+
junie: ".",
|
|
1231
|
+
windsurf: "."
|
|
1232
|
+
},
|
|
1233
|
+
watchEnabled: false,
|
|
1234
|
+
defaultTargets: ALL_TOOL_TARGETS.filter((tool) => tool !== "augmentcode-legacy"),
|
|
1235
|
+
legacy: false
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
function resolveTargets(targets, config) {
|
|
1239
|
+
if (targets.length === 1 && targets[0] === "*") {
|
|
1240
|
+
return config.defaultTargets;
|
|
1241
|
+
}
|
|
1242
|
+
const validatedTargets = ToolTargetsSchema.parse(targets);
|
|
1243
|
+
return validatedTargets;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1273
1246
|
// src/utils/config-loader.ts
|
|
1274
|
-
var import_c12 = require("c12");
|
|
1275
|
-
var import_core = require("zod/v4/core");
|
|
1276
1247
|
var MODULE_NAME = "rulesync";
|
|
1277
1248
|
async function loadConfig(options = {}) {
|
|
1278
1249
|
const defaultConfig = getDefaultConfig();
|
|
@@ -1459,6 +1430,93 @@ function mergeWithCliOptions(config, cliOptions) {
|
|
|
1459
1430
|
return merged;
|
|
1460
1431
|
}
|
|
1461
1432
|
|
|
1433
|
+
// src/utils/logger.ts
|
|
1434
|
+
var import_consola = require("consola");
|
|
1435
|
+
var Logger = class {
|
|
1436
|
+
_verbose = false;
|
|
1437
|
+
console = import_consola.consola.withDefaults({
|
|
1438
|
+
tag: "rulesync"
|
|
1439
|
+
});
|
|
1440
|
+
setVerbose(verbose) {
|
|
1441
|
+
this._verbose = verbose;
|
|
1442
|
+
}
|
|
1443
|
+
get verbose() {
|
|
1444
|
+
return this._verbose;
|
|
1445
|
+
}
|
|
1446
|
+
// Regular log (always shown, regardless of verbose)
|
|
1447
|
+
log(message, ...args) {
|
|
1448
|
+
this.console.log(message, ...args);
|
|
1449
|
+
}
|
|
1450
|
+
// Info level (shown only in verbose mode)
|
|
1451
|
+
info(message, ...args) {
|
|
1452
|
+
if (this._verbose) {
|
|
1453
|
+
this.console.info(message, ...args);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
// Success (always shown)
|
|
1457
|
+
success(message, ...args) {
|
|
1458
|
+
this.console.success(message, ...args);
|
|
1459
|
+
}
|
|
1460
|
+
// Warning (always shown)
|
|
1461
|
+
warn(message, ...args) {
|
|
1462
|
+
this.console.warn(message, ...args);
|
|
1463
|
+
}
|
|
1464
|
+
// Error (always shown)
|
|
1465
|
+
error(message, ...args) {
|
|
1466
|
+
this.console.error(message, ...args);
|
|
1467
|
+
}
|
|
1468
|
+
// Debug level (shown only in verbose mode)
|
|
1469
|
+
debug(message, ...args) {
|
|
1470
|
+
if (this._verbose) {
|
|
1471
|
+
this.console.debug(message, ...args);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
var logger = new Logger();
|
|
1476
|
+
|
|
1477
|
+
// src/cli/commands/add.ts
|
|
1478
|
+
function sanitizeFilename(filename) {
|
|
1479
|
+
return filename.endsWith(".md") ? filename.slice(0, -3) : filename;
|
|
1480
|
+
}
|
|
1481
|
+
function generateRuleTemplate(filename) {
|
|
1482
|
+
return `---
|
|
1483
|
+
root: false
|
|
1484
|
+
targets: ["*"]
|
|
1485
|
+
description: "Rules for ${filename}"
|
|
1486
|
+
globs: []
|
|
1487
|
+
---
|
|
1488
|
+
|
|
1489
|
+
# ${filename.charAt(0).toUpperCase() + filename.slice(1)} Rules
|
|
1490
|
+
|
|
1491
|
+
Add your rules here.
|
|
1492
|
+
`;
|
|
1493
|
+
}
|
|
1494
|
+
async function addCommand(filename, options = {}) {
|
|
1495
|
+
try {
|
|
1496
|
+
const configResult = await loadConfig();
|
|
1497
|
+
const config = configResult.config;
|
|
1498
|
+
const sanitizedFilename = sanitizeFilename(filename);
|
|
1499
|
+
const aiRulesDir = config.aiRulesDir;
|
|
1500
|
+
const useLegacy = options.legacy ?? config.legacy ?? false;
|
|
1501
|
+
const rulesDir = useLegacy ? aiRulesDir : path.join(aiRulesDir, "rules");
|
|
1502
|
+
const filePath = path.join(rulesDir, `${sanitizedFilename}.md`);
|
|
1503
|
+
await (0, import_promises.mkdir)(rulesDir, { recursive: true });
|
|
1504
|
+
const template = generateRuleTemplate(sanitizedFilename);
|
|
1505
|
+
await (0, import_promises.writeFile)(filePath, template, "utf8");
|
|
1506
|
+
logger.success(`Created rule file: ${filePath}`);
|
|
1507
|
+
logger.log(`\u{1F4DD} Edit the file to customize your rules.`);
|
|
1508
|
+
} catch (error) {
|
|
1509
|
+
logger.error(
|
|
1510
|
+
`Failed to create rule file: ${error instanceof Error ? error.message : String(error)}`
|
|
1511
|
+
);
|
|
1512
|
+
process.exit(3);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// src/cli/commands/config.ts
|
|
1517
|
+
var import_node_fs = require("fs");
|
|
1518
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
1519
|
+
|
|
1462
1520
|
// src/utils/error.ts
|
|
1463
1521
|
function getErrorMessage(error) {
|
|
1464
1522
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -1525,10 +1583,23 @@ async function findFiles(dir, extension = ".md") {
|
|
|
1525
1583
|
return [];
|
|
1526
1584
|
}
|
|
1527
1585
|
}
|
|
1586
|
+
async function findRuleFiles(aiRulesDir) {
|
|
1587
|
+
const rulesDir = (0, import_node_path.join)(aiRulesDir, "rules");
|
|
1588
|
+
const newLocationFiles = await findFiles(rulesDir, ".md");
|
|
1589
|
+
const legacyLocationFiles = await findFiles(aiRulesDir, ".md");
|
|
1590
|
+
const newLocationBasenames = new Set(
|
|
1591
|
+
newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
|
|
1592
|
+
);
|
|
1593
|
+
const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
|
|
1594
|
+
const basename6 = file.split("/").pop()?.replace(/\.md$/, "");
|
|
1595
|
+
return !newLocationBasenames.has(basename6);
|
|
1596
|
+
});
|
|
1597
|
+
return [...newLocationFiles, ...filteredLegacyFiles];
|
|
1598
|
+
}
|
|
1528
1599
|
async function removeDirectory(dirPath) {
|
|
1529
1600
|
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
1530
1601
|
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
1531
|
-
|
|
1602
|
+
logger.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
1532
1603
|
return;
|
|
1533
1604
|
}
|
|
1534
1605
|
try {
|
|
@@ -1536,7 +1607,7 @@ async function removeDirectory(dirPath) {
|
|
|
1536
1607
|
await (0, import_promises2.rm)(dirPath, { recursive: true, force: true });
|
|
1537
1608
|
}
|
|
1538
1609
|
} catch (error) {
|
|
1539
|
-
|
|
1610
|
+
logger.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
1540
1611
|
}
|
|
1541
1612
|
}
|
|
1542
1613
|
async function removeFile(filepath) {
|
|
@@ -1545,7 +1616,7 @@ async function removeFile(filepath) {
|
|
|
1545
1616
|
await (0, import_promises2.rm)(filepath);
|
|
1546
1617
|
}
|
|
1547
1618
|
} catch (error) {
|
|
1548
|
-
|
|
1619
|
+
logger.warn(`Failed to remove file ${filepath}:`, error);
|
|
1549
1620
|
}
|
|
1550
1621
|
}
|
|
1551
1622
|
async function removeClaudeGeneratedFiles() {
|
|
@@ -1568,50 +1639,50 @@ async function configCommand(options = {}) {
|
|
|
1568
1639
|
await showConfig();
|
|
1569
1640
|
}
|
|
1570
1641
|
async function showConfig() {
|
|
1571
|
-
|
|
1642
|
+
logger.log("Loading configuration...\n");
|
|
1572
1643
|
try {
|
|
1573
1644
|
const result = await loadConfig();
|
|
1574
1645
|
if (result.isEmpty) {
|
|
1575
|
-
|
|
1646
|
+
logger.log("No configuration file found. Using default configuration.\n");
|
|
1576
1647
|
} else {
|
|
1577
|
-
|
|
1648
|
+
logger.log(`Configuration loaded from: ${result.filepath}
|
|
1578
1649
|
`);
|
|
1579
1650
|
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1651
|
+
logger.log("Current configuration:");
|
|
1652
|
+
logger.log("=====================");
|
|
1582
1653
|
const config = result.config;
|
|
1583
|
-
|
|
1654
|
+
logger.log(`
|
|
1584
1655
|
AI Rules Directory: ${config.aiRulesDir}`);
|
|
1585
|
-
|
|
1656
|
+
logger.log(`
|
|
1586
1657
|
Default Targets: ${config.defaultTargets.join(", ")}`);
|
|
1587
1658
|
if (config.exclude && config.exclude.length > 0) {
|
|
1588
|
-
|
|
1659
|
+
logger.log(`Excluded Targets: ${config.exclude.join(", ")}`);
|
|
1589
1660
|
}
|
|
1590
|
-
|
|
1661
|
+
logger.log("\nOutput Paths:");
|
|
1591
1662
|
for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
|
|
1592
|
-
|
|
1663
|
+
logger.log(` ${tool}: ${outputPath}`);
|
|
1593
1664
|
}
|
|
1594
1665
|
if (config.baseDir) {
|
|
1595
1666
|
const dirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
1596
|
-
|
|
1667
|
+
logger.log(`
|
|
1597
1668
|
Base Directories: ${dirs.join(", ")}`);
|
|
1598
1669
|
}
|
|
1599
|
-
|
|
1670
|
+
logger.log(`
|
|
1600
1671
|
Verbose: ${config.verbose || false}`);
|
|
1601
|
-
|
|
1672
|
+
logger.log(`Delete before generate: ${config.delete || false}`);
|
|
1602
1673
|
if (config.watch) {
|
|
1603
|
-
|
|
1604
|
-
|
|
1674
|
+
logger.log("\nWatch Configuration:");
|
|
1675
|
+
logger.log(` Enabled: ${config.watch.enabled || false}`);
|
|
1605
1676
|
if (config.watch.interval) {
|
|
1606
|
-
|
|
1677
|
+
logger.log(` Interval: ${config.watch.interval}ms`);
|
|
1607
1678
|
}
|
|
1608
1679
|
if (config.watch.ignore && config.watch.ignore.length > 0) {
|
|
1609
|
-
|
|
1680
|
+
logger.log(` Ignore patterns: ${config.watch.ignore.join(", ")}`);
|
|
1610
1681
|
}
|
|
1611
1682
|
}
|
|
1612
|
-
|
|
1683
|
+
logger.log("\nTip: Use 'rulesync config init' to create a configuration file.");
|
|
1613
1684
|
} catch (error) {
|
|
1614
|
-
|
|
1685
|
+
logger.error(
|
|
1615
1686
|
"\u274C Failed to load configuration:",
|
|
1616
1687
|
error instanceof Error ? error.message : String(error)
|
|
1617
1688
|
);
|
|
@@ -1632,7 +1703,7 @@ async function initConfig(options) {
|
|
|
1632
1703
|
const validFormats = Object.keys(FORMAT_CONFIG);
|
|
1633
1704
|
const selectedFormat = options.format || "jsonc";
|
|
1634
1705
|
if (!validFormats.includes(selectedFormat)) {
|
|
1635
|
-
|
|
1706
|
+
logger.error(
|
|
1636
1707
|
`\u274C Invalid format: ${selectedFormat}. Valid formats are: ${validFormats.join(", ")}`
|
|
1637
1708
|
);
|
|
1638
1709
|
process.exit(1);
|
|
@@ -1648,7 +1719,7 @@ async function initConfig(options) {
|
|
|
1648
1719
|
if (result.success) {
|
|
1649
1720
|
validTargets.push(result.data);
|
|
1650
1721
|
} else {
|
|
1651
|
-
|
|
1722
|
+
logger.error(`\u274C Invalid target: ${target}`);
|
|
1652
1723
|
process.exit(1);
|
|
1653
1724
|
}
|
|
1654
1725
|
}
|
|
@@ -1662,7 +1733,7 @@ async function initConfig(options) {
|
|
|
1662
1733
|
if (result.success) {
|
|
1663
1734
|
validExcludes.push(result.data);
|
|
1664
1735
|
} else {
|
|
1665
|
-
|
|
1736
|
+
logger.error(`\u274C Invalid exclude target: ${exclude}`);
|
|
1666
1737
|
process.exit(1);
|
|
1667
1738
|
}
|
|
1668
1739
|
}
|
|
@@ -1685,18 +1756,18 @@ async function initConfig(options) {
|
|
|
1685
1756
|
try {
|
|
1686
1757
|
const fs2 = await import("fs/promises");
|
|
1687
1758
|
await fs2.access(filepath);
|
|
1688
|
-
|
|
1689
|
-
|
|
1759
|
+
logger.error(`\u274C Configuration file already exists: ${filepath}`);
|
|
1760
|
+
logger.log("Remove the existing file or choose a different format.");
|
|
1690
1761
|
process.exit(1);
|
|
1691
1762
|
} catch {
|
|
1692
1763
|
}
|
|
1693
1764
|
try {
|
|
1694
1765
|
(0, import_node_fs.writeFileSync)(filepath, content, "utf-8");
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1766
|
+
logger.success(`Created configuration file: ${filepath}`);
|
|
1767
|
+
logger.log("\nYou can now customize the configuration to fit your needs.");
|
|
1768
|
+
logger.log("Run 'rulesync generate' to use the new configuration.");
|
|
1698
1769
|
} catch (error) {
|
|
1699
|
-
|
|
1770
|
+
logger.error(
|
|
1700
1771
|
`\u274C Failed to create configuration file: ${error instanceof Error ? error.message : String(error)}`
|
|
1701
1772
|
);
|
|
1702
1773
|
process.exit(1);
|
|
@@ -1770,25 +1841,68 @@ export default config;
|
|
|
1770
1841
|
}
|
|
1771
1842
|
|
|
1772
1843
|
// src/cli/commands/generate.ts
|
|
1773
|
-
var
|
|
1844
|
+
var import_node_path13 = require("path");
|
|
1774
1845
|
|
|
1775
1846
|
// src/core/command-generator.ts
|
|
1776
|
-
var
|
|
1847
|
+
var import_node_path5 = require("path");
|
|
1777
1848
|
|
|
1778
|
-
// src/generators
|
|
1849
|
+
// src/utils/command-generators.ts
|
|
1779
1850
|
var import_node_path3 = require("path");
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1851
|
+
function generateYamlFrontmatter(command, options = {}) {
|
|
1852
|
+
const frontmatter = ["---"];
|
|
1853
|
+
if (options.includeDescription !== false && command.frontmatter.description) {
|
|
1854
|
+
frontmatter.push(`description: ${command.frontmatter.description}`);
|
|
1855
|
+
}
|
|
1856
|
+
if (options.additionalFields) {
|
|
1857
|
+
for (const field of options.additionalFields) {
|
|
1858
|
+
frontmatter.push(`${field.key}: ${field.value}`);
|
|
1786
1859
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1860
|
+
}
|
|
1861
|
+
frontmatter.push("---");
|
|
1862
|
+
return frontmatter;
|
|
1863
|
+
}
|
|
1864
|
+
function buildCommandContent(command, frontmatterOptions) {
|
|
1865
|
+
const frontmatter = generateYamlFrontmatter(command, frontmatterOptions);
|
|
1866
|
+
return `${frontmatter.join("\n")}
|
|
1789
1867
|
|
|
1790
1868
|
${command.content.trim()}
|
|
1791
1869
|
`;
|
|
1870
|
+
}
|
|
1871
|
+
function getFlattenedCommandPath(filename, baseDir, subdir) {
|
|
1872
|
+
const flattenedName = filename.replace(/\//g, "-");
|
|
1873
|
+
return (0, import_node_path3.join)(baseDir, subdir, `${flattenedName}.md`);
|
|
1874
|
+
}
|
|
1875
|
+
function getHierarchicalCommandPath(filename, baseDir, subdir, extension = "md") {
|
|
1876
|
+
const nameWithoutExt = filename.replace(/\.[^/.]+$/, "");
|
|
1877
|
+
const fileWithExt = `${nameWithoutExt}.${extension}`;
|
|
1878
|
+
return (0, import_node_path3.join)(baseDir, subdir, fileWithExt);
|
|
1879
|
+
}
|
|
1880
|
+
function escapeTomlString(str) {
|
|
1881
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1882
|
+
}
|
|
1883
|
+
var syntaxConverters = {
|
|
1884
|
+
/**
|
|
1885
|
+
* Convert Claude Code syntax to Gemini CLI syntax
|
|
1886
|
+
*/
|
|
1887
|
+
toGeminiCli(content) {
|
|
1888
|
+
let converted = content;
|
|
1889
|
+
converted = converted.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
1890
|
+
converted = converted.replace(/!`([^`]+)`/g, "!{$1}");
|
|
1891
|
+
return converted.trim();
|
|
1892
|
+
},
|
|
1893
|
+
/**
|
|
1894
|
+
* Convert to Roo Code syntax (currently identical to Claude Code)
|
|
1895
|
+
*/
|
|
1896
|
+
toRooCode(content) {
|
|
1897
|
+
return content.trim();
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
// src/generators/commands/claudecode.ts
|
|
1902
|
+
var ClaudeCodeCommandGenerator = class {
|
|
1903
|
+
generate(command, outputDir) {
|
|
1904
|
+
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1905
|
+
const content = buildCommandContent(command);
|
|
1792
1906
|
return {
|
|
1793
1907
|
tool: "claudecode",
|
|
1794
1908
|
filepath,
|
|
@@ -1796,20 +1910,18 @@ ${command.content.trim()}
|
|
|
1796
1910
|
};
|
|
1797
1911
|
}
|
|
1798
1912
|
getOutputPath(filename, baseDir) {
|
|
1799
|
-
|
|
1800
|
-
return (0, import_node_path3.join)(baseDir, ".claude", "commands", `${flattenedName}.md`);
|
|
1913
|
+
return getFlattenedCommandPath(filename, baseDir, ".claude/commands");
|
|
1801
1914
|
}
|
|
1802
1915
|
};
|
|
1803
1916
|
|
|
1804
1917
|
// src/generators/commands/geminicli.ts
|
|
1805
|
-
var import_node_path4 = require("path");
|
|
1806
1918
|
var GeminiCliCommandGenerator = class {
|
|
1807
1919
|
generate(command, outputDir) {
|
|
1808
1920
|
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1809
|
-
const convertedContent =
|
|
1921
|
+
const convertedContent = syntaxConverters.toGeminiCli(command.content);
|
|
1810
1922
|
const tomlLines = [];
|
|
1811
1923
|
if (command.frontmatter.description) {
|
|
1812
|
-
tomlLines.push(`description = "${
|
|
1924
|
+
tomlLines.push(`description = "${escapeTomlString(command.frontmatter.description)}"`);
|
|
1813
1925
|
tomlLines.push("");
|
|
1814
1926
|
}
|
|
1815
1927
|
tomlLines.push(`prompt = """${convertedContent}"""`);
|
|
@@ -1821,41 +1933,15 @@ var GeminiCliCommandGenerator = class {
|
|
|
1821
1933
|
};
|
|
1822
1934
|
}
|
|
1823
1935
|
getOutputPath(filename, baseDir) {
|
|
1824
|
-
|
|
1825
|
-
const filenameWithExt = tomlFilename.endsWith(".toml") ? tomlFilename : `${tomlFilename}.toml`;
|
|
1826
|
-
return (0, import_node_path4.join)(baseDir, ".gemini", "commands", filenameWithExt);
|
|
1827
|
-
}
|
|
1828
|
-
convertSyntax(content) {
|
|
1829
|
-
let converted = content;
|
|
1830
|
-
converted = converted.replace(/\$ARGUMENTS/g, "{{args}}");
|
|
1831
|
-
converted = converted.replace(/!`([^`]+)`/g, "!{$1}");
|
|
1832
|
-
const atSyntaxMatches = converted.match(/@[^\s]+/g);
|
|
1833
|
-
if (atSyntaxMatches) {
|
|
1834
|
-
console.warn(
|
|
1835
|
-
`\u26A0\uFE0F Warning: @ syntax found (${atSyntaxMatches.join(", ")}). Gemini CLI does not support file content injection. Consider using shell commands or remove these references.`
|
|
1836
|
-
);
|
|
1837
|
-
}
|
|
1838
|
-
return converted.trim();
|
|
1839
|
-
}
|
|
1840
|
-
escapeTomlString(str) {
|
|
1841
|
-
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1936
|
+
return getHierarchicalCommandPath(filename, baseDir, ".gemini/commands", "toml");
|
|
1842
1937
|
}
|
|
1843
1938
|
};
|
|
1844
1939
|
|
|
1845
1940
|
// src/generators/commands/roo.ts
|
|
1846
|
-
var import_node_path5 = require("path");
|
|
1847
1941
|
var RooCommandGenerator = class {
|
|
1848
1942
|
generate(command, outputDir) {
|
|
1849
1943
|
const filepath = this.getOutputPath(command.filename, outputDir);
|
|
1850
|
-
const
|
|
1851
|
-
if (command.frontmatter.description) {
|
|
1852
|
-
frontmatter.push(`description: ${command.frontmatter.description}`);
|
|
1853
|
-
}
|
|
1854
|
-
frontmatter.push("---");
|
|
1855
|
-
const content = `${frontmatter.join("\n")}
|
|
1856
|
-
|
|
1857
|
-
${command.content.trim()}
|
|
1858
|
-
`;
|
|
1944
|
+
const content = buildCommandContent(command);
|
|
1859
1945
|
return {
|
|
1860
1946
|
tool: "roo",
|
|
1861
1947
|
filepath,
|
|
@@ -1863,8 +1949,7 @@ ${command.content.trim()}
|
|
|
1863
1949
|
};
|
|
1864
1950
|
}
|
|
1865
1951
|
getOutputPath(filename, baseDir) {
|
|
1866
|
-
|
|
1867
|
-
return (0, import_node_path5.join)(baseDir, ".roo", "commands", `${flattenedName}.md`);
|
|
1952
|
+
return getFlattenedCommandPath(filename, baseDir, ".roo/commands");
|
|
1868
1953
|
}
|
|
1869
1954
|
};
|
|
1870
1955
|
|
|
@@ -1879,8 +1964,27 @@ function getCommandGenerator(tool) {
|
|
|
1879
1964
|
}
|
|
1880
1965
|
|
|
1881
1966
|
// src/core/command-parser.ts
|
|
1882
|
-
var
|
|
1967
|
+
var import_node_path4 = require("path");
|
|
1968
|
+
|
|
1969
|
+
// src/utils/frontmatter.ts
|
|
1883
1970
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
1971
|
+
function parseFrontmatter(content, options) {
|
|
1972
|
+
const parsed = (0, import_gray_matter.default)(content, options?.matterOptions);
|
|
1973
|
+
return {
|
|
1974
|
+
content: parsed.content.trim(),
|
|
1975
|
+
data: parsed.data || {}
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
function extractArrayField(data, key, defaultValue = []) {
|
|
1979
|
+
const value = data[key];
|
|
1980
|
+
return Array.isArray(value) ? value : defaultValue;
|
|
1981
|
+
}
|
|
1982
|
+
function extractStringField(data, key, defaultValue) {
|
|
1983
|
+
const value = data[key];
|
|
1984
|
+
return typeof value === "string" ? value : defaultValue;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
// src/core/command-parser.ts
|
|
1884
1988
|
async function parseCommandsFromDirectory(commandsDir) {
|
|
1885
1989
|
const commandFiles = await findFiles(commandsDir, ".md");
|
|
1886
1990
|
const commands = [];
|
|
@@ -1895,17 +1999,17 @@ async function parseCommandsFromDirectory(commandsDir) {
|
|
|
1895
1999
|
}
|
|
1896
2000
|
}
|
|
1897
2001
|
if (errors.length > 0) {
|
|
1898
|
-
|
|
2002
|
+
logger.warn(`Command parsing errors:
|
|
1899
2003
|
${errors.join("\n")}`);
|
|
1900
2004
|
}
|
|
1901
2005
|
return commands;
|
|
1902
2006
|
}
|
|
1903
2007
|
async function parseCommandFile(filepath) {
|
|
1904
2008
|
const content = await readFileContent(filepath);
|
|
1905
|
-
const parsed = (
|
|
2009
|
+
const parsed = parseFrontmatter(content);
|
|
1906
2010
|
try {
|
|
1907
2011
|
const validatedData = CommandFrontmatterSchema.parse(parsed.data);
|
|
1908
|
-
const filename = (0,
|
|
2012
|
+
const filename = (0, import_node_path4.basename)(filepath, ".md");
|
|
1909
2013
|
return {
|
|
1910
2014
|
frontmatter: {
|
|
1911
2015
|
description: validatedData.description
|
|
@@ -1923,7 +2027,7 @@ async function parseCommandFile(filepath) {
|
|
|
1923
2027
|
|
|
1924
2028
|
// src/core/command-generator.ts
|
|
1925
2029
|
async function generateCommands(projectRoot, baseDir, targets) {
|
|
1926
|
-
const commandsDir = (0,
|
|
2030
|
+
const commandsDir = (0, import_node_path5.join)(projectRoot, ".rulesync", "commands");
|
|
1927
2031
|
if (!await fileExists(commandsDir)) {
|
|
1928
2032
|
return [];
|
|
1929
2033
|
}
|
|
@@ -1947,8 +2051,8 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
1947
2051
|
outputs.push(output);
|
|
1948
2052
|
} catch (error) {
|
|
1949
2053
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1950
|
-
|
|
1951
|
-
|
|
2054
|
+
logger.error(
|
|
2055
|
+
`Failed to generate ${target} command for ${command.filename}: ${errorMessage}`
|
|
1952
2056
|
);
|
|
1953
2057
|
}
|
|
1954
2058
|
}
|
|
@@ -1957,7 +2061,7 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
1957
2061
|
}
|
|
1958
2062
|
|
|
1959
2063
|
// src/generators/ignore/shared-factory.ts
|
|
1960
|
-
var
|
|
2064
|
+
var import_node_path6 = require("path");
|
|
1961
2065
|
|
|
1962
2066
|
// src/generators/ignore/shared-helpers.ts
|
|
1963
2067
|
function extractIgnorePatternsFromRules(rules) {
|
|
@@ -2080,7 +2184,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
|
|
|
2080
2184
|
const outputs = [];
|
|
2081
2185
|
const content = generateIgnoreContent(rules, ignoreConfig);
|
|
2082
2186
|
const outputPath = baseDir || process.cwd();
|
|
2083
|
-
const filepath = (0,
|
|
2187
|
+
const filepath = (0, import_node_path6.join)(outputPath, ignoreConfig.filename);
|
|
2084
2188
|
outputs.push({
|
|
2085
2189
|
tool: ignoreConfig.tool,
|
|
2086
2190
|
filepath,
|
|
@@ -2668,20 +2772,20 @@ function generateWindsurfIgnore(rules, config, baseDir) {
|
|
|
2668
2772
|
}
|
|
2669
2773
|
|
|
2670
2774
|
// src/generators/rules/augmentcode.ts
|
|
2671
|
-
var
|
|
2775
|
+
var import_node_path9 = require("path");
|
|
2672
2776
|
|
|
2673
2777
|
// src/generators/rules/shared-helpers.ts
|
|
2674
|
-
var
|
|
2778
|
+
var import_node_path8 = require("path");
|
|
2675
2779
|
|
|
2676
2780
|
// src/utils/ignore.ts
|
|
2677
|
-
var
|
|
2781
|
+
var import_node_path7 = require("path");
|
|
2678
2782
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
2679
2783
|
var cachedIgnorePatterns = null;
|
|
2680
2784
|
async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
2681
2785
|
if (cachedIgnorePatterns) {
|
|
2682
2786
|
return cachedIgnorePatterns;
|
|
2683
2787
|
}
|
|
2684
|
-
const ignorePath = (0,
|
|
2788
|
+
const ignorePath = (0, import_node_path7.join)(baseDir, ".rulesyncignore");
|
|
2685
2789
|
if (!await fileExists(ignorePath)) {
|
|
2686
2790
|
cachedIgnorePatterns = { patterns: [] };
|
|
2687
2791
|
return cachedIgnorePatterns;
|
|
@@ -2692,7 +2796,7 @@ async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
|
2692
2796
|
cachedIgnorePatterns = { patterns };
|
|
2693
2797
|
return cachedIgnorePatterns;
|
|
2694
2798
|
} catch (error) {
|
|
2695
|
-
|
|
2799
|
+
logger.warn(`Failed to read .rulesyncignore: ${error}`);
|
|
2696
2800
|
cachedIgnorePatterns = { patterns: [] };
|
|
2697
2801
|
return cachedIgnorePatterns;
|
|
2698
2802
|
}
|
|
@@ -2735,7 +2839,7 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
2735
2839
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
2736
2840
|
outputs.push({
|
|
2737
2841
|
tool,
|
|
2738
|
-
filepath: (0,
|
|
2842
|
+
filepath: (0, import_node_path8.join)(outputDir, relativePath),
|
|
2739
2843
|
content
|
|
2740
2844
|
});
|
|
2741
2845
|
}
|
|
@@ -2744,7 +2848,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
2744
2848
|
for (const rule of rules) {
|
|
2745
2849
|
const content = generatorConfig.generateContent(rule);
|
|
2746
2850
|
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
2747
|
-
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0,
|
|
2851
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path8.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
2748
2852
|
outputs.push({
|
|
2749
2853
|
tool: generatorConfig.tool,
|
|
2750
2854
|
filepath,
|
|
@@ -2772,7 +2876,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
2772
2876
|
for (const rule of detailRules) {
|
|
2773
2877
|
const content = generatorConfig.generateDetailContent(rule);
|
|
2774
2878
|
const filepath = resolvePath(
|
|
2775
|
-
(0,
|
|
2879
|
+
(0, import_node_path8.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
2776
2880
|
baseDir
|
|
2777
2881
|
);
|
|
2778
2882
|
outputs.push({
|
|
@@ -2835,7 +2939,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
2835
2939
|
"augmentcode",
|
|
2836
2940
|
config,
|
|
2837
2941
|
baseDir,
|
|
2838
|
-
(0,
|
|
2942
|
+
(0, import_node_path9.join)(".augment", "rules", `${rule.filename}.md`),
|
|
2839
2943
|
generateRuleFile(rule)
|
|
2840
2944
|
);
|
|
2841
2945
|
});
|
|
@@ -2888,7 +2992,7 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
2888
2992
|
}
|
|
2889
2993
|
|
|
2890
2994
|
// src/generators/rules/claudecode.ts
|
|
2891
|
-
var
|
|
2995
|
+
var import_node_path10 = require("path");
|
|
2892
2996
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
2893
2997
|
const generatorConfig = {
|
|
2894
2998
|
tool: "claudecode",
|
|
@@ -2900,7 +3004,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
2900
3004
|
generateDetailContent: generateMemoryFile,
|
|
2901
3005
|
detailSubDir: ".claude/memories",
|
|
2902
3006
|
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
2903
|
-
const settingsPath = resolvePath((0,
|
|
3007
|
+
const settingsPath = resolvePath((0, import_node_path10.join)(".claude", "settings.json"), baseDir2);
|
|
2904
3008
|
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
2905
3009
|
return [];
|
|
2906
3010
|
}
|
|
@@ -2937,7 +3041,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
2937
3041
|
const content = await readFileContent(settingsPath);
|
|
2938
3042
|
rawSettings = JSON.parse(content);
|
|
2939
3043
|
} catch {
|
|
2940
|
-
|
|
3044
|
+
logger.warn(`Failed to parse existing ${settingsPath}, creating new settings`);
|
|
2941
3045
|
rawSettings = {};
|
|
2942
3046
|
}
|
|
2943
3047
|
}
|
|
@@ -2960,11 +3064,11 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
2960
3064
|
settings.permissions.deny = Array.from(new Set(filteredDeny));
|
|
2961
3065
|
const jsonContent = JSON.stringify(settings, null, 2);
|
|
2962
3066
|
await writeFileContent(settingsPath, jsonContent);
|
|
2963
|
-
|
|
3067
|
+
logger.success(`Updated Claude Code settings: ${settingsPath}`);
|
|
2964
3068
|
}
|
|
2965
3069
|
|
|
2966
3070
|
// src/generators/rules/generator-registry.ts
|
|
2967
|
-
var
|
|
3071
|
+
var import_node_path11 = require("path");
|
|
2968
3072
|
function determineCursorRuleType(frontmatter) {
|
|
2969
3073
|
if (frontmatter.cursorRuleType) {
|
|
2970
3074
|
return frontmatter.cursorRuleType;
|
|
@@ -3044,7 +3148,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3044
3148
|
},
|
|
3045
3149
|
pathResolver: (rule, outputDir) => {
|
|
3046
3150
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
3047
|
-
return (0,
|
|
3151
|
+
return (0, import_node_path11.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
3048
3152
|
}
|
|
3049
3153
|
},
|
|
3050
3154
|
cursor: {
|
|
@@ -3084,7 +3188,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3084
3188
|
return lines.join("\n");
|
|
3085
3189
|
},
|
|
3086
3190
|
pathResolver: (rule, outputDir) => {
|
|
3087
|
-
return (0,
|
|
3191
|
+
return (0, import_node_path11.join)(outputDir, `${rule.filename}.mdc`);
|
|
3088
3192
|
}
|
|
3089
3193
|
},
|
|
3090
3194
|
codexcli: {
|
|
@@ -3120,10 +3224,10 @@ var GENERATOR_REGISTRY = {
|
|
|
3120
3224
|
pathResolver: (rule, outputDir) => {
|
|
3121
3225
|
const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
|
|
3122
3226
|
if (outputFormat === "single-file") {
|
|
3123
|
-
return (0,
|
|
3227
|
+
return (0, import_node_path11.join)(outputDir, ".windsurf-rules");
|
|
3124
3228
|
} else {
|
|
3125
|
-
const rulesDir = (0,
|
|
3126
|
-
return (0,
|
|
3229
|
+
const rulesDir = (0, import_node_path11.join)(outputDir, ".windsurf", "rules");
|
|
3230
|
+
return (0, import_node_path11.join)(rulesDir, `${rule.filename}.md`);
|
|
3127
3231
|
}
|
|
3128
3232
|
}
|
|
3129
3233
|
},
|
|
@@ -3241,7 +3345,7 @@ async function generateCodexConfig(rules, config, baseDir) {
|
|
|
3241
3345
|
const concatenatedContent = generateConcatenatedCodexContent(sortedRules);
|
|
3242
3346
|
if (concatenatedContent.trim()) {
|
|
3243
3347
|
const outputDir = resolveOutputDir(config, "codexcli", baseDir);
|
|
3244
|
-
const filepath = `${outputDir}/
|
|
3348
|
+
const filepath = `${outputDir}/AGENTS.md`;
|
|
3245
3349
|
outputs.push({
|
|
3246
3350
|
tool: "codexcli",
|
|
3247
3351
|
filepath,
|
|
@@ -3347,14 +3451,12 @@ async function generateConfigurations(rules, config, targetTools, baseDir) {
|
|
|
3347
3451
|
const toolsToGenerate = targetTools || config.defaultTargets;
|
|
3348
3452
|
const rootFiles = rules.filter((rule) => rule.frontmatter.root === true);
|
|
3349
3453
|
if (rootFiles.length === 0) {
|
|
3350
|
-
|
|
3351
|
-
"\u26A0\uFE0F Warning: No files with 'root: true' found. This may result in incomplete configurations."
|
|
3352
|
-
);
|
|
3454
|
+
logger.warn("No files with 'root: true' found. This may result in incomplete configurations.");
|
|
3353
3455
|
}
|
|
3354
3456
|
for (const tool of toolsToGenerate) {
|
|
3355
3457
|
const relevantRules = filterRulesForTool(rules, tool, config);
|
|
3356
3458
|
if (relevantRules.length === 0) {
|
|
3357
|
-
|
|
3459
|
+
logger.warn(`No rules found for tool: ${tool}`);
|
|
3358
3460
|
continue;
|
|
3359
3461
|
}
|
|
3360
3462
|
const toolOutputs = await generateForTool(tool, relevantRules, config, baseDir);
|
|
@@ -3419,22 +3521,21 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
3419
3521
|
return [...windsurfRulesOutputs, ...windsurfIgnoreOutputs];
|
|
3420
3522
|
}
|
|
3421
3523
|
default:
|
|
3422
|
-
|
|
3524
|
+
logger.warn(`Unknown tool: ${tool}`);
|
|
3423
3525
|
return null;
|
|
3424
3526
|
}
|
|
3425
3527
|
}
|
|
3426
3528
|
|
|
3427
3529
|
// src/core/parser.ts
|
|
3428
|
-
var
|
|
3429
|
-
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
3530
|
+
var import_node_path12 = require("path");
|
|
3430
3531
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
3431
3532
|
const ignorePatterns = await loadIgnorePatterns();
|
|
3432
|
-
const allRuleFiles = await
|
|
3533
|
+
const allRuleFiles = await findRuleFiles(aiRulesDir);
|
|
3433
3534
|
const ruleFiles = filterIgnoredFiles(allRuleFiles, ignorePatterns.patterns);
|
|
3434
3535
|
const rules = [];
|
|
3435
3536
|
const errors = [];
|
|
3436
3537
|
if (ignorePatterns.patterns.length > 0) {
|
|
3437
|
-
|
|
3538
|
+
logger.info(`Loaded ${ignorePatterns.patterns.length} ignore patterns from .rulesyncignore`);
|
|
3438
3539
|
}
|
|
3439
3540
|
for (const filepath of ruleFiles) {
|
|
3440
3541
|
try {
|
|
@@ -3460,7 +3561,7 @@ ${errors.join("\n")}`);
|
|
|
3460
3561
|
}
|
|
3461
3562
|
async function parseRuleFile(filepath) {
|
|
3462
3563
|
const content = await readFileContent(filepath);
|
|
3463
|
-
const parsed = (
|
|
3564
|
+
const parsed = parseFrontmatter(content);
|
|
3464
3565
|
try {
|
|
3465
3566
|
const validatedData = RuleFrontmatterSchema.parse(parsed.data);
|
|
3466
3567
|
const frontmatter = {
|
|
@@ -3479,7 +3580,7 @@ async function parseRuleFile(filepath) {
|
|
|
3479
3580
|
},
|
|
3480
3581
|
...validatedData.tags !== void 0 && { tags: validatedData.tags }
|
|
3481
3582
|
};
|
|
3482
|
-
const filename = (0,
|
|
3583
|
+
const filename = (0, import_node_path12.basename)(filepath, ".md");
|
|
3483
3584
|
return {
|
|
3484
3585
|
frontmatter,
|
|
3485
3586
|
content: parsed.content,
|
|
@@ -3648,6 +3749,7 @@ async function generateCommand(options = {}) {
|
|
|
3648
3749
|
...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
|
|
3649
3750
|
};
|
|
3650
3751
|
const config = mergeWithCliOptions(configResult.config, cliOptions);
|
|
3752
|
+
logger.setVerbose(config.verbose || false);
|
|
3651
3753
|
if (options.tools && options.tools.length > 0) {
|
|
3652
3754
|
const configTargets = config.defaultTargets;
|
|
3653
3755
|
const cliTools = options.tools;
|
|
@@ -3656,18 +3758,18 @@ async function generateCommand(options = {}) {
|
|
|
3656
3758
|
const notInConfig = cliTools.filter((tool) => !configTargetsSet.has(tool));
|
|
3657
3759
|
const notInCli = configTargets.filter((tool) => !cliToolsSet.has(tool));
|
|
3658
3760
|
if (notInConfig.length > 0 || notInCli.length > 0) {
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3761
|
+
logger.warn("\u26A0\uFE0F Warning: CLI tool selection differs from configuration!");
|
|
3762
|
+
logger.warn(` Config targets: ${configTargets.join(", ")}`);
|
|
3763
|
+
logger.warn(` CLI specified: ${cliTools.join(", ")}`);
|
|
3662
3764
|
if (notInConfig.length > 0) {
|
|
3663
|
-
|
|
3765
|
+
logger.warn(` Tools specified but not in config: ${notInConfig.join(", ")}`);
|
|
3664
3766
|
}
|
|
3665
3767
|
if (notInCli.length > 0) {
|
|
3666
|
-
|
|
3768
|
+
logger.warn(` Tools in config but not specified: ${notInCli.join(", ")}`);
|
|
3667
3769
|
}
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3770
|
+
logger.warn("\n The configuration file targets will be used.");
|
|
3771
|
+
logger.warn(" To change targets, update your rulesync config file.");
|
|
3772
|
+
logger.warn("");
|
|
3671
3773
|
}
|
|
3672
3774
|
}
|
|
3673
3775
|
let baseDirs;
|
|
@@ -3678,42 +3780,46 @@ async function generateCommand(options = {}) {
|
|
|
3678
3780
|
} else {
|
|
3679
3781
|
baseDirs = [process.cwd()];
|
|
3680
3782
|
}
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
}
|
|
3684
|
-
console.log("Generating configuration files...");
|
|
3783
|
+
logger.info(`Loaded configuration from: ${configResult.filepath}`);
|
|
3784
|
+
logger.log("Generating configuration files...");
|
|
3685
3785
|
if (!await fileExists(config.aiRulesDir)) {
|
|
3686
|
-
|
|
3786
|
+
logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
|
|
3687
3787
|
process.exit(1);
|
|
3688
3788
|
}
|
|
3689
3789
|
try {
|
|
3690
|
-
|
|
3691
|
-
console.log(`Parsing rules from ${config.aiRulesDir}...`);
|
|
3692
|
-
}
|
|
3790
|
+
logger.info(`Parsing rules from ${config.aiRulesDir}...`);
|
|
3693
3791
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
3694
3792
|
if (rules.length === 0) {
|
|
3695
|
-
|
|
3793
|
+
logger.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
3696
3794
|
return;
|
|
3697
3795
|
}
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
console.log(`Base directories: ${baseDirs.join(", ")}`);
|
|
3701
|
-
}
|
|
3796
|
+
logger.info(`Found ${rules.length} rule(s)`);
|
|
3797
|
+
logger.info(`Base directories: ${baseDirs.join(", ")}`);
|
|
3702
3798
|
if (config.delete) {
|
|
3703
|
-
|
|
3704
|
-
console.log("Deleting existing output directories...");
|
|
3705
|
-
}
|
|
3799
|
+
logger.info("Deleting existing output directories...");
|
|
3706
3800
|
const targetTools = config.defaultTargets;
|
|
3707
3801
|
const deleteTasks = [];
|
|
3802
|
+
const commandsDir = (0, import_node_path13.join)(config.aiRulesDir, "commands");
|
|
3803
|
+
const hasCommands = await fileExists(commandsDir);
|
|
3804
|
+
let hasCommandFiles = false;
|
|
3805
|
+
if (hasCommands) {
|
|
3806
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
3807
|
+
try {
|
|
3808
|
+
const files = await readdir2(commandsDir);
|
|
3809
|
+
hasCommandFiles = files.some((file) => file.endsWith(".md"));
|
|
3810
|
+
} catch {
|
|
3811
|
+
hasCommandFiles = false;
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3708
3814
|
for (const tool of targetTools) {
|
|
3709
3815
|
switch (tool) {
|
|
3710
3816
|
case "augmentcode":
|
|
3711
|
-
deleteTasks.push(removeDirectory((0,
|
|
3712
|
-
deleteTasks.push(removeDirectory((0,
|
|
3817
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "rules")));
|
|
3818
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "ignore")));
|
|
3713
3819
|
break;
|
|
3714
3820
|
case "augmentcode-legacy":
|
|
3715
3821
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3716
|
-
deleteTasks.push(removeDirectory((0,
|
|
3822
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".augment", "ignore")));
|
|
3717
3823
|
break;
|
|
3718
3824
|
case "copilot":
|
|
3719
3825
|
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
@@ -3726,15 +3832,21 @@ async function generateCommand(options = {}) {
|
|
|
3726
3832
|
break;
|
|
3727
3833
|
case "claudecode":
|
|
3728
3834
|
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
3729
|
-
|
|
3835
|
+
if (hasCommandFiles) {
|
|
3836
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".claude", "commands")));
|
|
3837
|
+
}
|
|
3730
3838
|
break;
|
|
3731
3839
|
case "roo":
|
|
3732
3840
|
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
3733
|
-
|
|
3841
|
+
if (hasCommandFiles) {
|
|
3842
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".roo", "commands")));
|
|
3843
|
+
}
|
|
3734
3844
|
break;
|
|
3735
3845
|
case "geminicli":
|
|
3736
3846
|
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
3737
|
-
|
|
3847
|
+
if (hasCommandFiles) {
|
|
3848
|
+
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".gemini", "commands")));
|
|
3849
|
+
}
|
|
3738
3850
|
break;
|
|
3739
3851
|
case "kiro":
|
|
3740
3852
|
deleteTasks.push(removeDirectory(config.outputPaths.kiro));
|
|
@@ -3745,44 +3857,34 @@ async function generateCommand(options = {}) {
|
|
|
3745
3857
|
}
|
|
3746
3858
|
}
|
|
3747
3859
|
await Promise.all(deleteTasks);
|
|
3748
|
-
|
|
3749
|
-
console.log("Deleted existing output directories");
|
|
3750
|
-
}
|
|
3860
|
+
logger.info("Deleted existing output directories");
|
|
3751
3861
|
}
|
|
3752
3862
|
let totalOutputs = 0;
|
|
3753
3863
|
for (const baseDir of baseDirs) {
|
|
3754
|
-
|
|
3755
|
-
console.log(`
|
|
3864
|
+
logger.info(`
|
|
3756
3865
|
Generating configurations for base directory: ${baseDir}`);
|
|
3757
|
-
}
|
|
3758
3866
|
const outputs = await generateConfigurations(rules, config, config.defaultTargets, baseDir);
|
|
3759
3867
|
if (outputs.length === 0) {
|
|
3760
|
-
|
|
3761
|
-
console.warn(`\u26A0\uFE0F No configurations generated for ${baseDir}`);
|
|
3762
|
-
}
|
|
3868
|
+
logger.warn(`\u26A0\uFE0F No configurations generated for ${baseDir}`);
|
|
3763
3869
|
continue;
|
|
3764
3870
|
}
|
|
3765
3871
|
for (const output of outputs) {
|
|
3766
3872
|
await writeFileContent(output.filepath, output.content);
|
|
3767
|
-
|
|
3873
|
+
logger.success(`Generated ${output.tool} configuration: ${output.filepath}`);
|
|
3768
3874
|
}
|
|
3769
3875
|
totalOutputs += outputs.length;
|
|
3770
3876
|
}
|
|
3771
3877
|
if (totalOutputs === 0) {
|
|
3772
|
-
|
|
3878
|
+
logger.warn("\u26A0\uFE0F No configurations generated");
|
|
3773
3879
|
return;
|
|
3774
3880
|
}
|
|
3775
|
-
|
|
3776
|
-
console.log("\nGenerating MCP configurations...");
|
|
3777
|
-
}
|
|
3881
|
+
logger.info("\nGenerating MCP configurations...");
|
|
3778
3882
|
let totalMcpOutputs = 0;
|
|
3779
3883
|
for (const baseDir of baseDirs) {
|
|
3780
3884
|
try {
|
|
3781
3885
|
const mcpConfig = parseMcpConfig(process.cwd());
|
|
3782
3886
|
if (!mcpConfig || !mcpConfig.mcpServers || Object.keys(mcpConfig.mcpServers).length === 0) {
|
|
3783
|
-
|
|
3784
|
-
console.log(`No MCP configuration found for ${baseDir}`);
|
|
3785
|
-
}
|
|
3887
|
+
logger.info(`No MCP configuration found for ${baseDir}`);
|
|
3786
3888
|
continue;
|
|
3787
3889
|
}
|
|
3788
3890
|
const mcpResults = await generateMcpConfigurations(
|
|
@@ -3791,27 +3893,21 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3791
3893
|
config.defaultTargets
|
|
3792
3894
|
);
|
|
3793
3895
|
if (mcpResults.length === 0) {
|
|
3794
|
-
|
|
3795
|
-
console.log(`No MCP configurations generated for ${baseDir}`);
|
|
3796
|
-
}
|
|
3896
|
+
logger.info(`No MCP configurations generated for ${baseDir}`);
|
|
3797
3897
|
continue;
|
|
3798
3898
|
}
|
|
3799
3899
|
for (const result of mcpResults) {
|
|
3800
3900
|
await writeFileContent(result.filepath, result.content);
|
|
3801
|
-
|
|
3901
|
+
logger.success(`Generated ${result.tool} MCP configuration: ${result.filepath}`);
|
|
3802
3902
|
totalMcpOutputs++;
|
|
3803
3903
|
}
|
|
3804
3904
|
} catch (error) {
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
);
|
|
3809
|
-
}
|
|
3905
|
+
logger.error(
|
|
3906
|
+
`\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
3907
|
+
);
|
|
3810
3908
|
}
|
|
3811
3909
|
}
|
|
3812
|
-
|
|
3813
|
-
console.log("\nGenerating command files...");
|
|
3814
|
-
}
|
|
3910
|
+
logger.info("\nGenerating command files...");
|
|
3815
3911
|
let totalCommandOutputs = 0;
|
|
3816
3912
|
for (const baseDir of baseDirs) {
|
|
3817
3913
|
const commandResults = await generateCommands(
|
|
@@ -3820,14 +3916,12 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3820
3916
|
config.defaultTargets
|
|
3821
3917
|
);
|
|
3822
3918
|
if (commandResults.length === 0) {
|
|
3823
|
-
|
|
3824
|
-
console.log(`No commands found for ${baseDir}`);
|
|
3825
|
-
}
|
|
3919
|
+
logger.info(`No commands found for ${baseDir}`);
|
|
3826
3920
|
continue;
|
|
3827
3921
|
}
|
|
3828
3922
|
for (const result of commandResults) {
|
|
3829
3923
|
await writeFileContent(result.filepath, result.content);
|
|
3830
|
-
|
|
3924
|
+
logger.success(`Generated ${result.tool} command: ${result.filepath}`);
|
|
3831
3925
|
totalCommandOutputs++;
|
|
3832
3926
|
}
|
|
3833
3927
|
}
|
|
@@ -3837,22 +3931,22 @@ Generating configurations for base directory: ${baseDir}`);
|
|
|
3837
3931
|
if (totalOutputs > 0) parts.push(`${totalOutputs} configurations`);
|
|
3838
3932
|
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP configurations`);
|
|
3839
3933
|
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
3840
|
-
|
|
3934
|
+
logger.success(
|
|
3841
3935
|
`
|
|
3842
3936
|
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`
|
|
3843
3937
|
);
|
|
3844
3938
|
}
|
|
3845
3939
|
} catch (error) {
|
|
3846
|
-
|
|
3940
|
+
logger.error("\u274C Failed to generate configurations:", error);
|
|
3847
3941
|
process.exit(1);
|
|
3848
3942
|
}
|
|
3849
3943
|
}
|
|
3850
3944
|
|
|
3851
3945
|
// src/cli/commands/gitignore.ts
|
|
3852
3946
|
var import_node_fs2 = require("fs");
|
|
3853
|
-
var
|
|
3947
|
+
var import_node_path14 = require("path");
|
|
3854
3948
|
var gitignoreCommand = async () => {
|
|
3855
|
-
const gitignorePath = (0,
|
|
3949
|
+
const gitignorePath = (0, import_node_path14.join)(process.cwd(), ".gitignore");
|
|
3856
3950
|
const rulesFilesToIgnore = [
|
|
3857
3951
|
"# Generated by rulesync - AI tool configuration files",
|
|
3858
3952
|
"**/.github/copilot-instructions.md",
|
|
@@ -3864,7 +3958,7 @@ var gitignoreCommand = async () => {
|
|
|
3864
3958
|
"**/CLAUDE.md",
|
|
3865
3959
|
"**/.claude/memories/",
|
|
3866
3960
|
"**/.claude/commands/",
|
|
3867
|
-
"**/
|
|
3961
|
+
"**/AGENTS.md",
|
|
3868
3962
|
"**/.codexignore",
|
|
3869
3963
|
"**/.roo/rules/",
|
|
3870
3964
|
"**/.rooignore",
|
|
@@ -3900,7 +3994,7 @@ var gitignoreCommand = async () => {
|
|
|
3900
3994
|
}
|
|
3901
3995
|
}
|
|
3902
3996
|
if (linesToAdd.length === 0) {
|
|
3903
|
-
|
|
3997
|
+
logger.success(".gitignore is already up to date");
|
|
3904
3998
|
return;
|
|
3905
3999
|
}
|
|
3906
4000
|
const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
|
|
@@ -3909,21 +4003,20 @@ ${linesToAdd.join("\n")}
|
|
|
3909
4003
|
` : `${linesToAdd.join("\n")}
|
|
3910
4004
|
`;
|
|
3911
4005
|
(0, import_node_fs2.writeFileSync)(gitignorePath, newContent);
|
|
3912
|
-
|
|
4006
|
+
logger.success(`Added ${linesToAdd.length} rules to .gitignore:`);
|
|
3913
4007
|
for (const line of linesToAdd) {
|
|
3914
4008
|
if (!line.startsWith("#")) {
|
|
3915
|
-
|
|
4009
|
+
logger.log(` ${line}`);
|
|
3916
4010
|
}
|
|
3917
4011
|
}
|
|
3918
4012
|
};
|
|
3919
4013
|
|
|
3920
4014
|
// src/core/importer.ts
|
|
3921
|
-
var
|
|
3922
|
-
var
|
|
4015
|
+
var import_node_path21 = require("path");
|
|
4016
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
3923
4017
|
|
|
3924
4018
|
// src/parsers/augmentcode.ts
|
|
3925
|
-
var
|
|
3926
|
-
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
4019
|
+
var import_node_path15 = require("path");
|
|
3927
4020
|
|
|
3928
4021
|
// src/utils/parser-helpers.ts
|
|
3929
4022
|
function createParseResult() {
|
|
@@ -3971,7 +4064,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
3971
4064
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
3972
4065
|
const result = createParseResult();
|
|
3973
4066
|
if (config.rulesDir) {
|
|
3974
|
-
const rulesDir = (0,
|
|
4067
|
+
const rulesDir = (0, import_node_path15.join)(baseDir, config.rulesDir);
|
|
3975
4068
|
if (await fileExists(rulesDir)) {
|
|
3976
4069
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
3977
4070
|
addRules(result, rulesResult.rules);
|
|
@@ -3984,7 +4077,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
3984
4077
|
}
|
|
3985
4078
|
}
|
|
3986
4079
|
if (config.legacyFilePath) {
|
|
3987
|
-
const legacyPath = (0,
|
|
4080
|
+
const legacyPath = (0, import_node_path15.join)(baseDir, config.legacyFilePath);
|
|
3988
4081
|
if (await fileExists(legacyPath)) {
|
|
3989
4082
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
3990
4083
|
if (legacyResult.rule) {
|
|
@@ -4008,23 +4101,22 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
4008
4101
|
const files = await readdir2(rulesDir);
|
|
4009
4102
|
for (const file of files) {
|
|
4010
4103
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
4011
|
-
const filePath = (0,
|
|
4104
|
+
const filePath = (0, import_node_path15.join)(rulesDir, file);
|
|
4012
4105
|
try {
|
|
4013
4106
|
const rawContent = await readFileContent(filePath);
|
|
4014
|
-
const parsed = (
|
|
4015
|
-
const
|
|
4016
|
-
const
|
|
4017
|
-
const
|
|
4018
|
-
const tags = Array.isArray(frontmatterData.tags) ? frontmatterData.tags : void 0;
|
|
4107
|
+
const parsed = parseFrontmatter(rawContent);
|
|
4108
|
+
const ruleType = extractStringField(parsed.data, "type", "manual");
|
|
4109
|
+
const description = extractStringField(parsed.data, "description", "");
|
|
4110
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
4019
4111
|
const isRoot = ruleType === "always";
|
|
4020
|
-
const filename = (0,
|
|
4112
|
+
const filename = (0, import_node_path15.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
4021
4113
|
const frontmatter = {
|
|
4022
4114
|
root: isRoot,
|
|
4023
4115
|
targets: [config.targetName],
|
|
4024
4116
|
description,
|
|
4025
4117
|
globs: ["**/*"],
|
|
4026
4118
|
// AugmentCode doesn't use specific globs in the same way
|
|
4027
|
-
...tags && { tags }
|
|
4119
|
+
...tags.length > 0 && { tags }
|
|
4028
4120
|
};
|
|
4029
4121
|
rules.push({
|
|
4030
4122
|
frontmatter,
|
|
@@ -4075,8 +4167,7 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
|
4075
4167
|
}
|
|
4076
4168
|
|
|
4077
4169
|
// src/parsers/shared-helpers.ts
|
|
4078
|
-
var
|
|
4079
|
-
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
|
|
4170
|
+
var import_node_path16 = require("path");
|
|
4080
4171
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
4081
4172
|
const errors = [];
|
|
4082
4173
|
const rules = [];
|
|
@@ -4089,16 +4180,18 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
4089
4180
|
let content;
|
|
4090
4181
|
let frontmatter;
|
|
4091
4182
|
if (mainFile.useFrontmatter) {
|
|
4092
|
-
const parsed = (
|
|
4093
|
-
content = parsed.content
|
|
4094
|
-
const parsedFrontmatter = parsed.data;
|
|
4183
|
+
const parsed = parseFrontmatter(rawContent);
|
|
4184
|
+
content = parsed.content;
|
|
4095
4185
|
frontmatter = {
|
|
4096
4186
|
root: mainFile.isRoot ?? false,
|
|
4097
4187
|
targets: [config.tool],
|
|
4098
|
-
description:
|
|
4099
|
-
globs:
|
|
4100
|
-
...parsedFrontmatter.tags && { tags: parsedFrontmatter.tags }
|
|
4188
|
+
description: extractStringField(parsed.data, "description", mainFile.description),
|
|
4189
|
+
globs: extractArrayField(parsed.data, "globs", ["**/*"])
|
|
4101
4190
|
};
|
|
4191
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
4192
|
+
if (tags.length > 0) {
|
|
4193
|
+
frontmatter.tags = tags;
|
|
4194
|
+
}
|
|
4102
4195
|
} else {
|
|
4103
4196
|
content = rawContent.trim();
|
|
4104
4197
|
frontmatter = {
|
|
@@ -4131,23 +4224,29 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
4131
4224
|
const files = await readdir2(dirPath);
|
|
4132
4225
|
for (const file of files) {
|
|
4133
4226
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
4134
|
-
const filePath = (0,
|
|
4227
|
+
const filePath = (0, import_node_path16.join)(dirPath, file);
|
|
4135
4228
|
const fileResult = await safeAsyncOperation(async () => {
|
|
4136
4229
|
const rawContent = await readFileContent(filePath);
|
|
4137
4230
|
let content;
|
|
4138
4231
|
let frontmatter;
|
|
4139
4232
|
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
4140
4233
|
if (dirConfig.filePattern === ".instructions.md") {
|
|
4141
|
-
const parsed = (
|
|
4142
|
-
content = parsed.content
|
|
4143
|
-
const parsedFrontmatter = parsed.data;
|
|
4234
|
+
const parsed = parseFrontmatter(rawContent);
|
|
4235
|
+
content = parsed.content;
|
|
4144
4236
|
frontmatter = {
|
|
4145
4237
|
root: false,
|
|
4146
4238
|
targets: [config.tool],
|
|
4147
|
-
description:
|
|
4148
|
-
|
|
4149
|
-
|
|
4239
|
+
description: extractStringField(
|
|
4240
|
+
parsed.data,
|
|
4241
|
+
"description",
|
|
4242
|
+
`${dirConfig.description}: ${filename}`
|
|
4243
|
+
),
|
|
4244
|
+
globs: extractArrayField(parsed.data, "globs", ["**/*"])
|
|
4150
4245
|
};
|
|
4246
|
+
const tags = extractArrayField(parsed.data, "tags");
|
|
4247
|
+
if (tags.length > 0) {
|
|
4248
|
+
frontmatter.tags = tags;
|
|
4249
|
+
}
|
|
4151
4250
|
} else {
|
|
4152
4251
|
content = rawContent.trim();
|
|
4153
4252
|
frontmatter = {
|
|
@@ -4276,10 +4375,10 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
4276
4375
|
const files = await readdir2(memoryDir);
|
|
4277
4376
|
for (const file of files) {
|
|
4278
4377
|
if (file.endsWith(".md")) {
|
|
4279
|
-
const filePath = (0,
|
|
4378
|
+
const filePath = (0, import_node_path16.join)(memoryDir, file);
|
|
4280
4379
|
const content = await readFileContent(filePath);
|
|
4281
4380
|
if (content.trim()) {
|
|
4282
|
-
const filename = (0,
|
|
4381
|
+
const filename = (0, import_node_path16.basename)(file, ".md");
|
|
4283
4382
|
const frontmatter = {
|
|
4284
4383
|
root: false,
|
|
4285
4384
|
targets: [config.tool],
|
|
@@ -4306,20 +4405,19 @@ async function parseCommandsFiles(commandsDir, config) {
|
|
|
4306
4405
|
const files = await readdir2(commandsDir);
|
|
4307
4406
|
for (const file of files) {
|
|
4308
4407
|
if (file.endsWith(".md")) {
|
|
4309
|
-
const filePath = (0,
|
|
4408
|
+
const filePath = (0, import_node_path16.join)(commandsDir, file);
|
|
4310
4409
|
const content = await readFileContent(filePath);
|
|
4311
4410
|
if (content.trim()) {
|
|
4312
|
-
const filename = (0,
|
|
4411
|
+
const filename = (0, import_node_path16.basename)(file, ".md");
|
|
4313
4412
|
let frontmatter;
|
|
4314
4413
|
let ruleContent;
|
|
4315
4414
|
try {
|
|
4316
|
-
const parsed = (
|
|
4317
|
-
ruleContent = parsed.content
|
|
4318
|
-
const parsedFrontmatter = parsed.data;
|
|
4415
|
+
const parsed = parseFrontmatter(content);
|
|
4416
|
+
ruleContent = parsed.content;
|
|
4319
4417
|
frontmatter = {
|
|
4320
4418
|
root: false,
|
|
4321
4419
|
targets: [config.tool],
|
|
4322
|
-
description:
|
|
4420
|
+
description: extractStringField(parsed.data, "description", `Command: ${filename}`),
|
|
4323
4421
|
globs: ["**/*"]
|
|
4324
4422
|
};
|
|
4325
4423
|
} catch {
|
|
@@ -4420,7 +4518,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
4420
4518
|
}
|
|
4421
4519
|
|
|
4422
4520
|
// src/parsers/codexcli.ts
|
|
4423
|
-
var
|
|
4521
|
+
var import_node_path17 = require("path");
|
|
4424
4522
|
|
|
4425
4523
|
// src/parsers/copilot.ts
|
|
4426
4524
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -4443,8 +4541,7 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
4443
4541
|
}
|
|
4444
4542
|
|
|
4445
4543
|
// src/parsers/cursor.ts
|
|
4446
|
-
var
|
|
4447
|
-
var import_gray_matter5 = __toESM(require("gray-matter"), 1);
|
|
4544
|
+
var import_node_path18 = require("path");
|
|
4448
4545
|
var import_js_yaml = require("js-yaml");
|
|
4449
4546
|
var import_mini8 = require("zod/mini");
|
|
4450
4547
|
var customMatterOptions = {
|
|
@@ -4568,12 +4665,12 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4568
4665
|
const rules = [];
|
|
4569
4666
|
let ignorePatterns;
|
|
4570
4667
|
let mcpServers;
|
|
4571
|
-
const cursorFilePath = (0,
|
|
4668
|
+
const cursorFilePath = (0, import_node_path18.join)(baseDir, ".cursorrules");
|
|
4572
4669
|
if (await fileExists(cursorFilePath)) {
|
|
4573
4670
|
try {
|
|
4574
4671
|
const rawContent = await readFileContent(cursorFilePath);
|
|
4575
|
-
const parsed = (
|
|
4576
|
-
const content = parsed.content
|
|
4672
|
+
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
4673
|
+
const content = parsed.content;
|
|
4577
4674
|
if (content) {
|
|
4578
4675
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, "cursorrules");
|
|
4579
4676
|
frontmatter.targets = ["cursor"];
|
|
@@ -4589,20 +4686,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4589
4686
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
4590
4687
|
}
|
|
4591
4688
|
}
|
|
4592
|
-
const cursorRulesDir = (0,
|
|
4689
|
+
const cursorRulesDir = (0, import_node_path18.join)(baseDir, ".cursor", "rules");
|
|
4593
4690
|
if (await fileExists(cursorRulesDir)) {
|
|
4594
4691
|
try {
|
|
4595
4692
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
4596
4693
|
const files = await readdir2(cursorRulesDir);
|
|
4597
4694
|
for (const file of files) {
|
|
4598
4695
|
if (file.endsWith(".mdc")) {
|
|
4599
|
-
const filePath = (0,
|
|
4696
|
+
const filePath = (0, import_node_path18.join)(cursorRulesDir, file);
|
|
4600
4697
|
try {
|
|
4601
4698
|
const rawContent = await readFileContent(filePath);
|
|
4602
|
-
const parsed = (
|
|
4603
|
-
const content = parsed.content
|
|
4699
|
+
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
4700
|
+
const content = parsed.content;
|
|
4604
4701
|
if (content) {
|
|
4605
|
-
const filename = (0,
|
|
4702
|
+
const filename = (0, import_node_path18.basename)(file, ".mdc");
|
|
4606
4703
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
4607
4704
|
rules.push({
|
|
4608
4705
|
frontmatter,
|
|
@@ -4625,7 +4722,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4625
4722
|
if (rules.length === 0) {
|
|
4626
4723
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
4627
4724
|
}
|
|
4628
|
-
const cursorIgnorePath = (0,
|
|
4725
|
+
const cursorIgnorePath = (0, import_node_path18.join)(baseDir, ".cursorignore");
|
|
4629
4726
|
if (await fileExists(cursorIgnorePath)) {
|
|
4630
4727
|
try {
|
|
4631
4728
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -4638,7 +4735,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
4638
4735
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
4639
4736
|
}
|
|
4640
4737
|
}
|
|
4641
|
-
const cursorMcpPath = (0,
|
|
4738
|
+
const cursorMcpPath = (0, import_node_path18.join)(baseDir, ".cursor", "mcp.json");
|
|
4642
4739
|
if (await fileExists(cursorMcpPath)) {
|
|
4643
4740
|
try {
|
|
4644
4741
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -4688,11 +4785,11 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
4688
4785
|
}
|
|
4689
4786
|
|
|
4690
4787
|
// src/parsers/junie.ts
|
|
4691
|
-
var
|
|
4788
|
+
var import_node_path19 = require("path");
|
|
4692
4789
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
4693
4790
|
const errors = [];
|
|
4694
4791
|
const rules = [];
|
|
4695
|
-
const guidelinesPath = (0,
|
|
4792
|
+
const guidelinesPath = (0, import_node_path19.join)(baseDir, ".junie", "guidelines.md");
|
|
4696
4793
|
if (!await fileExists(guidelinesPath)) {
|
|
4697
4794
|
errors.push(".junie/guidelines.md file not found");
|
|
4698
4795
|
return { rules, errors };
|
|
@@ -4745,18 +4842,23 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
4745
4842
|
|
|
4746
4843
|
// src/parsers/windsurf.ts
|
|
4747
4844
|
var import_promises3 = require("fs/promises");
|
|
4748
|
-
var
|
|
4749
|
-
var import_gray_matter6 = __toESM(require("gray-matter"), 1);
|
|
4845
|
+
var import_node_path20 = require("path");
|
|
4750
4846
|
|
|
4751
4847
|
// src/core/importer.ts
|
|
4752
4848
|
async function importConfiguration(options) {
|
|
4753
|
-
const {
|
|
4849
|
+
const {
|
|
4850
|
+
tool,
|
|
4851
|
+
baseDir = process.cwd(),
|
|
4852
|
+
rulesDir = ".rulesync",
|
|
4853
|
+
verbose = false,
|
|
4854
|
+
useLegacyLocation = false
|
|
4855
|
+
} = options;
|
|
4754
4856
|
const errors = [];
|
|
4755
4857
|
let rules = [];
|
|
4756
4858
|
let ignorePatterns;
|
|
4757
4859
|
let mcpServers;
|
|
4758
4860
|
if (verbose) {
|
|
4759
|
-
|
|
4861
|
+
logger.log(`Importing ${tool} configuration from ${baseDir}...`);
|
|
4760
4862
|
}
|
|
4761
4863
|
try {
|
|
4762
4864
|
switch (tool) {
|
|
@@ -4832,7 +4934,7 @@ async function importConfiguration(options) {
|
|
|
4832
4934
|
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
4833
4935
|
return { success: false, rulesCreated: 0, errors };
|
|
4834
4936
|
}
|
|
4835
|
-
const rulesDirPath = (0,
|
|
4937
|
+
const rulesDirPath = (0, import_node_path21.join)(baseDir, rulesDir);
|
|
4836
4938
|
try {
|
|
4837
4939
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4838
4940
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -4847,16 +4949,22 @@ async function importConfiguration(options) {
|
|
|
4847
4949
|
const baseFilename = rule.filename;
|
|
4848
4950
|
let targetDir = rulesDirPath;
|
|
4849
4951
|
if (rule.type === "command") {
|
|
4850
|
-
targetDir = (0,
|
|
4952
|
+
targetDir = (0, import_node_path21.join)(rulesDirPath, "commands");
|
|
4851
4953
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4852
4954
|
await mkdir3(targetDir, { recursive: true });
|
|
4955
|
+
} else {
|
|
4956
|
+
if (!useLegacyLocation) {
|
|
4957
|
+
targetDir = (0, import_node_path21.join)(rulesDirPath, "rules");
|
|
4958
|
+
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
4959
|
+
await mkdir3(targetDir, { recursive: true });
|
|
4960
|
+
}
|
|
4853
4961
|
}
|
|
4854
|
-
const filePath = (0,
|
|
4962
|
+
const filePath = (0, import_node_path21.join)(targetDir, `${baseFilename}.md`);
|
|
4855
4963
|
const content = generateRuleFileContent(rule);
|
|
4856
4964
|
await writeFileContent(filePath, content);
|
|
4857
4965
|
rulesCreated++;
|
|
4858
4966
|
if (verbose) {
|
|
4859
|
-
|
|
4967
|
+
logger.success(`Created rule file: ${filePath}`);
|
|
4860
4968
|
}
|
|
4861
4969
|
} catch (error) {
|
|
4862
4970
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4866,13 +4974,13 @@ async function importConfiguration(options) {
|
|
|
4866
4974
|
let ignoreFileCreated = false;
|
|
4867
4975
|
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
4868
4976
|
try {
|
|
4869
|
-
const rulesyncignorePath = (0,
|
|
4977
|
+
const rulesyncignorePath = (0, import_node_path21.join)(baseDir, ".rulesyncignore");
|
|
4870
4978
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
4871
4979
|
`;
|
|
4872
4980
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
4873
4981
|
ignoreFileCreated = true;
|
|
4874
4982
|
if (verbose) {
|
|
4875
|
-
|
|
4983
|
+
logger.success(`Created .rulesyncignore with ${ignorePatterns.length} patterns`);
|
|
4876
4984
|
}
|
|
4877
4985
|
} catch (error) {
|
|
4878
4986
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4882,13 +4990,13 @@ async function importConfiguration(options) {
|
|
|
4882
4990
|
let mcpFileCreated = false;
|
|
4883
4991
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
4884
4992
|
try {
|
|
4885
|
-
const mcpPath = (0,
|
|
4993
|
+
const mcpPath = (0, import_node_path21.join)(baseDir, rulesDir, ".mcp.json");
|
|
4886
4994
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
4887
4995
|
`;
|
|
4888
4996
|
await writeFileContent(mcpPath, mcpContent);
|
|
4889
4997
|
mcpFileCreated = true;
|
|
4890
4998
|
if (verbose) {
|
|
4891
|
-
|
|
4999
|
+
logger.success(`Created .mcp.json with ${Object.keys(mcpServers).length} servers`);
|
|
4892
5000
|
}
|
|
4893
5001
|
} catch (error) {
|
|
4894
5002
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4909,15 +5017,16 @@ function generateRuleFileContent(rule) {
|
|
|
4909
5017
|
description: rule.frontmatter.description,
|
|
4910
5018
|
targets: rule.frontmatter.targets
|
|
4911
5019
|
};
|
|
4912
|
-
const frontmatter2 =
|
|
5020
|
+
const frontmatter2 = import_gray_matter2.default.stringify("", simplifiedFrontmatter);
|
|
4913
5021
|
return frontmatter2 + rule.content;
|
|
4914
5022
|
}
|
|
4915
|
-
const frontmatter =
|
|
5023
|
+
const frontmatter = import_gray_matter2.default.stringify("", rule.frontmatter);
|
|
4916
5024
|
return frontmatter + rule.content;
|
|
4917
5025
|
}
|
|
4918
5026
|
|
|
4919
5027
|
// src/cli/commands/import.ts
|
|
4920
5028
|
async function importCommand(options = {}) {
|
|
5029
|
+
logger.setVerbose(options.verbose || false);
|
|
4921
5030
|
const tools = [];
|
|
4922
5031
|
if (options.augmentcode) tools.push("augmentcode");
|
|
4923
5032
|
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
@@ -4928,66 +5037,74 @@ async function importCommand(options = {}) {
|
|
|
4928
5037
|
if (options.roo) tools.push("roo");
|
|
4929
5038
|
if (options.geminicli) tools.push("geminicli");
|
|
4930
5039
|
if (tools.length === 0) {
|
|
4931
|
-
|
|
5040
|
+
logger.error(
|
|
4932
5041
|
"\u274C Please specify one tool to import from (--augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli)"
|
|
4933
5042
|
);
|
|
4934
5043
|
process.exit(1);
|
|
4935
5044
|
}
|
|
4936
5045
|
if (tools.length > 1) {
|
|
4937
|
-
|
|
5046
|
+
logger.error(
|
|
4938
5047
|
"\u274C Only one tool can be specified at a time. Please run the import command separately for each tool."
|
|
4939
5048
|
);
|
|
4940
5049
|
process.exit(1);
|
|
4941
5050
|
}
|
|
4942
5051
|
const tool = tools[0];
|
|
4943
5052
|
if (!tool) {
|
|
4944
|
-
|
|
5053
|
+
logger.error("Error: No tool specified");
|
|
4945
5054
|
process.exit(1);
|
|
4946
5055
|
}
|
|
4947
|
-
|
|
5056
|
+
logger.log(`Importing configuration files from ${tool}...`);
|
|
4948
5057
|
try {
|
|
4949
5058
|
const result = await importConfiguration({
|
|
4950
5059
|
tool,
|
|
4951
|
-
verbose: options.verbose ?? false
|
|
5060
|
+
verbose: options.verbose ?? false,
|
|
5061
|
+
useLegacyLocation: options.legacy ?? false
|
|
4952
5062
|
});
|
|
4953
5063
|
if (result.success) {
|
|
4954
|
-
|
|
5064
|
+
logger.success(`Imported ${result.rulesCreated} rule(s) from ${tool}`);
|
|
4955
5065
|
if (result.ignoreFileCreated) {
|
|
4956
|
-
|
|
5066
|
+
logger.success("Created .rulesyncignore file from ignore patterns");
|
|
4957
5067
|
}
|
|
4958
5068
|
if (result.mcpFileCreated) {
|
|
4959
|
-
|
|
5069
|
+
logger.success("Created .rulesync/.mcp.json file from MCP configuration");
|
|
4960
5070
|
}
|
|
4961
|
-
|
|
5071
|
+
logger.log("You can now run 'rulesync generate' to create tool-specific configurations.");
|
|
4962
5072
|
} else if (result.errors.length > 0) {
|
|
4963
|
-
|
|
4964
|
-
if (
|
|
4965
|
-
|
|
5073
|
+
logger.warn(`\u26A0\uFE0F Failed to import from ${tool}: ${result.errors[0]}`);
|
|
5074
|
+
if (result.errors.length > 1) {
|
|
5075
|
+
logger.info("\nDetailed errors:");
|
|
4966
5076
|
for (const error of result.errors) {
|
|
4967
|
-
|
|
5077
|
+
logger.info(` - ${error}`);
|
|
4968
5078
|
}
|
|
4969
5079
|
}
|
|
4970
5080
|
}
|
|
4971
5081
|
} catch (error) {
|
|
4972
5082
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4973
|
-
|
|
5083
|
+
logger.error(`\u274C Error importing from ${tool}: ${errorMessage}`);
|
|
4974
5084
|
process.exit(1);
|
|
4975
5085
|
}
|
|
4976
5086
|
}
|
|
4977
5087
|
|
|
4978
5088
|
// src/cli/commands/init.ts
|
|
4979
|
-
var
|
|
4980
|
-
async function initCommand() {
|
|
4981
|
-
const
|
|
4982
|
-
|
|
5089
|
+
var import_node_path22 = require("path");
|
|
5090
|
+
async function initCommand(options = {}) {
|
|
5091
|
+
const configResult = await loadConfig();
|
|
5092
|
+
const config = configResult.config;
|
|
5093
|
+
const aiRulesDir = config.aiRulesDir;
|
|
5094
|
+
logger.log("Initializing rulesync...");
|
|
4983
5095
|
await ensureDir(aiRulesDir);
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
5096
|
+
const useLegacy = options.legacy ?? config.legacy ?? false;
|
|
5097
|
+
const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path22.join)(aiRulesDir, "rules");
|
|
5098
|
+
if (!useLegacy) {
|
|
5099
|
+
await ensureDir(rulesDir);
|
|
5100
|
+
}
|
|
5101
|
+
await createSampleFiles(rulesDir);
|
|
5102
|
+
logger.success("rulesync initialized successfully!");
|
|
5103
|
+
logger.log("\nNext steps:");
|
|
5104
|
+
logger.log(`1. Edit rule files in ${rulesDir}/`);
|
|
5105
|
+
logger.log("2. Run 'rulesync generate' to create configuration files");
|
|
5106
|
+
}
|
|
5107
|
+
async function createSampleFiles(rulesDir) {
|
|
4991
5108
|
const sampleFile = {
|
|
4992
5109
|
filename: "overview.md",
|
|
4993
5110
|
content: `---
|
|
@@ -5023,36 +5140,36 @@ globs: ["**/*"]
|
|
|
5023
5140
|
- Follow single responsibility principle
|
|
5024
5141
|
`
|
|
5025
5142
|
};
|
|
5026
|
-
const filepath = (0,
|
|
5143
|
+
const filepath = (0, import_node_path22.join)(rulesDir, sampleFile.filename);
|
|
5027
5144
|
if (!await fileExists(filepath)) {
|
|
5028
5145
|
await writeFileContent(filepath, sampleFile.content);
|
|
5029
|
-
|
|
5146
|
+
logger.success(`Created ${filepath}`);
|
|
5030
5147
|
} else {
|
|
5031
|
-
|
|
5148
|
+
logger.log(`Skipped ${filepath} (already exists)`);
|
|
5032
5149
|
}
|
|
5033
5150
|
}
|
|
5034
5151
|
|
|
5035
5152
|
// src/cli/commands/status.ts
|
|
5036
5153
|
async function statusCommand() {
|
|
5037
5154
|
const config = getDefaultConfig();
|
|
5038
|
-
|
|
5039
|
-
|
|
5155
|
+
logger.log("rulesync Status");
|
|
5156
|
+
logger.log("===============");
|
|
5040
5157
|
const rulesyncExists = await fileExists(config.aiRulesDir);
|
|
5041
|
-
|
|
5158
|
+
logger.log(`
|
|
5042
5159
|
\u{1F4C1} .rulesync directory: ${rulesyncExists ? "\u2705 Found" : "\u274C Not found"}`);
|
|
5043
5160
|
if (!rulesyncExists) {
|
|
5044
|
-
|
|
5161
|
+
logger.log("\n\u{1F4A1} Run 'rulesync init' to get started");
|
|
5045
5162
|
return;
|
|
5046
5163
|
}
|
|
5047
5164
|
try {
|
|
5048
5165
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
5049
|
-
|
|
5166
|
+
logger.log(`
|
|
5050
5167
|
\u{1F4CB} Rules: ${rules.length} total`);
|
|
5051
5168
|
if (rules.length > 0) {
|
|
5052
5169
|
const rootRules = rules.filter((r) => r.frontmatter.root).length;
|
|
5053
5170
|
const nonRootRules = rules.length - rootRules;
|
|
5054
|
-
|
|
5055
|
-
|
|
5171
|
+
logger.log(` - Root rules: ${rootRules}`);
|
|
5172
|
+
logger.log(` - Non-root rules: ${nonRootRules}`);
|
|
5056
5173
|
const targetCounts = { copilot: 0, cursor: 0, cline: 0, claudecode: 0, roo: 0 };
|
|
5057
5174
|
for (const rule of rules) {
|
|
5058
5175
|
const targets = rule.frontmatter.targets[0] === "*" ? config.defaultTargets : rule.frontmatter.targets;
|
|
@@ -5064,63 +5181,63 @@ async function statusCommand() {
|
|
|
5064
5181
|
else if (target === "roo") targetCounts.roo++;
|
|
5065
5182
|
}
|
|
5066
5183
|
}
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
}
|
|
5074
|
-
|
|
5184
|
+
logger.log("\n\u{1F3AF} Target tool coverage:");
|
|
5185
|
+
logger.log(` - Copilot: ${targetCounts.copilot} rules`);
|
|
5186
|
+
logger.log(` - Cursor: ${targetCounts.cursor} rules`);
|
|
5187
|
+
logger.log(` - Cline: ${targetCounts.cline} rules`);
|
|
5188
|
+
logger.log(` - Claude Code: ${targetCounts.claudecode} rules`);
|
|
5189
|
+
logger.log(` - Roo: ${targetCounts.roo} rules`);
|
|
5190
|
+
}
|
|
5191
|
+
logger.log("\n\u{1F4E4} Generated files:");
|
|
5075
5192
|
for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
|
|
5076
5193
|
const outputExists = await fileExists(outputPath);
|
|
5077
|
-
|
|
5194
|
+
logger.log(` - ${tool}: ${outputExists ? "\u2705 Generated" : "\u274C Not found"}`);
|
|
5078
5195
|
}
|
|
5079
5196
|
if (rules.length > 0) {
|
|
5080
|
-
|
|
5197
|
+
logger.log("\n\u{1F4A1} Run 'rulesync generate' to update configuration files");
|
|
5081
5198
|
}
|
|
5082
5199
|
} catch (error) {
|
|
5083
|
-
|
|
5200
|
+
logger.error("\nFailed to get status:", error);
|
|
5084
5201
|
}
|
|
5085
5202
|
}
|
|
5086
5203
|
|
|
5087
5204
|
// src/cli/commands/validate.ts
|
|
5088
5205
|
async function validateCommand() {
|
|
5089
5206
|
const config = getDefaultConfig();
|
|
5090
|
-
|
|
5207
|
+
logger.log("Validating rulesync configuration...");
|
|
5091
5208
|
if (!await fileExists(config.aiRulesDir)) {
|
|
5092
|
-
|
|
5209
|
+
logger.error(".rulesync directory not found. Run 'rulesync init' first.");
|
|
5093
5210
|
process.exit(1);
|
|
5094
5211
|
}
|
|
5095
5212
|
try {
|
|
5096
5213
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
5097
5214
|
if (rules.length === 0) {
|
|
5098
|
-
|
|
5215
|
+
logger.warn("No rules found in .rulesync directory");
|
|
5099
5216
|
return;
|
|
5100
5217
|
}
|
|
5101
|
-
|
|
5218
|
+
logger.log(`Found ${rules.length} rule(s), validating...`);
|
|
5102
5219
|
const validation = await validateRules(rules);
|
|
5103
5220
|
if (validation.warnings.length > 0) {
|
|
5104
|
-
|
|
5221
|
+
logger.log("\n\u26A0\uFE0F Warnings:");
|
|
5105
5222
|
for (const warning of validation.warnings) {
|
|
5106
|
-
|
|
5223
|
+
logger.log(` - ${warning}`);
|
|
5107
5224
|
}
|
|
5108
5225
|
}
|
|
5109
5226
|
if (validation.errors.length > 0) {
|
|
5110
|
-
|
|
5227
|
+
logger.log("\nErrors:");
|
|
5111
5228
|
for (const error of validation.errors) {
|
|
5112
|
-
|
|
5229
|
+
logger.log(` - ${error}`);
|
|
5113
5230
|
}
|
|
5114
5231
|
}
|
|
5115
5232
|
if (validation.isValid) {
|
|
5116
|
-
|
|
5233
|
+
logger.success("\nAll rules are valid!");
|
|
5117
5234
|
} else {
|
|
5118
|
-
|
|
5119
|
-
|
|
5235
|
+
logger.log(`
|
|
5236
|
+
Validation failed with ${validation.errors.length} error(s)`);
|
|
5120
5237
|
process.exit(1);
|
|
5121
5238
|
}
|
|
5122
5239
|
} catch (error) {
|
|
5123
|
-
|
|
5240
|
+
logger.error("Failed to validate rules:", error);
|
|
5124
5241
|
process.exit(1);
|
|
5125
5242
|
}
|
|
5126
5243
|
}
|
|
@@ -5129,8 +5246,8 @@ async function validateCommand() {
|
|
|
5129
5246
|
var import_chokidar = require("chokidar");
|
|
5130
5247
|
async function watchCommand() {
|
|
5131
5248
|
const config = getDefaultConfig();
|
|
5132
|
-
|
|
5133
|
-
|
|
5249
|
+
logger.log("\u{1F440} Watching for changes in .rulesync directory...");
|
|
5250
|
+
logger.log("Press Ctrl+C to stop watching");
|
|
5134
5251
|
await generateCommand({ verbose: false });
|
|
5135
5252
|
const watcher = (0, import_chokidar.watch)(`${config.aiRulesDir}/**/*.md`, {
|
|
5136
5253
|
ignoreInitial: true,
|
|
@@ -5140,26 +5257,26 @@ async function watchCommand() {
|
|
|
5140
5257
|
const handleChange = async (path5) => {
|
|
5141
5258
|
if (isGenerating) return;
|
|
5142
5259
|
isGenerating = true;
|
|
5143
|
-
|
|
5260
|
+
logger.log(`
|
|
5144
5261
|
\u{1F4DD} Detected change in ${path5}`);
|
|
5145
5262
|
try {
|
|
5146
5263
|
await generateCommand({ verbose: false });
|
|
5147
|
-
|
|
5264
|
+
logger.success("Regenerated configuration files");
|
|
5148
5265
|
} catch (error) {
|
|
5149
|
-
|
|
5266
|
+
logger.error("Failed to regenerate:", error);
|
|
5150
5267
|
} finally {
|
|
5151
5268
|
isGenerating = false;
|
|
5152
5269
|
}
|
|
5153
5270
|
};
|
|
5154
5271
|
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (path5) => {
|
|
5155
|
-
|
|
5272
|
+
logger.log(`
|
|
5156
5273
|
\u{1F5D1}\uFE0F Removed ${path5}`);
|
|
5157
5274
|
handleChange(path5);
|
|
5158
5275
|
}).on("error", (error) => {
|
|
5159
|
-
|
|
5276
|
+
logger.error("Watcher error:", error);
|
|
5160
5277
|
});
|
|
5161
5278
|
process.on("SIGINT", () => {
|
|
5162
|
-
|
|
5279
|
+
logger.log("\n\n\u{1F44B} Stopping watcher...");
|
|
5163
5280
|
watcher.close();
|
|
5164
5281
|
process.exit(0);
|
|
5165
5282
|
});
|
|
@@ -5167,11 +5284,11 @@ async function watchCommand() {
|
|
|
5167
5284
|
|
|
5168
5285
|
// src/cli/index.ts
|
|
5169
5286
|
var program = new import_commander.Command();
|
|
5170
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
5171
|
-
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
5172
|
-
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
5287
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.63.0");
|
|
5288
|
+
program.command("init").description("Initialize rulesync in current directory").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(initCommand);
|
|
5289
|
+
program.command("add <filename>").description("Add a new rule file").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(addCommand);
|
|
5173
5290
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
5174
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("-v, --verbose", "Verbose output").action(importCommand);
|
|
5291
|
+
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("-v, --verbose", "Verbose output").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(importCommand);
|
|
5175
5292
|
program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--codexcli", "Generate only for OpenAI Codex CLI").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--windsurf", "Generate only for Windsurf").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
5176
5293
|
"-b, --base-dir <paths>",
|
|
5177
5294
|
"Base directories to generate files (comma-separated for multiple paths)"
|