rulesync 0.64.0 → 0.67.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 +87 -42
- package/dist/{amazonqcli-WVGYACHI.js → amazonqcli-PWXCSRAN.js} +2 -2
- package/dist/{augmentcode-DTHPPXWO.js → augmentcode-4AFYW4BU.js} +2 -2
- package/dist/{chunk-FVPZQEWP.js → chunk-35VMCHXQ.js} +1 -1
- package/dist/{chunk-EID75W45.js → chunk-3QGD3CH5.js} +1 -1
- package/dist/{chunk-LURFNGH4.js → chunk-5GKH5TQ4.js} +1 -1
- package/dist/{chunk-KKWJVA56.js → chunk-7BIZ5Y6F.js} +1 -1
- package/dist/{chunk-HHJIL3YZ.js → chunk-7QVQO6MQ.js} +1 -1
- package/dist/{chunk-TQOL7OKY.js → chunk-B2HD24KC.js} +1 -1
- package/dist/{chunk-LYVES5YR.js → chunk-CS7AV6JT.js} +2 -0
- package/dist/{chunk-DMTCLQ4T.js → chunk-KONQNQY3.js} +1 -1
- package/dist/{chunk-JX55DU6Y.js → chunk-OARJESSZ.js} +1 -1
- package/dist/{chunk-6LSN7HSJ.js → chunk-V36ICGOY.js} +14 -1
- package/dist/{chunk-TBXG53FV.js → chunk-WCON5BAI.js} +1 -1
- package/dist/{chunk-YPJW7Z5M.js → chunk-WFOWHPBC.js} +1 -1
- package/dist/{chunk-4NAQ5HL4.js → chunk-WYYQXVHC.js} +1 -1
- package/dist/{chunk-E2J3UBBK.js → chunk-YZUDL4GW.js} +1 -1
- package/dist/chunk-ZMGXHLYP.js +17 -0
- package/dist/{claudecode-SSYLLUXX.js → claudecode-OC7VHCF6.js} +3 -3
- package/dist/{cline-5EUGKNZ6.js → cline-A4KFSAQE.js} +3 -3
- package/dist/{codexcli-IGM2ADYK.js → codexcli-YP3X7FWB.js} +3 -3
- package/dist/{copilot-HSQO7ZCJ.js → copilot-3LIMXQ7O.js} +2 -2
- package/dist/{cursor-ZB3XNGBK.js → cursor-QV72CDJC.js} +3 -3
- package/dist/{geminicli-FNRKH5GX.js → geminicli-XPSJJS65.js} +3 -3
- package/dist/index.cjs +2048 -492
- package/dist/index.js +2006 -498
- package/dist/{junie-3YGOSOGF.js → junie-265XIW43.js} +3 -3
- package/dist/{kiro-B6WZNLY4.js → kiro-6OHFHN5X.js} +2 -2
- package/dist/{opencode-SZETJ62M.js → opencode-C5QAYVJ5.js} +2 -2
- package/dist/qwencode-5RR24UW6.js +10 -0
- package/dist/{roo-KLTWVAKE.js → roo-5IXVBUHD.js} +3 -3
- package/dist/{windsurf-IZEKUAID.js → windsurf-DVQUJJJ5.js} +3 -3
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -35,12 +35,13 @@ 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_mini, 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_mini = require("zod/mini");
|
|
43
43
|
ALL_TOOL_TARGETS = [
|
|
44
|
+
"agentsmd",
|
|
44
45
|
"amazonqcli",
|
|
45
46
|
"augmentcode",
|
|
46
47
|
"augmentcode-legacy",
|
|
@@ -50,16 +51,17 @@ var init_tool_targets = __esm({
|
|
|
50
51
|
"claudecode",
|
|
51
52
|
"codexcli",
|
|
52
53
|
"opencode",
|
|
54
|
+
"qwencode",
|
|
53
55
|
"roo",
|
|
54
56
|
"geminicli",
|
|
55
57
|
"kiro",
|
|
56
58
|
"junie",
|
|
57
59
|
"windsurf"
|
|
58
60
|
];
|
|
59
|
-
ToolTargetSchema =
|
|
60
|
-
ToolTargetsSchema =
|
|
61
|
-
WildcardTargetSchema =
|
|
62
|
-
RulesyncTargetsSchema =
|
|
61
|
+
ToolTargetSchema = import_mini.z.enum(ALL_TOOL_TARGETS);
|
|
62
|
+
ToolTargetsSchema = import_mini.z.array(ToolTargetSchema);
|
|
63
|
+
WildcardTargetSchema = import_mini.z.tuple([import_mini.z.literal("*")]);
|
|
64
|
+
RulesyncTargetsSchema = import_mini.z.union([ToolTargetsSchema, WildcardTargetSchema]);
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
|
|
@@ -161,8 +163,8 @@ async function findRuleFiles(aiRulesDir) {
|
|
|
161
163
|
newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
|
|
162
164
|
);
|
|
163
165
|
const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
|
|
164
|
-
const
|
|
165
|
-
return !newLocationBasenames.has(
|
|
166
|
+
const basename7 = file.split("/").pop()?.replace(/\.md$/, "");
|
|
167
|
+
return !newLocationBasenames.has(basename7);
|
|
166
168
|
});
|
|
167
169
|
return [...newLocationFiles, ...filteredLegacyFiles];
|
|
168
170
|
}
|
|
@@ -796,6 +798,19 @@ var init_shared_factory = __esm({
|
|
|
796
798
|
$schema: SCHEMA_URLS.OPENCODE,
|
|
797
799
|
mcp: servers
|
|
798
800
|
})
|
|
801
|
+
},
|
|
802
|
+
qwencode: {
|
|
803
|
+
target: "qwencode",
|
|
804
|
+
configPaths: [".qwen/settings.json"],
|
|
805
|
+
serverTransform: (server) => {
|
|
806
|
+
const { targets: _, ...serverConfig } = server;
|
|
807
|
+
const qwenServer = { ...serverConfig };
|
|
808
|
+
if (server.env) {
|
|
809
|
+
qwenServer.env = server.env;
|
|
810
|
+
}
|
|
811
|
+
return qwenServer;
|
|
812
|
+
},
|
|
813
|
+
configWrapper: configWrappers.mcpServers
|
|
799
814
|
}
|
|
800
815
|
};
|
|
801
816
|
cursorMcpGenerator = createMcpGenerator("cursor");
|
|
@@ -1212,6 +1227,25 @@ var init_kiro = __esm({
|
|
|
1212
1227
|
}
|
|
1213
1228
|
});
|
|
1214
1229
|
|
|
1230
|
+
// src/generators/mcp/qwencode.ts
|
|
1231
|
+
var qwencode_exports = {};
|
|
1232
|
+
__export(qwencode_exports, {
|
|
1233
|
+
generateQwenCodeMcp: () => generateQwenCodeMcp,
|
|
1234
|
+
generateQwenCodeMcpConfiguration: () => generateQwenCodeMcpConfiguration
|
|
1235
|
+
});
|
|
1236
|
+
function generateQwenCodeMcp(config) {
|
|
1237
|
+
return generateMcpFromRegistry("qwencode", config);
|
|
1238
|
+
}
|
|
1239
|
+
function generateQwenCodeMcpConfiguration(mcpServers, baseDir = "") {
|
|
1240
|
+
return generateMcpConfigurationFilesFromRegistry("qwencode", mcpServers, baseDir);
|
|
1241
|
+
}
|
|
1242
|
+
var init_qwencode = __esm({
|
|
1243
|
+
"src/generators/mcp/qwencode.ts"() {
|
|
1244
|
+
"use strict";
|
|
1245
|
+
init_shared_factory();
|
|
1246
|
+
}
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1215
1249
|
// src/generators/mcp/roo.ts
|
|
1216
1250
|
var roo_exports = {};
|
|
1217
1251
|
__export(roo_exports, {
|
|
@@ -1272,6 +1306,75 @@ var init_opencode = __esm({
|
|
|
1272
1306
|
// src/cli/index.ts
|
|
1273
1307
|
var import_commander = require("commander");
|
|
1274
1308
|
|
|
1309
|
+
// src/types/config-options.ts
|
|
1310
|
+
var import_mini2 = require("zod/mini");
|
|
1311
|
+
init_tool_targets();
|
|
1312
|
+
var FEATURE_TYPES = ["rules", "commands", "mcp", "ignore", "subagents"];
|
|
1313
|
+
var FeatureTypeSchema = import_mini2.z.enum(FEATURE_TYPES);
|
|
1314
|
+
var FeaturesSchema = import_mini2.z.union([import_mini2.z.array(FeatureTypeSchema), import_mini2.z.literal("*")]);
|
|
1315
|
+
var OutputPathsSchema = import_mini2.z.object({
|
|
1316
|
+
agentsmd: import_mini2.z.optional(import_mini2.z.string()),
|
|
1317
|
+
amazonqcli: import_mini2.z.optional(import_mini2.z.string()),
|
|
1318
|
+
augmentcode: import_mini2.z.optional(import_mini2.z.string()),
|
|
1319
|
+
"augmentcode-legacy": import_mini2.z.optional(import_mini2.z.string()),
|
|
1320
|
+
copilot: import_mini2.z.optional(import_mini2.z.string()),
|
|
1321
|
+
cursor: import_mini2.z.optional(import_mini2.z.string()),
|
|
1322
|
+
cline: import_mini2.z.optional(import_mini2.z.string()),
|
|
1323
|
+
claudecode: import_mini2.z.optional(import_mini2.z.string()),
|
|
1324
|
+
codexcli: import_mini2.z.optional(import_mini2.z.string()),
|
|
1325
|
+
opencode: import_mini2.z.optional(import_mini2.z.string()),
|
|
1326
|
+
qwencode: import_mini2.z.optional(import_mini2.z.string()),
|
|
1327
|
+
roo: import_mini2.z.optional(import_mini2.z.string()),
|
|
1328
|
+
geminicli: import_mini2.z.optional(import_mini2.z.string()),
|
|
1329
|
+
kiro: import_mini2.z.optional(import_mini2.z.string()),
|
|
1330
|
+
junie: import_mini2.z.optional(import_mini2.z.string()),
|
|
1331
|
+
windsurf: import_mini2.z.optional(import_mini2.z.string())
|
|
1332
|
+
});
|
|
1333
|
+
var ConfigOptionsSchema = import_mini2.z.object({
|
|
1334
|
+
aiRulesDir: import_mini2.z.optional(import_mini2.z.string()),
|
|
1335
|
+
outputPaths: import_mini2.z.optional(OutputPathsSchema),
|
|
1336
|
+
watchEnabled: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1337
|
+
defaultTargets: import_mini2.z.optional(ToolTargetsSchema),
|
|
1338
|
+
targets: import_mini2.z.optional(import_mini2.z.array(ToolTargetSchema)),
|
|
1339
|
+
exclude: import_mini2.z.optional(import_mini2.z.array(ToolTargetSchema)),
|
|
1340
|
+
features: import_mini2.z.optional(FeaturesSchema),
|
|
1341
|
+
verbose: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1342
|
+
delete: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1343
|
+
baseDir: import_mini2.z.optional(import_mini2.z.union([import_mini2.z.string(), import_mini2.z.array(import_mini2.z.string())])),
|
|
1344
|
+
legacy: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1345
|
+
watch: import_mini2.z.optional(
|
|
1346
|
+
import_mini2.z.object({
|
|
1347
|
+
enabled: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1348
|
+
interval: import_mini2.z.optional(import_mini2.z.number()),
|
|
1349
|
+
ignore: import_mini2.z.optional(import_mini2.z.array(import_mini2.z.string()))
|
|
1350
|
+
})
|
|
1351
|
+
)
|
|
1352
|
+
});
|
|
1353
|
+
var MergedConfigSchema = import_mini2.z.object({
|
|
1354
|
+
aiRulesDir: import_mini2.z.string(),
|
|
1355
|
+
outputPaths: import_mini2.z.record(ToolTargetSchema, import_mini2.z.string()),
|
|
1356
|
+
watchEnabled: import_mini2.z.boolean(),
|
|
1357
|
+
defaultTargets: ToolTargetsSchema,
|
|
1358
|
+
targets: import_mini2.z.optional(import_mini2.z.array(ToolTargetSchema)),
|
|
1359
|
+
exclude: import_mini2.z.optional(import_mini2.z.array(ToolTargetSchema)),
|
|
1360
|
+
features: import_mini2.z.optional(FeaturesSchema),
|
|
1361
|
+
verbose: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1362
|
+
delete: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1363
|
+
baseDir: import_mini2.z.optional(import_mini2.z.union([import_mini2.z.string(), import_mini2.z.array(import_mini2.z.string())])),
|
|
1364
|
+
configPath: import_mini2.z.optional(import_mini2.z.string()),
|
|
1365
|
+
legacy: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1366
|
+
watch: import_mini2.z.optional(
|
|
1367
|
+
import_mini2.z.object({
|
|
1368
|
+
enabled: import_mini2.z.optional(import_mini2.z.boolean()),
|
|
1369
|
+
interval: import_mini2.z.optional(import_mini2.z.number()),
|
|
1370
|
+
ignore: import_mini2.z.optional(import_mini2.z.array(import_mini2.z.string()))
|
|
1371
|
+
})
|
|
1372
|
+
)
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
// src/cli/index.ts
|
|
1376
|
+
init_logger();
|
|
1377
|
+
|
|
1275
1378
|
// src/cli/commands/add.ts
|
|
1276
1379
|
var import_promises = require("fs/promises");
|
|
1277
1380
|
var path = __toESM(require("path"), 1);
|
|
@@ -1281,101 +1384,42 @@ var import_c12 = require("c12");
|
|
|
1281
1384
|
var import_core = require("zod/v4/core");
|
|
1282
1385
|
|
|
1283
1386
|
// src/types/claudecode.ts
|
|
1284
|
-
var
|
|
1285
|
-
var ClaudeSettingsSchema =
|
|
1286
|
-
permissions:
|
|
1287
|
-
|
|
1288
|
-
deny:
|
|
1387
|
+
var import_mini3 = require("zod/mini");
|
|
1388
|
+
var ClaudeSettingsSchema = import_mini3.z.looseObject({
|
|
1389
|
+
permissions: import_mini3.z._default(
|
|
1390
|
+
import_mini3.z.looseObject({
|
|
1391
|
+
deny: import_mini3.z._default(import_mini3.z.array(import_mini3.z.string()), [])
|
|
1289
1392
|
}),
|
|
1290
1393
|
{ deny: [] }
|
|
1291
1394
|
)
|
|
1292
1395
|
});
|
|
1293
1396
|
|
|
1294
1397
|
// src/types/shared.ts
|
|
1295
|
-
var
|
|
1398
|
+
var import_mini4 = require("zod/mini");
|
|
1296
1399
|
init_tool_targets();
|
|
1297
|
-
var OutputSchema =
|
|
1400
|
+
var OutputSchema = import_mini4.z.object({
|
|
1298
1401
|
tool: ToolTargetSchema,
|
|
1299
|
-
filepath:
|
|
1300
|
-
content:
|
|
1402
|
+
filepath: import_mini4.z.string(),
|
|
1403
|
+
content: import_mini4.z.string()
|
|
1301
1404
|
});
|
|
1302
|
-
var BaseFrontmatterSchema =
|
|
1303
|
-
description:
|
|
1405
|
+
var BaseFrontmatterSchema = import_mini4.z.object({
|
|
1406
|
+
description: import_mini4.z.optional(import_mini4.z.string())
|
|
1304
1407
|
});
|
|
1305
1408
|
|
|
1306
1409
|
// src/types/commands.ts
|
|
1307
1410
|
var CommandFrontmatterSchema = BaseFrontmatterSchema;
|
|
1308
1411
|
|
|
1309
1412
|
// src/types/config.ts
|
|
1310
|
-
var import_mini4 = require("zod/mini");
|
|
1311
|
-
init_tool_targets();
|
|
1312
|
-
var ConfigSchema = import_mini4.z.object({
|
|
1313
|
-
aiRulesDir: import_mini4.z.string(),
|
|
1314
|
-
outputPaths: import_mini4.z.record(ToolTargetSchema, import_mini4.z.string()),
|
|
1315
|
-
watchEnabled: import_mini4.z.boolean(),
|
|
1316
|
-
defaultTargets: ToolTargetsSchema,
|
|
1317
|
-
claudecodeCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
1318
|
-
geminicliCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
1319
|
-
legacy: import_mini4.z.optional(import_mini4.z.boolean())
|
|
1320
|
-
});
|
|
1321
|
-
|
|
1322
|
-
// src/types/config-options.ts
|
|
1323
1413
|
var import_mini5 = require("zod/mini");
|
|
1324
1414
|
init_tool_targets();
|
|
1325
|
-
var
|
|
1326
|
-
amazonqcli: import_mini5.z.optional(import_mini5.z.string()),
|
|
1327
|
-
augmentcode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1328
|
-
"augmentcode-legacy": import_mini5.z.optional(import_mini5.z.string()),
|
|
1329
|
-
copilot: import_mini5.z.optional(import_mini5.z.string()),
|
|
1330
|
-
cursor: import_mini5.z.optional(import_mini5.z.string()),
|
|
1331
|
-
cline: import_mini5.z.optional(import_mini5.z.string()),
|
|
1332
|
-
claudecode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1333
|
-
codexcli: import_mini5.z.optional(import_mini5.z.string()),
|
|
1334
|
-
opencode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1335
|
-
roo: import_mini5.z.optional(import_mini5.z.string()),
|
|
1336
|
-
geminicli: import_mini5.z.optional(import_mini5.z.string()),
|
|
1337
|
-
kiro: import_mini5.z.optional(import_mini5.z.string()),
|
|
1338
|
-
junie: import_mini5.z.optional(import_mini5.z.string()),
|
|
1339
|
-
windsurf: import_mini5.z.optional(import_mini5.z.string())
|
|
1340
|
-
});
|
|
1341
|
-
var ConfigOptionsSchema = import_mini5.z.object({
|
|
1342
|
-
aiRulesDir: import_mini5.z.optional(import_mini5.z.string()),
|
|
1343
|
-
outputPaths: import_mini5.z.optional(OutputPathsSchema),
|
|
1344
|
-
watchEnabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1345
|
-
defaultTargets: import_mini5.z.optional(ToolTargetsSchema),
|
|
1346
|
-
targets: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
1347
|
-
exclude: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
1348
|
-
verbose: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1349
|
-
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1350
|
-
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
1351
|
-
legacy: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1352
|
-
watch: import_mini5.z.optional(
|
|
1353
|
-
import_mini5.z.object({
|
|
1354
|
-
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1355
|
-
interval: import_mini5.z.optional(import_mini5.z.number()),
|
|
1356
|
-
ignore: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
1357
|
-
})
|
|
1358
|
-
)
|
|
1359
|
-
});
|
|
1360
|
-
var MergedConfigSchema = import_mini5.z.object({
|
|
1415
|
+
var ConfigSchema = import_mini5.z.object({
|
|
1361
1416
|
aiRulesDir: import_mini5.z.string(),
|
|
1362
1417
|
outputPaths: import_mini5.z.record(ToolTargetSchema, import_mini5.z.string()),
|
|
1363
1418
|
watchEnabled: import_mini5.z.boolean(),
|
|
1364
1419
|
defaultTargets: ToolTargetsSchema,
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1369
|
-
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
1370
|
-
configPath: import_mini5.z.optional(import_mini5.z.string()),
|
|
1371
|
-
legacy: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1372
|
-
watch: import_mini5.z.optional(
|
|
1373
|
-
import_mini5.z.object({
|
|
1374
|
-
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1375
|
-
interval: import_mini5.z.optional(import_mini5.z.number()),
|
|
1376
|
-
ignore: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
1377
|
-
})
|
|
1378
|
-
)
|
|
1420
|
+
claudecodeCommands: import_mini5.z.optional(import_mini5.z.string()),
|
|
1421
|
+
geminicliCommands: import_mini5.z.optional(import_mini5.z.string()),
|
|
1422
|
+
legacy: import_mini5.z.optional(import_mini5.z.boolean())
|
|
1379
1423
|
});
|
|
1380
1424
|
|
|
1381
1425
|
// src/types/mcp.ts
|
|
@@ -1439,6 +1483,7 @@ function getDefaultConfig() {
|
|
|
1439
1483
|
return {
|
|
1440
1484
|
aiRulesDir: ".rulesync",
|
|
1441
1485
|
outputPaths: {
|
|
1486
|
+
agentsmd: ".agents/memories",
|
|
1442
1487
|
amazonqcli: ".amazonq/rules",
|
|
1443
1488
|
augmentcode: ".",
|
|
1444
1489
|
"augmentcode-legacy": ".",
|
|
@@ -1448,6 +1493,7 @@ function getDefaultConfig() {
|
|
|
1448
1493
|
claudecode: ".",
|
|
1449
1494
|
codexcli: ".",
|
|
1450
1495
|
opencode: ".",
|
|
1496
|
+
qwencode: ".qwen/memories",
|
|
1451
1497
|
roo: ".roo/rules",
|
|
1452
1498
|
geminicli: ".gemini/memories",
|
|
1453
1499
|
kiro: ".kiro/steering",
|
|
@@ -1555,6 +1601,11 @@ function generateMinimalConfig(options) {
|
|
|
1555
1601
|
if (comma) lines[lines.length - 1] += comma;
|
|
1556
1602
|
lines.push(` "exclude": ${JSON.stringify(options.exclude)}`);
|
|
1557
1603
|
}
|
|
1604
|
+
if (options.features) {
|
|
1605
|
+
const comma = lines.length > 1 ? "," : "";
|
|
1606
|
+
if (comma) lines[lines.length - 1] += comma;
|
|
1607
|
+
lines.push(` "features": ${JSON.stringify(options.features)}`);
|
|
1608
|
+
}
|
|
1558
1609
|
if (options.aiRulesDir) {
|
|
1559
1610
|
const comma = lines.length > 1 ? "," : "";
|
|
1560
1611
|
if (comma) lines[lines.length - 1] += comma;
|
|
@@ -1595,6 +1646,7 @@ function generateMinimalConfig(options) {
|
|
|
1595
1646
|
function generateSampleConfig(options) {
|
|
1596
1647
|
const targets = options?.targets || ALL_TOOL_TARGETS;
|
|
1597
1648
|
const excludeValue = options?.exclude ? JSON.stringify(options.exclude) : null;
|
|
1649
|
+
const featuresValue = options?.features || ["rules", "commands", "mcp", "ignore", "subagents"];
|
|
1598
1650
|
const aiRulesDir = options?.aiRulesDir || null;
|
|
1599
1651
|
const baseDir = options?.baseDir || null;
|
|
1600
1652
|
const deleteFlag = options?.delete || false;
|
|
@@ -1606,6 +1658,10 @@ function generateSampleConfig(options) {
|
|
|
1606
1658
|
|
|
1607
1659
|
// Tools to exclude from generation (overrides targets)
|
|
1608
1660
|
${excludeValue ? `"exclude": ${excludeValue},` : '// "exclude": ["roo"],'}
|
|
1661
|
+
|
|
1662
|
+
// Features to generate (rules, commands, mcp, ignore, subagents)
|
|
1663
|
+
// Use "*" to generate all features, or specify an array of features
|
|
1664
|
+
"features": ${JSON.stringify(featuresValue)},
|
|
1609
1665
|
${aiRulesDir ? `
|
|
1610
1666
|
// Directory containing AI rule files
|
|
1611
1667
|
"aiRulesDir": "${aiRulesDir}",` : ""}
|
|
@@ -1636,23 +1692,6 @@ function generateSampleConfig(options) {
|
|
|
1636
1692
|
}
|
|
1637
1693
|
`;
|
|
1638
1694
|
}
|
|
1639
|
-
function mergeWithCliOptions(config, cliOptions) {
|
|
1640
|
-
const merged = { ...config };
|
|
1641
|
-
if (cliOptions.verbose !== void 0) {
|
|
1642
|
-
merged.verbose = cliOptions.verbose;
|
|
1643
|
-
}
|
|
1644
|
-
if (cliOptions.delete !== void 0) {
|
|
1645
|
-
merged.delete = cliOptions.delete;
|
|
1646
|
-
}
|
|
1647
|
-
if (cliOptions.baseDirs && cliOptions.baseDirs.length > 0) {
|
|
1648
|
-
merged.baseDir = cliOptions.baseDirs;
|
|
1649
|
-
}
|
|
1650
|
-
if (cliOptions.tools && cliOptions.tools.length > 0) {
|
|
1651
|
-
merged.defaultTargets = cliOptions.tools;
|
|
1652
|
-
merged.exclude = void 0;
|
|
1653
|
-
}
|
|
1654
|
-
return merged;
|
|
1655
|
-
}
|
|
1656
1695
|
|
|
1657
1696
|
// src/cli/commands/add.ts
|
|
1658
1697
|
init_logger();
|
|
@@ -1761,6 +1800,11 @@ Default Targets: ${config.defaultTargets.join(", ")}`);
|
|
|
1761
1800
|
if (config.exclude && config.exclude.length > 0) {
|
|
1762
1801
|
logger.log(`Excluded Targets: ${config.exclude.join(", ")}`);
|
|
1763
1802
|
}
|
|
1803
|
+
if (config.features) {
|
|
1804
|
+
const featuresDisplay = config.features === "*" ? "*" : Array.isArray(config.features) ? config.features.join(", ") : String(config.features);
|
|
1805
|
+
logger.log(`
|
|
1806
|
+
Features: ${featuresDisplay}`);
|
|
1807
|
+
}
|
|
1764
1808
|
logger.log("\nOutput Paths:");
|
|
1765
1809
|
for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
|
|
1766
1810
|
logger.log(` ${tool}: ${outputPath}`);
|
|
@@ -1891,6 +1935,10 @@ const config: ConfigOptions = {
|
|
|
1891
1935
|
// Available: ${ALL_TOOL_TARGETS.join(", ")}
|
|
1892
1936
|
targets: ${JSON.stringify(ALL_TOOL_TARGETS)},
|
|
1893
1937
|
|
|
1938
|
+
// Features to generate (rules, commands, mcp, ignore, subagents)
|
|
1939
|
+
// Use "*" to generate all features, or specify an array of features
|
|
1940
|
+
features: ["rules", "commands", "mcp", "ignore", "subagents"],
|
|
1941
|
+
|
|
1894
1942
|
// Custom output paths for specific tools
|
|
1895
1943
|
// outputPaths: {
|
|
1896
1944
|
// copilot: ".github/copilot-instructions.md",
|
|
@@ -1912,6 +1960,9 @@ export default config;`;
|
|
|
1912
1960
|
if (options.exclude) {
|
|
1913
1961
|
configLines.push(` exclude: ${JSON.stringify(options.exclude)}`);
|
|
1914
1962
|
}
|
|
1963
|
+
if (options.features) {
|
|
1964
|
+
configLines.push(` features: ${JSON.stringify(options.features)}`);
|
|
1965
|
+
}
|
|
1915
1966
|
if (options.aiRulesDir) {
|
|
1916
1967
|
configLines.push(` aiRulesDir: "${options.aiRulesDir}"`);
|
|
1917
1968
|
}
|
|
@@ -1944,7 +1995,7 @@ export default config;
|
|
|
1944
1995
|
}
|
|
1945
1996
|
|
|
1946
1997
|
// src/cli/commands/generate.ts
|
|
1947
|
-
var
|
|
1998
|
+
var import_node_path18 = require("path");
|
|
1948
1999
|
|
|
1949
2000
|
// src/core/command-generator.ts
|
|
1950
2001
|
var import_node_path5 = require("path");
|
|
@@ -2213,8 +2264,475 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
2213
2264
|
return outputs;
|
|
2214
2265
|
}
|
|
2215
2266
|
|
|
2216
|
-
// src/
|
|
2267
|
+
// src/utils/feature-validator.ts
|
|
2268
|
+
function isFeatureType(value) {
|
|
2269
|
+
return FEATURE_TYPES.some((type) => type === value);
|
|
2270
|
+
}
|
|
2271
|
+
function validateFeatures(features) {
|
|
2272
|
+
if (features === void 0) {
|
|
2273
|
+
return "*";
|
|
2274
|
+
}
|
|
2275
|
+
if (features === "*") {
|
|
2276
|
+
return "*";
|
|
2277
|
+
}
|
|
2278
|
+
if (!Array.isArray(features)) {
|
|
2279
|
+
throw new Error('Features must be an array of feature names or "*"');
|
|
2280
|
+
}
|
|
2281
|
+
if (features.length === 0) {
|
|
2282
|
+
throw new Error('Features array cannot be empty. Use "*" to include all features');
|
|
2283
|
+
}
|
|
2284
|
+
const validFeatures = [];
|
|
2285
|
+
const invalidFeatures = [];
|
|
2286
|
+
for (const feature of features) {
|
|
2287
|
+
if (isFeatureType(feature)) {
|
|
2288
|
+
validFeatures.push(feature);
|
|
2289
|
+
} else {
|
|
2290
|
+
invalidFeatures.push(feature);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
if (invalidFeatures.length > 0) {
|
|
2294
|
+
throw new Error(
|
|
2295
|
+
`Invalid feature types: ${invalidFeatures.join(", ")}. Valid features are: ${FEATURE_TYPES.join(", ")}`
|
|
2296
|
+
);
|
|
2297
|
+
}
|
|
2298
|
+
return [...new Set(validFeatures)];
|
|
2299
|
+
}
|
|
2300
|
+
function expandWildcard() {
|
|
2301
|
+
return [...FEATURE_TYPES];
|
|
2302
|
+
}
|
|
2303
|
+
function normalizeFeatures(features) {
|
|
2304
|
+
if (features === "*" || features === void 0) {
|
|
2305
|
+
return expandWildcard();
|
|
2306
|
+
}
|
|
2307
|
+
return features;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// src/core/config/cli-parser.ts
|
|
2311
|
+
var CliParser = class {
|
|
2312
|
+
/**
|
|
2313
|
+
* CLI引数を解析する
|
|
2314
|
+
* @param cliOptions - 生のCLIオプション
|
|
2315
|
+
* @returns 解析されたCliOptions
|
|
2316
|
+
*/
|
|
2317
|
+
parse(cliOptions) {
|
|
2318
|
+
const parsed = {};
|
|
2319
|
+
if (cliOptions.tools && Array.isArray(cliOptions.tools) && cliOptions.tools.length > 0) {
|
|
2320
|
+
parsed.tools = cliOptions.tools;
|
|
2321
|
+
}
|
|
2322
|
+
if (cliOptions.features !== void 0) {
|
|
2323
|
+
try {
|
|
2324
|
+
parsed.features = validateFeatures(cliOptions.features);
|
|
2325
|
+
} catch (error) {
|
|
2326
|
+
throw new Error(
|
|
2327
|
+
`Invalid features: ${error instanceof Error ? error.message : String(error)}`
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
if (typeof cliOptions.verbose === "boolean") {
|
|
2332
|
+
parsed.verbose = cliOptions.verbose;
|
|
2333
|
+
}
|
|
2334
|
+
if (typeof cliOptions.delete === "boolean") {
|
|
2335
|
+
parsed.delete = cliOptions.delete;
|
|
2336
|
+
}
|
|
2337
|
+
if (cliOptions.baseDirs && Array.isArray(cliOptions.baseDirs) && cliOptions.baseDirs.length > 0) {
|
|
2338
|
+
parsed.baseDirs = cliOptions.baseDirs;
|
|
2339
|
+
}
|
|
2340
|
+
if (typeof cliOptions.config === "string") {
|
|
2341
|
+
parsed.config = cliOptions.config;
|
|
2342
|
+
}
|
|
2343
|
+
if (typeof cliOptions.noConfig === "boolean") {
|
|
2344
|
+
parsed.noConfig = cliOptions.noConfig;
|
|
2345
|
+
}
|
|
2346
|
+
return parsed;
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* CLI引数が有効かどうかを検証する
|
|
2350
|
+
* @param cliOptions - 検証するCLIオプション
|
|
2351
|
+
* @returns 検証結果
|
|
2352
|
+
*/
|
|
2353
|
+
validate(cliOptions) {
|
|
2354
|
+
const errors = [];
|
|
2355
|
+
if (cliOptions.config && cliOptions.noConfig) {
|
|
2356
|
+
errors.push("--config and --no-config cannot be used together");
|
|
2357
|
+
}
|
|
2358
|
+
if (cliOptions.baseDirs && cliOptions.baseDirs.length === 0) {
|
|
2359
|
+
errors.push("--base-dirs cannot be empty");
|
|
2360
|
+
}
|
|
2361
|
+
if (cliOptions.tools && cliOptions.tools.length === 0) {
|
|
2362
|
+
errors.push("--tools cannot be empty");
|
|
2363
|
+
}
|
|
2364
|
+
return {
|
|
2365
|
+
valid: errors.length === 0,
|
|
2366
|
+
errors
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
|
|
2371
|
+
// src/core/config/config-file-loader.ts
|
|
2217
2372
|
var import_node_path6 = require("path");
|
|
2373
|
+
var ConfigFileLoader = class {
|
|
2374
|
+
/**
|
|
2375
|
+
* 設定ファイルを読み込む
|
|
2376
|
+
* @param options - 設定ファイルの読み込みオプション
|
|
2377
|
+
* @returns 設定ファイルの読み込み結果
|
|
2378
|
+
*/
|
|
2379
|
+
async load(options = {}) {
|
|
2380
|
+
try {
|
|
2381
|
+
return await loadConfig(options);
|
|
2382
|
+
} catch (error) {
|
|
2383
|
+
throw new Error(
|
|
2384
|
+
`Failed to load configuration file: ${error instanceof Error ? error.message : String(error)}`
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
/**
|
|
2389
|
+
* 設定ファイルが存在するかどうかを確認する
|
|
2390
|
+
* @param configPath - 設定ファイルのパス
|
|
2391
|
+
* @returns ファイルが存在するかどうか
|
|
2392
|
+
*/
|
|
2393
|
+
async exists(configPath) {
|
|
2394
|
+
try {
|
|
2395
|
+
const { access } = await import("fs/promises");
|
|
2396
|
+
await access(configPath);
|
|
2397
|
+
return true;
|
|
2398
|
+
} catch {
|
|
2399
|
+
return false;
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
/**
|
|
2403
|
+
* 設定ファイルのパスを解決する
|
|
2404
|
+
* @param configPath - 指定された設定ファイルのパス
|
|
2405
|
+
* @param workingDirectory - 作業ディレクトリ
|
|
2406
|
+
* @returns 解決された設定ファイルのパス
|
|
2407
|
+
*/
|
|
2408
|
+
resolvePath(configPath, workingDirectory) {
|
|
2409
|
+
if (!configPath) {
|
|
2410
|
+
return void 0;
|
|
2411
|
+
}
|
|
2412
|
+
if ((0, import_node_path6.isAbsolute)(configPath)) {
|
|
2413
|
+
return configPath;
|
|
2414
|
+
}
|
|
2415
|
+
const baseDir = workingDirectory || process.cwd();
|
|
2416
|
+
return (0, import_node_path6.resolve)(baseDir, configPath);
|
|
2417
|
+
}
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2420
|
+
// src/core/config/config-merger.ts
|
|
2421
|
+
var ConfigMerger = class {
|
|
2422
|
+
/**
|
|
2423
|
+
* 設定ファイルとCLI引数をマージする
|
|
2424
|
+
* @param fileConfig - 設定ファイルから読み込まれた設定
|
|
2425
|
+
* @param cliOptions - CLI引数から解析された設定
|
|
2426
|
+
* @returns マージされた設定
|
|
2427
|
+
*/
|
|
2428
|
+
merge(fileConfig, cliOptions) {
|
|
2429
|
+
const merged = { ...fileConfig };
|
|
2430
|
+
if (cliOptions.verbose !== void 0) {
|
|
2431
|
+
merged.verbose = cliOptions.verbose;
|
|
2432
|
+
}
|
|
2433
|
+
if (cliOptions.delete !== void 0) {
|
|
2434
|
+
merged.delete = cliOptions.delete;
|
|
2435
|
+
}
|
|
2436
|
+
if (cliOptions.baseDirs && cliOptions.baseDirs.length > 0) {
|
|
2437
|
+
merged.baseDir = cliOptions.baseDirs;
|
|
2438
|
+
}
|
|
2439
|
+
if (cliOptions.tools && cliOptions.tools.length > 0) {
|
|
2440
|
+
merged.defaultTargets = cliOptions.tools;
|
|
2441
|
+
merged.exclude = void 0;
|
|
2442
|
+
}
|
|
2443
|
+
if (cliOptions.features !== void 0) {
|
|
2444
|
+
merged.features = cliOptions.features;
|
|
2445
|
+
}
|
|
2446
|
+
return merged;
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* 設定値のマージメタデータを生成する
|
|
2450
|
+
* @param fileConfig - 設定ファイルの設定
|
|
2451
|
+
* @param cliOptions - CLI引数の設定
|
|
2452
|
+
* @param merged - マージされた設定
|
|
2453
|
+
* @returns マージメタデータ
|
|
2454
|
+
*/
|
|
2455
|
+
generateMetadata(fileConfig, cliOptions, merged) {
|
|
2456
|
+
const metadata = {};
|
|
2457
|
+
if (merged.verbose !== void 0) {
|
|
2458
|
+
metadata.verbose = {
|
|
2459
|
+
source: cliOptions.verbose !== void 0 ? "cli_args" /* CLI_ARGS */ : "config_file" /* CONFIG_FILE */,
|
|
2460
|
+
value: merged.verbose
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
if (merged.delete !== void 0) {
|
|
2464
|
+
metadata.delete = {
|
|
2465
|
+
source: cliOptions.delete !== void 0 ? "cli_args" /* CLI_ARGS */ : "config_file" /* CONFIG_FILE */,
|
|
2466
|
+
value: merged.delete
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
if (merged.baseDir !== void 0) {
|
|
2470
|
+
metadata.baseDir = {
|
|
2471
|
+
source: cliOptions.baseDirs ? "cli_args" /* CLI_ARGS */ : "config_file" /* CONFIG_FILE */,
|
|
2472
|
+
value: merged.baseDir
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
metadata.defaultTargets = {
|
|
2476
|
+
source: cliOptions.tools ? "cli_args" /* CLI_ARGS */ : "config_file" /* CONFIG_FILE */,
|
|
2477
|
+
value: merged.defaultTargets
|
|
2478
|
+
};
|
|
2479
|
+
if (merged.exclude !== void 0) {
|
|
2480
|
+
metadata.exclude = {
|
|
2481
|
+
source: "config_file" /* CONFIG_FILE */,
|
|
2482
|
+
// excludeはCLIから直接指定されない
|
|
2483
|
+
value: merged.exclude
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
if (merged.features !== void 0) {
|
|
2487
|
+
metadata.features = {
|
|
2488
|
+
source: cliOptions.features !== void 0 ? "cli_args" /* CLI_ARGS */ : "config_file" /* CONFIG_FILE */,
|
|
2489
|
+
value: merged.features
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2492
|
+
return metadata;
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* マージされた設定を検証する
|
|
2496
|
+
* @param config - マージされた設定
|
|
2497
|
+
* @returns 検証結果
|
|
2498
|
+
*/
|
|
2499
|
+
validate(config) {
|
|
2500
|
+
const errors = [];
|
|
2501
|
+
if (!config.defaultTargets || config.defaultTargets.length === 0) {
|
|
2502
|
+
errors.push("At least one tool must be specified in targets or CLI arguments");
|
|
2503
|
+
}
|
|
2504
|
+
if (!config.aiRulesDir) {
|
|
2505
|
+
errors.push("aiRulesDir must be specified");
|
|
2506
|
+
}
|
|
2507
|
+
if (!config.outputPaths) {
|
|
2508
|
+
errors.push("outputPaths must be specified");
|
|
2509
|
+
}
|
|
2510
|
+
return {
|
|
2511
|
+
valid: errors.length === 0,
|
|
2512
|
+
errors
|
|
2513
|
+
};
|
|
2514
|
+
}
|
|
2515
|
+
};
|
|
2516
|
+
|
|
2517
|
+
// src/core/config/validators.ts
|
|
2518
|
+
var ConfigValidationError = class extends Error {
|
|
2519
|
+
constructor(message, errors) {
|
|
2520
|
+
super(message);
|
|
2521
|
+
this.errors = errors;
|
|
2522
|
+
this.name = "ConfigValidationError";
|
|
2523
|
+
}
|
|
2524
|
+
};
|
|
2525
|
+
var ConfigValidator = class {
|
|
2526
|
+
/**
|
|
2527
|
+
* CLI引数を検証する
|
|
2528
|
+
* @param cliOptions - 検証するCLI引数
|
|
2529
|
+
* @throws {ConfigValidationError} バリデーションエラーが発生した場合
|
|
2530
|
+
*/
|
|
2531
|
+
validateCliOptions(cliOptions) {
|
|
2532
|
+
const errors = [];
|
|
2533
|
+
if (cliOptions.config && cliOptions.noConfig) {
|
|
2534
|
+
errors.push("--config and --no-config cannot be used together");
|
|
2535
|
+
}
|
|
2536
|
+
if (cliOptions.baseDirs && cliOptions.baseDirs.length === 0) {
|
|
2537
|
+
errors.push("--base-dirs cannot be empty");
|
|
2538
|
+
}
|
|
2539
|
+
if (cliOptions.tools && cliOptions.tools.length === 0) {
|
|
2540
|
+
errors.push("--tools cannot be empty");
|
|
2541
|
+
}
|
|
2542
|
+
if (cliOptions.baseDirs) {
|
|
2543
|
+
for (const [index, dir] of cliOptions.baseDirs.entries()) {
|
|
2544
|
+
if (typeof dir !== "string" || dir.trim() === "") {
|
|
2545
|
+
errors.push(`Base directory at index ${index} must be a non-empty string`);
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
if (errors.length > 0) {
|
|
2550
|
+
throw new ConfigValidationError("CLI options validation failed", errors);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
/**
|
|
2554
|
+
* マージされた設定を検証する
|
|
2555
|
+
* @param config - 検証する設定
|
|
2556
|
+
* @throws {ConfigValidationError} バリデーションエラーが発生した場合
|
|
2557
|
+
*/
|
|
2558
|
+
validateMergedConfig(config) {
|
|
2559
|
+
const errors = [];
|
|
2560
|
+
if (!config.aiRulesDir || config.aiRulesDir.trim() === "") {
|
|
2561
|
+
errors.push("aiRulesDir must be specified and non-empty");
|
|
2562
|
+
}
|
|
2563
|
+
if (!config.outputPaths) {
|
|
2564
|
+
errors.push("outputPaths must be specified");
|
|
2565
|
+
}
|
|
2566
|
+
if (!config.defaultTargets || config.defaultTargets.length === 0) {
|
|
2567
|
+
errors.push("At least one tool must be specified in defaultTargets");
|
|
2568
|
+
}
|
|
2569
|
+
if (config.watchEnabled === void 0) {
|
|
2570
|
+
errors.push("watchEnabled must be specified");
|
|
2571
|
+
}
|
|
2572
|
+
if (config.baseDir !== void 0) {
|
|
2573
|
+
const dirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
2574
|
+
for (const [index, dir] of dirs.entries()) {
|
|
2575
|
+
if (typeof dir !== "string" || dir.trim() === "") {
|
|
2576
|
+
errors.push(`Base directory at index ${index} must be a non-empty string`);
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
if (config.exclude && config.defaultTargets) {
|
|
2581
|
+
const invalidExcludes = config.exclude.filter(
|
|
2582
|
+
(excludeTool) => !config.defaultTargets.includes(excludeTool)
|
|
2583
|
+
);
|
|
2584
|
+
if (invalidExcludes.length > 0) {
|
|
2585
|
+
errors.push(`Exclude contains tools not in defaultTargets: ${invalidExcludes.join(", ")}`);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
if (errors.length > 0) {
|
|
2589
|
+
throw new ConfigValidationError("Merged configuration validation failed", errors);
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
/**
|
|
2593
|
+
* 設定ファイルのパスが有効かどうかを検証する
|
|
2594
|
+
* @param configPath - 設定ファイルのパス
|
|
2595
|
+
* @throws {ConfigValidationError} パスが無効な場合
|
|
2596
|
+
*/
|
|
2597
|
+
validateConfigPath(configPath) {
|
|
2598
|
+
if (configPath !== void 0 && typeof configPath !== "string") {
|
|
2599
|
+
throw new ConfigValidationError("Configuration validation failed", [
|
|
2600
|
+
"Config path must be a string"
|
|
2601
|
+
]);
|
|
2602
|
+
}
|
|
2603
|
+
if (typeof configPath === "string" && configPath.trim() === "") {
|
|
2604
|
+
throw new ConfigValidationError("Configuration validation failed", [
|
|
2605
|
+
"Config path cannot be empty"
|
|
2606
|
+
]);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
/**
|
|
2610
|
+
* 作業ディレクトリが有効かどうかを検証する
|
|
2611
|
+
* @param workingDirectory - 作業ディレクトリのパス
|
|
2612
|
+
* @throws {ConfigValidationError} パスが無効な場合
|
|
2613
|
+
*/
|
|
2614
|
+
validateWorkingDirectory(workingDirectory) {
|
|
2615
|
+
if (workingDirectory !== void 0 && typeof workingDirectory !== "string") {
|
|
2616
|
+
throw new ConfigValidationError("Configuration validation failed", [
|
|
2617
|
+
"Working directory must be a string"
|
|
2618
|
+
]);
|
|
2619
|
+
}
|
|
2620
|
+
if (typeof workingDirectory === "string" && workingDirectory.trim() === "") {
|
|
2621
|
+
throw new ConfigValidationError("Configuration validation failed", [
|
|
2622
|
+
"Working directory cannot be empty"
|
|
2623
|
+
]);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
|
|
2628
|
+
// src/core/config/config-resolver.ts
|
|
2629
|
+
var ConfigResolver = class {
|
|
2630
|
+
cliParser;
|
|
2631
|
+
configLoader;
|
|
2632
|
+
merger;
|
|
2633
|
+
validator;
|
|
2634
|
+
constructor(cliParser, configLoader, merger, validator) {
|
|
2635
|
+
this.cliParser = cliParser || new CliParser();
|
|
2636
|
+
this.configLoader = configLoader || new ConfigFileLoader();
|
|
2637
|
+
this.merger = merger || new ConfigMerger();
|
|
2638
|
+
this.validator = validator || new ConfigValidator();
|
|
2639
|
+
}
|
|
2640
|
+
/**
|
|
2641
|
+
* 設定を解決してマージされた設定を返す
|
|
2642
|
+
* @param options - 設定解決のオプション
|
|
2643
|
+
* @returns 解決された設定と詳細情報
|
|
2644
|
+
*/
|
|
2645
|
+
async resolve(options) {
|
|
2646
|
+
try {
|
|
2647
|
+
this.validator.validateWorkingDirectory(options.workingDirectory);
|
|
2648
|
+
const parsedCliOptions = this.cliParser.parse(options.cliOptions);
|
|
2649
|
+
this.validator.validateCliOptions(parsedCliOptions);
|
|
2650
|
+
const configLoaderOptions = {
|
|
2651
|
+
cwd: options.workingDirectory || process.cwd(),
|
|
2652
|
+
...parsedCliOptions.config && { configPath: parsedCliOptions.config },
|
|
2653
|
+
...parsedCliOptions.noConfig && { noConfig: parsedCliOptions.noConfig }
|
|
2654
|
+
};
|
|
2655
|
+
this.validator.validateConfigPath(configLoaderOptions.configPath);
|
|
2656
|
+
const configResult = await this.configLoader.load(configLoaderOptions);
|
|
2657
|
+
const mergedConfig = this.merger.merge(configResult.config, parsedCliOptions);
|
|
2658
|
+
this.validator.validateMergedConfig(mergedConfig);
|
|
2659
|
+
const metadata = this.merger.generateMetadata(
|
|
2660
|
+
configResult.config,
|
|
2661
|
+
parsedCliOptions,
|
|
2662
|
+
mergedConfig
|
|
2663
|
+
);
|
|
2664
|
+
const configSource = this.determineConfigSource(configResult.isEmpty, parsedCliOptions);
|
|
2665
|
+
return {
|
|
2666
|
+
value: mergedConfig,
|
|
2667
|
+
source: configSource,
|
|
2668
|
+
metadata
|
|
2669
|
+
};
|
|
2670
|
+
} catch (error) {
|
|
2671
|
+
if (error instanceof ConfigValidationError) {
|
|
2672
|
+
throw error;
|
|
2673
|
+
}
|
|
2674
|
+
throw new Error(
|
|
2675
|
+
`Failed to resolve configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
/**
|
|
2680
|
+
* 設定の主要なソースを判定する
|
|
2681
|
+
* @param configFileEmpty - 設定ファイルが空かどうか
|
|
2682
|
+
* @param cliOptions - CLI引数
|
|
2683
|
+
* @returns 主要な設定ソース
|
|
2684
|
+
*/
|
|
2685
|
+
determineConfigSource(configFileEmpty, cliOptions) {
|
|
2686
|
+
if (cliOptions.tools || cliOptions.verbose !== void 0 || cliOptions.delete !== void 0) {
|
|
2687
|
+
return "cli_args" /* CLI_ARGS */;
|
|
2688
|
+
}
|
|
2689
|
+
if (!configFileEmpty) {
|
|
2690
|
+
return "config_file" /* CONFIG_FILE */;
|
|
2691
|
+
}
|
|
2692
|
+
return "default" /* DEFAULT */;
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* 設定解決の詳細情報を取得する(デバッグ用)
|
|
2696
|
+
* @param options - 設定解決のオプション
|
|
2697
|
+
* @returns 詳細な解決情報
|
|
2698
|
+
*/
|
|
2699
|
+
async resolveWithDetails(options) {
|
|
2700
|
+
const parsedCliOptions = this.cliParser.parse(options.cliOptions);
|
|
2701
|
+
const configLoaderOptions = {
|
|
2702
|
+
cwd: options.workingDirectory || process.cwd(),
|
|
2703
|
+
...parsedCliOptions.config && { configPath: parsedCliOptions.config },
|
|
2704
|
+
...parsedCliOptions.noConfig && { noConfig: parsedCliOptions.noConfig }
|
|
2705
|
+
};
|
|
2706
|
+
const configFileResult = await this.configLoader.load(configLoaderOptions);
|
|
2707
|
+
try {
|
|
2708
|
+
const result = await this.resolve(options);
|
|
2709
|
+
return {
|
|
2710
|
+
result,
|
|
2711
|
+
details: {
|
|
2712
|
+
parsedCliOptions,
|
|
2713
|
+
configFileResult
|
|
2714
|
+
}
|
|
2715
|
+
};
|
|
2716
|
+
} catch (error) {
|
|
2717
|
+
const validationErrors = error instanceof ConfigValidationError ? error.errors : [error instanceof Error ? error.message : String(error)];
|
|
2718
|
+
const partialConfig = this.merger.merge(configFileResult.config, parsedCliOptions);
|
|
2719
|
+
return {
|
|
2720
|
+
result: {
|
|
2721
|
+
value: partialConfig,
|
|
2722
|
+
source: this.determineConfigSource(configFileResult.isEmpty, parsedCliOptions)
|
|
2723
|
+
},
|
|
2724
|
+
details: {
|
|
2725
|
+
parsedCliOptions,
|
|
2726
|
+
configFileResult,
|
|
2727
|
+
validationErrors
|
|
2728
|
+
}
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
};
|
|
2733
|
+
|
|
2734
|
+
// src/generators/ignore/shared-factory.ts
|
|
2735
|
+
var import_node_path7 = require("path");
|
|
2218
2736
|
|
|
2219
2737
|
// src/generators/ignore/shared-helpers.ts
|
|
2220
2738
|
function extractIgnorePatternsFromRules(rules) {
|
|
@@ -2337,7 +2855,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
|
|
|
2337
2855
|
const outputs = [];
|
|
2338
2856
|
const content = generateIgnoreContent(rules, ignoreConfig);
|
|
2339
2857
|
const outputPath = baseDir || process.cwd();
|
|
2340
|
-
const filepath = (0,
|
|
2858
|
+
const filepath = (0, import_node_path7.join)(outputPath, ignoreConfig.filename);
|
|
2341
2859
|
outputs.push({
|
|
2342
2860
|
tool: ignoreConfig.tool,
|
|
2343
2861
|
filepath,
|
|
@@ -2919,17 +3437,114 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
|
2919
3437
|
return generateIgnoreFile(rules, config, ignoreConfigs.kiro, baseDir);
|
|
2920
3438
|
}
|
|
2921
3439
|
|
|
3440
|
+
// src/generators/ignore/qwencode.ts
|
|
3441
|
+
var import_node_path8 = require("path");
|
|
3442
|
+
function extractQwenCodeFileFilteringPatterns(content) {
|
|
3443
|
+
const filtering = {};
|
|
3444
|
+
const configBlocks = content.match(/```(?:json|javascript)\s*\n([\s\S]*?)\n```/g);
|
|
3445
|
+
if (configBlocks) {
|
|
3446
|
+
for (const block of configBlocks) {
|
|
3447
|
+
try {
|
|
3448
|
+
const jsonContent = block.replace(/```(?:json|javascript)\s*\n/, "").replace(/\n```$/, "");
|
|
3449
|
+
const parsed = JSON.parse(jsonContent);
|
|
3450
|
+
if (parsed.fileFiltering) {
|
|
3451
|
+
Object.assign(filtering, parsed.fileFiltering);
|
|
3452
|
+
}
|
|
3453
|
+
} catch {
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
if (content.includes("respectGitIgnore")) {
|
|
3458
|
+
if (content.includes("respectGitIgnore: false") || content.includes('"respectGitIgnore": false')) {
|
|
3459
|
+
filtering.respectGitIgnore = false;
|
|
3460
|
+
} else {
|
|
3461
|
+
filtering.respectGitIgnore = true;
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
if (content.includes("enableRecursiveFileSearch")) {
|
|
3465
|
+
if (content.includes("enableRecursiveFileSearch: false") || content.includes('"enableRecursiveFileSearch": false')) {
|
|
3466
|
+
filtering.enableRecursiveFileSearch = false;
|
|
3467
|
+
} else {
|
|
3468
|
+
filtering.enableRecursiveFileSearch = true;
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
return Object.keys(filtering).length > 0 ? filtering : void 0;
|
|
3472
|
+
}
|
|
3473
|
+
function generateQwenCodeConfiguration(rules) {
|
|
3474
|
+
const config = {};
|
|
3475
|
+
config.fileFiltering = {
|
|
3476
|
+
respectGitIgnore: true,
|
|
3477
|
+
enableRecursiveFileSearch: true
|
|
3478
|
+
};
|
|
3479
|
+
for (const rule of rules) {
|
|
3480
|
+
const ruleFiltering = extractQwenCodeFileFilteringPatterns(rule.content);
|
|
3481
|
+
if (ruleFiltering) {
|
|
3482
|
+
Object.assign(config.fileFiltering, ruleFiltering);
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
return config;
|
|
3486
|
+
}
|
|
3487
|
+
async function generateQwenCodeIgnoreFiles(rules, config, baseDir) {
|
|
3488
|
+
const outputs = [];
|
|
3489
|
+
const outputPath = baseDir || process.cwd();
|
|
3490
|
+
const qwenConfig = generateQwenCodeConfiguration(rules);
|
|
3491
|
+
const settingsPath = (0, import_node_path8.join)(outputPath, ".qwen", "settings.json");
|
|
3492
|
+
outputs.push({
|
|
3493
|
+
tool: "qwencode",
|
|
3494
|
+
filepath: settingsPath,
|
|
3495
|
+
content: `${JSON.stringify(qwenConfig, null, 2)}
|
|
3496
|
+
`
|
|
3497
|
+
});
|
|
3498
|
+
return outputs;
|
|
3499
|
+
}
|
|
3500
|
+
|
|
2922
3501
|
// src/generators/ignore/windsurf.ts
|
|
2923
3502
|
function generateWindsurfIgnore(rules, config, baseDir) {
|
|
2924
3503
|
return generateIgnoreFile(rules, config, ignoreConfigs.windsurf, baseDir);
|
|
2925
3504
|
}
|
|
2926
3505
|
|
|
3506
|
+
// src/generators/rules/agentsmd.ts
|
|
3507
|
+
init_file();
|
|
3508
|
+
async function generateAgentsMdConfig(rules, config, baseDir) {
|
|
3509
|
+
const outputs = [];
|
|
3510
|
+
const nonEmptyRules = rules.filter((rule) => rule.content.trim().length > 0);
|
|
3511
|
+
if (nonEmptyRules.length > 0) {
|
|
3512
|
+
const rootRule = nonEmptyRules.find((rule) => rule.frontmatter.root);
|
|
3513
|
+
const detailRules = nonEmptyRules.filter((rule) => !rule.frontmatter.root);
|
|
3514
|
+
if (rootRule) {
|
|
3515
|
+
const agentsPath = resolvePath("AGENTS.md", baseDir);
|
|
3516
|
+
const agentsContent = generateAgentsMarkdown(rootRule);
|
|
3517
|
+
outputs.push({
|
|
3518
|
+
tool: "agentsmd",
|
|
3519
|
+
filepath: agentsPath,
|
|
3520
|
+
content: agentsContent
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
for (const rule of detailRules) {
|
|
3524
|
+
const memoryPath = resolvePath(`.agents/memories/${rule.filename}.md`, baseDir);
|
|
3525
|
+
const memoryContent = generateMemoryMarkdown(rule);
|
|
3526
|
+
outputs.push({
|
|
3527
|
+
tool: "agentsmd",
|
|
3528
|
+
filepath: memoryPath,
|
|
3529
|
+
content: memoryContent
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
return outputs;
|
|
3534
|
+
}
|
|
3535
|
+
function generateAgentsMarkdown(rootRule) {
|
|
3536
|
+
return rootRule.content.trim();
|
|
3537
|
+
}
|
|
3538
|
+
function generateMemoryMarkdown(rule) {
|
|
3539
|
+
return rule.content.trim();
|
|
3540
|
+
}
|
|
3541
|
+
|
|
2927
3542
|
// src/generators/rules/shared-helpers.ts
|
|
2928
|
-
var
|
|
3543
|
+
var import_node_path10 = require("path");
|
|
2929
3544
|
init_file();
|
|
2930
3545
|
|
|
2931
3546
|
// src/utils/ignore.ts
|
|
2932
|
-
var
|
|
3547
|
+
var import_node_path9 = require("path");
|
|
2933
3548
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
2934
3549
|
init_file();
|
|
2935
3550
|
init_logger();
|
|
@@ -2938,7 +3553,7 @@ async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
|
2938
3553
|
if (cachedIgnorePatterns) {
|
|
2939
3554
|
return cachedIgnorePatterns;
|
|
2940
3555
|
}
|
|
2941
|
-
const ignorePath = (0,
|
|
3556
|
+
const ignorePath = (0, import_node_path9.join)(baseDir, ".rulesyncignore");
|
|
2942
3557
|
if (!await fileExists(ignorePath)) {
|
|
2943
3558
|
cachedIgnorePatterns = { patterns: [] };
|
|
2944
3559
|
return cachedIgnorePatterns;
|
|
@@ -2992,21 +3607,35 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
2992
3607
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
2993
3608
|
outputs.push({
|
|
2994
3609
|
tool,
|
|
2995
|
-
filepath: (0,
|
|
3610
|
+
filepath: (0, import_node_path10.join)(outputDir, relativePath),
|
|
2996
3611
|
content
|
|
2997
3612
|
});
|
|
2998
3613
|
}
|
|
2999
3614
|
async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
3000
3615
|
const outputs = [];
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3616
|
+
const nonEmptyRules = rules.filter((rule) => rule.content.trim().length > 0);
|
|
3617
|
+
if (nonEmptyRules.length === 0) {
|
|
3618
|
+
return outputs;
|
|
3619
|
+
}
|
|
3620
|
+
if (generatorConfig.singleFileMode && generatorConfig.fileName && generatorConfig.generateCombinedContent) {
|
|
3621
|
+
const filepath = resolvePath(generatorConfig.fileName, baseDir);
|
|
3622
|
+
const content = generatorConfig.generateCombinedContent(nonEmptyRules);
|
|
3005
3623
|
outputs.push({
|
|
3006
3624
|
tool: generatorConfig.tool,
|
|
3007
3625
|
filepath,
|
|
3008
3626
|
content
|
|
3009
3627
|
});
|
|
3628
|
+
} else if (generatorConfig.fileExtension) {
|
|
3629
|
+
for (const rule of nonEmptyRules) {
|
|
3630
|
+
const content = generatorConfig.generateContent(rule);
|
|
3631
|
+
const outputDir = resolveOutputDir(config, generatorConfig.tool, baseDir);
|
|
3632
|
+
const filepath = generatorConfig.pathResolver ? generatorConfig.pathResolver(rule, outputDir) : (0, import_node_path10.join)(outputDir, `${rule.filename}${generatorConfig.fileExtension}`);
|
|
3633
|
+
outputs.push({
|
|
3634
|
+
tool: generatorConfig.tool,
|
|
3635
|
+
filepath,
|
|
3636
|
+
content
|
|
3637
|
+
});
|
|
3638
|
+
}
|
|
3010
3639
|
}
|
|
3011
3640
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
3012
3641
|
if (ignorePatterns.patterns.length > 0 && generatorConfig.ignoreFileName) {
|
|
@@ -3029,7 +3658,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
3029
3658
|
for (const rule of detailRules) {
|
|
3030
3659
|
const content = generatorConfig.generateDetailContent(rule);
|
|
3031
3660
|
const filepath = resolvePath(
|
|
3032
|
-
(0,
|
|
3661
|
+
(0, import_node_path10.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
3033
3662
|
baseDir
|
|
3034
3663
|
);
|
|
3035
3664
|
outputs.push({
|
|
@@ -3137,7 +3766,7 @@ function generateRuleFile(rule) {
|
|
|
3137
3766
|
}
|
|
3138
3767
|
|
|
3139
3768
|
// src/generators/rules/augmentcode.ts
|
|
3140
|
-
var
|
|
3769
|
+
var import_node_path11 = require("path");
|
|
3141
3770
|
async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
3142
3771
|
const outputs = createOutputsArray();
|
|
3143
3772
|
rules.forEach((rule) => {
|
|
@@ -3146,7 +3775,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
3146
3775
|
"augmentcode",
|
|
3147
3776
|
config,
|
|
3148
3777
|
baseDir,
|
|
3149
|
-
(0,
|
|
3778
|
+
(0, import_node_path11.join)(".augment", "rules", `${rule.filename}.md`),
|
|
3150
3779
|
generateRuleFile2(rule)
|
|
3151
3780
|
);
|
|
3152
3781
|
});
|
|
@@ -3199,7 +3828,7 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
3199
3828
|
}
|
|
3200
3829
|
|
|
3201
3830
|
// src/generators/rules/claudecode.ts
|
|
3202
|
-
var
|
|
3831
|
+
var import_node_path12 = require("path");
|
|
3203
3832
|
init_file();
|
|
3204
3833
|
init_logger();
|
|
3205
3834
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
@@ -3213,7 +3842,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
3213
3842
|
generateDetailContent: generateMemoryFile,
|
|
3214
3843
|
detailSubDir: ".claude/memories",
|
|
3215
3844
|
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
3216
|
-
const settingsPath = resolvePath((0,
|
|
3845
|
+
const settingsPath = resolvePath((0, import_node_path12.join)(".claude", "settings.json"), baseDir2);
|
|
3217
3846
|
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
3218
3847
|
return [];
|
|
3219
3848
|
}
|
|
@@ -3277,7 +3906,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
3277
3906
|
}
|
|
3278
3907
|
|
|
3279
3908
|
// src/generators/rules/generator-registry.ts
|
|
3280
|
-
var
|
|
3909
|
+
var import_node_path13 = require("path");
|
|
3281
3910
|
function determineCursorRuleType(frontmatter) {
|
|
3282
3911
|
if (frontmatter.cursorRuleType) {
|
|
3283
3912
|
return frontmatter.cursorRuleType;
|
|
@@ -3301,6 +3930,15 @@ function determineCursorRuleType(frontmatter) {
|
|
|
3301
3930
|
}
|
|
3302
3931
|
var GENERATOR_REGISTRY = {
|
|
3303
3932
|
// Simple generators - generate one file per rule
|
|
3933
|
+
agentsmd: {
|
|
3934
|
+
type: "complex",
|
|
3935
|
+
tool: "agentsmd",
|
|
3936
|
+
fileExtension: ".md",
|
|
3937
|
+
ignoreFileName: ".agentsignore",
|
|
3938
|
+
generateContent: (rule) => rule.content.trim()
|
|
3939
|
+
// NOTE: AGENTS.md specific logic is handled in the actual generator file
|
|
3940
|
+
// Root rule goes to AGENTS.md, detail rules go to .agents/memories/
|
|
3941
|
+
},
|
|
3304
3942
|
amazonqcli: {
|
|
3305
3943
|
type: "complex",
|
|
3306
3944
|
tool: "amazonqcli",
|
|
@@ -3373,7 +4011,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3373
4011
|
},
|
|
3374
4012
|
pathResolver: (rule, outputDir) => {
|
|
3375
4013
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
3376
|
-
return (0,
|
|
4014
|
+
return (0, import_node_path13.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
3377
4015
|
}
|
|
3378
4016
|
},
|
|
3379
4017
|
cursor: {
|
|
@@ -3413,7 +4051,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3413
4051
|
return lines.join("\n");
|
|
3414
4052
|
},
|
|
3415
4053
|
pathResolver: (rule, outputDir) => {
|
|
3416
|
-
return (0,
|
|
4054
|
+
return (0, import_node_path13.join)(outputDir, `${rule.filename}.mdc`);
|
|
3417
4055
|
}
|
|
3418
4056
|
},
|
|
3419
4057
|
codexcli: {
|
|
@@ -3449,10 +4087,10 @@ var GENERATOR_REGISTRY = {
|
|
|
3449
4087
|
pathResolver: (rule, outputDir) => {
|
|
3450
4088
|
const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
|
|
3451
4089
|
if (outputFormat === "single-file") {
|
|
3452
|
-
return (0,
|
|
4090
|
+
return (0, import_node_path13.join)(outputDir, ".windsurf-rules");
|
|
3453
4091
|
} else {
|
|
3454
|
-
const rulesDir = (0,
|
|
3455
|
-
return (0,
|
|
4092
|
+
const rulesDir = (0, import_node_path13.join)(outputDir, ".windsurf", "rules");
|
|
4093
|
+
return (0, import_node_path13.join)(rulesDir, `${rule.filename}.md`);
|
|
3456
4094
|
}
|
|
3457
4095
|
}
|
|
3458
4096
|
},
|
|
@@ -3515,6 +4153,22 @@ var GENERATOR_REGISTRY = {
|
|
|
3515
4153
|
const lines = [];
|
|
3516
4154
|
if (rule.frontmatter.description) {
|
|
3517
4155
|
lines.push(`# ${rule.frontmatter.description}
|
|
4156
|
+
`);
|
|
4157
|
+
}
|
|
4158
|
+
lines.push(rule.content.trim());
|
|
4159
|
+
return lines.join("\n");
|
|
4160
|
+
}
|
|
4161
|
+
// Complex generation handled by existing generator
|
|
4162
|
+
},
|
|
4163
|
+
qwencode: {
|
|
4164
|
+
type: "complex",
|
|
4165
|
+
tool: "qwencode",
|
|
4166
|
+
fileExtension: ".md",
|
|
4167
|
+
// ignoreFileName omitted - Qwen Code uses git-aware filtering instead of dedicated ignore files
|
|
4168
|
+
generateContent: (rule) => {
|
|
4169
|
+
const lines = [];
|
|
4170
|
+
if (rule.frontmatter.description) {
|
|
4171
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
3518
4172
|
`);
|
|
3519
4173
|
}
|
|
3520
4174
|
lines.push(rule.content.trim());
|
|
@@ -3571,9 +4225,60 @@ var generateCopilotConfig = createSimpleGenerator("copilot");
|
|
|
3571
4225
|
var generateWindsurfConfig = createSimpleGenerator("windsurf");
|
|
3572
4226
|
var generateKiroConfig = createSimpleGenerator("kiro");
|
|
3573
4227
|
var generateRooConfig = createSimpleGenerator("roo");
|
|
4228
|
+
var generateQwencodeConfig = createSimpleGenerator("qwencode");
|
|
4229
|
+
|
|
4230
|
+
// src/generators/rules/base-generator.ts
|
|
4231
|
+
async function generateBaseRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
4232
|
+
const unifiedConfig = {
|
|
4233
|
+
tool: generatorConfig.tool,
|
|
4234
|
+
fileName: generatorConfig.fileName,
|
|
4235
|
+
...generatorConfig.ignoreFileName ? { ignoreFileName: generatorConfig.ignoreFileName } : {},
|
|
4236
|
+
singleFileMode: true,
|
|
4237
|
+
generateCombinedContent: generatorConfig.generateContent,
|
|
4238
|
+
generateContent: () => ""
|
|
4239
|
+
// Not used in single file mode
|
|
4240
|
+
};
|
|
4241
|
+
return generateRulesConfig(rules, config, unifiedConfig, baseDir);
|
|
4242
|
+
}
|
|
4243
|
+
function categorizeRules(rules) {
|
|
4244
|
+
return rules.reduce(
|
|
4245
|
+
(acc, rule) => {
|
|
4246
|
+
if (rule.frontmatter.root) {
|
|
4247
|
+
acc.root.push(rule);
|
|
4248
|
+
} else {
|
|
4249
|
+
acc.detail.push(rule);
|
|
4250
|
+
}
|
|
4251
|
+
return acc;
|
|
4252
|
+
},
|
|
4253
|
+
{ root: [], detail: [] }
|
|
4254
|
+
);
|
|
4255
|
+
}
|
|
4256
|
+
function generateMarkdownContent(rules) {
|
|
4257
|
+
const sections = [];
|
|
4258
|
+
const categorized = categorizeRules(rules);
|
|
4259
|
+
if (categorized.root.length > 0) {
|
|
4260
|
+
sections.push(...categorized.root.map((rule) => rule.content.trim()));
|
|
4261
|
+
}
|
|
4262
|
+
if (categorized.detail.length > 0) {
|
|
4263
|
+
sections.push(...categorized.detail.map((rule) => rule.content.trim()));
|
|
4264
|
+
}
|
|
4265
|
+
return sections.join("\n\n").trim();
|
|
4266
|
+
}
|
|
3574
4267
|
|
|
3575
4268
|
// src/generators/rules/codexcli.ts
|
|
3576
|
-
|
|
4269
|
+
async function generateCodexConfig(rules, config, baseDir) {
|
|
4270
|
+
return generateBaseRulesConfig(
|
|
4271
|
+
rules,
|
|
4272
|
+
config,
|
|
4273
|
+
{
|
|
4274
|
+
fileName: "AGENTS.md",
|
|
4275
|
+
ignoreFileName: ".codexignore",
|
|
4276
|
+
generateContent: generateMarkdownContent,
|
|
4277
|
+
tool: "codexcli"
|
|
4278
|
+
},
|
|
4279
|
+
baseDir
|
|
4280
|
+
);
|
|
4281
|
+
}
|
|
3577
4282
|
|
|
3578
4283
|
// src/utils/xml-document-generator.ts
|
|
3579
4284
|
var import_fast_xml_parser = require("fast-xml-parser");
|
|
@@ -3619,47 +4324,6 @@ function generateRootMarkdownWithXmlDocs(rootRule, memoryRules, config) {
|
|
|
3619
4324
|
return lines.join("\n");
|
|
3620
4325
|
}
|
|
3621
4326
|
|
|
3622
|
-
// src/generators/rules/codexcli.ts
|
|
3623
|
-
async function generateCodexConfig(rules, config, baseDir) {
|
|
3624
|
-
const outputs = [];
|
|
3625
|
-
const nonEmptyRules = rules.filter((rule) => rule.content.trim().length > 0);
|
|
3626
|
-
if (nonEmptyRules.length > 0) {
|
|
3627
|
-
const generatorConfig = {
|
|
3628
|
-
tool: "codexcli",
|
|
3629
|
-
fileExtension: ".md",
|
|
3630
|
-
ignoreFileName: ".codexignore",
|
|
3631
|
-
generateContent: generateCodexMemoryMarkdown,
|
|
3632
|
-
generateDetailContent: generateCodexMemoryMarkdown,
|
|
3633
|
-
generateRootContent: generateCodexRootMarkdown,
|
|
3634
|
-
rootFilePath: "AGENTS.md",
|
|
3635
|
-
detailSubDir: ".codex/memories"
|
|
3636
|
-
};
|
|
3637
|
-
const ruleOutputs = await generateComplexRules(nonEmptyRules, config, generatorConfig, baseDir);
|
|
3638
|
-
outputs.push(...ruleOutputs);
|
|
3639
|
-
} else {
|
|
3640
|
-
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
3641
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
3642
|
-
const ignorePath = resolvePath(".codexignore", baseDir);
|
|
3643
|
-
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, "codexcli");
|
|
3644
|
-
outputs.push({
|
|
3645
|
-
tool: "codexcli",
|
|
3646
|
-
filepath: ignorePath,
|
|
3647
|
-
content: ignoreContent
|
|
3648
|
-
});
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
|
-
return outputs;
|
|
3652
|
-
}
|
|
3653
|
-
function generateCodexMemoryMarkdown(rule) {
|
|
3654
|
-
return rule.content.trim();
|
|
3655
|
-
}
|
|
3656
|
-
function generateCodexRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
3657
|
-
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
3658
|
-
memorySubDir: ".codex/memories",
|
|
3659
|
-
fallbackTitle: "OpenAI Codex CLI Configuration"
|
|
3660
|
-
});
|
|
3661
|
-
}
|
|
3662
|
-
|
|
3663
4327
|
// src/generators/rules/geminicli.ts
|
|
3664
4328
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
3665
4329
|
const generatorConfig = {
|
|
@@ -3717,21 +4381,39 @@ async function generateOpenCodeConfig(rules, config, baseDir) {
|
|
|
3717
4381
|
tool: "opencode",
|
|
3718
4382
|
fileExtension: ".md",
|
|
3719
4383
|
// ignoreFileName omitted - OpenCode doesn't use dedicated ignore files
|
|
3720
|
-
generateContent:
|
|
3721
|
-
generateDetailContent:
|
|
3722
|
-
generateRootContent:
|
|
4384
|
+
generateContent: (rule) => rule.content.trim(),
|
|
4385
|
+
generateDetailContent: (rule) => rule.content.trim(),
|
|
4386
|
+
generateRootContent: (rootRule, memoryRules) => generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
4387
|
+
memorySubDir: ".opencode/memories",
|
|
4388
|
+
fallbackTitle: "OpenCode Configuration"
|
|
4389
|
+
}),
|
|
3723
4390
|
rootFilePath: "AGENTS.md",
|
|
3724
4391
|
detailSubDir: ".opencode/memories"
|
|
3725
4392
|
};
|
|
3726
4393
|
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
3727
4394
|
}
|
|
3728
|
-
|
|
4395
|
+
|
|
4396
|
+
// src/generators/rules/qwencode.ts
|
|
4397
|
+
async function generateQwencodeConfig2(rules, config, baseDir) {
|
|
4398
|
+
const generatorConfig = {
|
|
4399
|
+
tool: "qwencode",
|
|
4400
|
+
fileExtension: ".md",
|
|
4401
|
+
// ignoreFileName omitted - Qwen Code uses git-aware filtering instead of dedicated ignore files
|
|
4402
|
+
generateContent: generateQwenMemoryMarkdown,
|
|
4403
|
+
generateDetailContent: generateQwenMemoryMarkdown,
|
|
4404
|
+
generateRootContent: generateQwenRootMarkdown,
|
|
4405
|
+
rootFilePath: "QWEN.md",
|
|
4406
|
+
detailSubDir: ".qwen/memories"
|
|
4407
|
+
};
|
|
4408
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
4409
|
+
}
|
|
4410
|
+
function generateQwenMemoryMarkdown(rule) {
|
|
3729
4411
|
return rule.content.trim();
|
|
3730
4412
|
}
|
|
3731
|
-
function
|
|
4413
|
+
function generateQwenRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
3732
4414
|
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
3733
|
-
memorySubDir: ".
|
|
3734
|
-
fallbackTitle: "
|
|
4415
|
+
memorySubDir: ".qwen/memories",
|
|
4416
|
+
fallbackTitle: "Qwen Code Configuration"
|
|
3735
4417
|
});
|
|
3736
4418
|
}
|
|
3737
4419
|
|
|
@@ -3768,6 +4450,8 @@ function filterRulesForTool(rules, tool, config) {
|
|
|
3768
4450
|
}
|
|
3769
4451
|
async function generateForTool(tool, rules, config, baseDir) {
|
|
3770
4452
|
switch (tool) {
|
|
4453
|
+
case "agentsmd":
|
|
4454
|
+
return await generateAgentsMdConfig(rules, config, baseDir);
|
|
3771
4455
|
case "amazonqcli":
|
|
3772
4456
|
return await generateAmazonqcliConfig(rules, config, baseDir);
|
|
3773
4457
|
case "augmentcode": {
|
|
@@ -3810,6 +4494,11 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
3810
4494
|
}
|
|
3811
4495
|
case "opencode":
|
|
3812
4496
|
return generateOpenCodeConfig(rules, config, baseDir);
|
|
4497
|
+
case "qwencode": {
|
|
4498
|
+
const qwenRulesOutputs = await generateQwencodeConfig2(rules, config, baseDir);
|
|
4499
|
+
const qwenIgnoreOutputs = await generateQwenCodeIgnoreFiles(rules, config, baseDir);
|
|
4500
|
+
return [...qwenRulesOutputs, ...qwenIgnoreOutputs];
|
|
4501
|
+
}
|
|
3813
4502
|
case "windsurf": {
|
|
3814
4503
|
const windsurfRulesOutputs = await generateWindsurfConfig(rules, config, baseDir);
|
|
3815
4504
|
const windsurfIgnoreOutputs = await generateWindsurfIgnore(rules, config, baseDir);
|
|
@@ -3822,7 +4511,7 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
3822
4511
|
}
|
|
3823
4512
|
|
|
3824
4513
|
// src/core/parser.ts
|
|
3825
|
-
var
|
|
4514
|
+
var import_node_path14 = require("path");
|
|
3826
4515
|
init_logger();
|
|
3827
4516
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
3828
4517
|
const ignorePatterns = await loadIgnorePatterns();
|
|
@@ -3876,7 +4565,7 @@ async function parseRuleFile(filepath) {
|
|
|
3876
4565
|
},
|
|
3877
4566
|
...validatedData.tags !== void 0 && { tags: validatedData.tags }
|
|
3878
4567
|
};
|
|
3879
|
-
const filename = (0,
|
|
4568
|
+
const filename = (0, import_node_path14.basename)(filepath, ".md");
|
|
3880
4569
|
return {
|
|
3881
4570
|
frontmatter,
|
|
3882
4571
|
content: parsed.content,
|
|
@@ -3954,6 +4643,7 @@ init_cursor();
|
|
|
3954
4643
|
init_geminicli();
|
|
3955
4644
|
init_junie();
|
|
3956
4645
|
init_kiro();
|
|
4646
|
+
init_qwencode();
|
|
3957
4647
|
init_roo();
|
|
3958
4648
|
init_windsurf();
|
|
3959
4649
|
|
|
@@ -3991,10 +4681,12 @@ function parseMcpConfig(projectRoot) {
|
|
|
3991
4681
|
async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
3992
4682
|
const outputs = [];
|
|
3993
4683
|
const toolMap = {
|
|
4684
|
+
agentsmd: async () => [],
|
|
3994
4685
|
amazonqcli: async (servers, dir) => {
|
|
3995
4686
|
const config = {
|
|
3996
4687
|
aiRulesDir: ".rulesync",
|
|
3997
4688
|
outputPaths: {
|
|
4689
|
+
agentsmd: ".agents/memories",
|
|
3998
4690
|
amazonqcli: ".amazonq/rules",
|
|
3999
4691
|
augmentcode: ".",
|
|
4000
4692
|
"augmentcode-legacy": ".",
|
|
@@ -4004,6 +4696,7 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
|
4004
4696
|
claudecode: ".",
|
|
4005
4697
|
codexcli: ".",
|
|
4006
4698
|
opencode: ".",
|
|
4699
|
+
qwencode: ".qwen/memories",
|
|
4007
4700
|
roo: ".roo/rules",
|
|
4008
4701
|
geminicli: ".gemini/memories",
|
|
4009
4702
|
kiro: ".kiro/steering",
|
|
@@ -4047,6 +4740,10 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
|
4047
4740
|
),
|
|
4048
4741
|
kiro: async (servers, dir) => (await Promise.resolve().then(() => (init_kiro(), kiro_exports))).generateKiroMcpConfiguration(servers, dir),
|
|
4049
4742
|
junie: async (servers, dir) => (await Promise.resolve().then(() => (init_junie(), junie_exports))).generateJunieMcpConfiguration(servers, dir),
|
|
4743
|
+
qwencode: async (servers, dir) => (await Promise.resolve().then(() => (init_qwencode(), qwencode_exports))).generateQwenCodeMcpConfiguration(
|
|
4744
|
+
servers,
|
|
4745
|
+
dir
|
|
4746
|
+
),
|
|
4050
4747
|
windsurf: async (servers, dir) => (await Promise.resolve().then(() => (init_windsurf(), windsurf_exports))).generateWindsurfMcpConfiguration(
|
|
4051
4748
|
servers,
|
|
4052
4749
|
dir
|
|
@@ -4068,223 +4765,594 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
|
4068
4765
|
return outputs;
|
|
4069
4766
|
}
|
|
4070
4767
|
|
|
4071
|
-
// src/
|
|
4768
|
+
// src/core/subagent-generator.ts
|
|
4769
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
4770
|
+
|
|
4771
|
+
// src/generators/subagents/claudecode.ts
|
|
4072
4772
|
init_logger();
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
logger.
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4773
|
+
|
|
4774
|
+
// src/generators/subagents/base.ts
|
|
4775
|
+
var import_node_path15 = __toESM(require("path"), 1);
|
|
4776
|
+
init_file();
|
|
4777
|
+
init_logger();
|
|
4778
|
+
var BaseSubagentGenerator = class {
|
|
4779
|
+
/**
|
|
4780
|
+
* Generate subagent files for the tool
|
|
4781
|
+
*/
|
|
4782
|
+
async generate(rules, config, baseDir, parsedSubagents) {
|
|
4783
|
+
const toolName = this.getToolName();
|
|
4784
|
+
const agentsDir = this.getAgentsDirectory();
|
|
4785
|
+
const outputs = [];
|
|
4786
|
+
try {
|
|
4787
|
+
const outputDir = resolvePath(
|
|
4788
|
+
import_node_path15.default.join(config.outputPaths[toolName] ?? "", agentsDir),
|
|
4789
|
+
baseDir
|
|
4790
|
+
);
|
|
4791
|
+
await ensureDir(outputDir);
|
|
4792
|
+
let subagentOutputs;
|
|
4793
|
+
if (parsedSubagents && parsedSubagents.length > 0) {
|
|
4794
|
+
logger.debug(
|
|
4795
|
+
`Generating ${parsedSubagents.length} subagents from parsed data for ${toolName}`
|
|
4796
|
+
);
|
|
4797
|
+
subagentOutputs = this.generateFromParsedSubagents(parsedSubagents);
|
|
4798
|
+
} else {
|
|
4799
|
+
logger.debug(`Generating subagents from rules for ${toolName}`);
|
|
4800
|
+
subagentOutputs = this.generateFromRules(rules);
|
|
4801
|
+
}
|
|
4802
|
+
for (const subagent of subagentOutputs) {
|
|
4803
|
+
const filePath = import_node_path15.default.join(outputDir, subagent.filename);
|
|
4804
|
+
outputs.push({
|
|
4805
|
+
tool: toolName,
|
|
4806
|
+
filepath: filePath,
|
|
4807
|
+
content: subagent.content
|
|
4808
|
+
});
|
|
4809
|
+
}
|
|
4810
|
+
if (outputs.length > 0) {
|
|
4811
|
+
logger.info(`Generated ${outputs.length} subagent files for ${toolName}`);
|
|
4812
|
+
} else {
|
|
4813
|
+
logger.debug(`No subagents generated for ${toolName}`);
|
|
4814
|
+
}
|
|
4815
|
+
return outputs;
|
|
4816
|
+
} catch (error) {
|
|
4817
|
+
logger.error(`Error generating subagents for ${toolName}:`, error);
|
|
4818
|
+
return [];
|
|
4819
|
+
}
|
|
4116
4820
|
}
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4821
|
+
};
|
|
4822
|
+
|
|
4823
|
+
// src/generators/subagents/claudecode.ts
|
|
4824
|
+
var ClaudeCodeSubagentGenerator = class extends BaseSubagentGenerator {
|
|
4825
|
+
getToolName() {
|
|
4826
|
+
return "claudecode";
|
|
4827
|
+
}
|
|
4828
|
+
getAgentsDirectory() {
|
|
4829
|
+
return ".claude/agents";
|
|
4830
|
+
}
|
|
4831
|
+
generateFromRules(_rules) {
|
|
4832
|
+
logger.debug("Skipping rule-to-subagent conversion (deprecated behavior)");
|
|
4833
|
+
return [];
|
|
4834
|
+
}
|
|
4835
|
+
generateFromParsedSubagents(subagents) {
|
|
4836
|
+
return subagents.map((subagent) => {
|
|
4837
|
+
const frontmatterLines = ["---"];
|
|
4838
|
+
frontmatterLines.push(`name: ${subagent.frontmatter.name}`);
|
|
4839
|
+
frontmatterLines.push(`description: ${subagent.frontmatter.description}`);
|
|
4840
|
+
if (subagent.frontmatter.claudecode?.model) {
|
|
4841
|
+
frontmatterLines.push(`model: ${subagent.frontmatter.claudecode.model}`);
|
|
4842
|
+
}
|
|
4843
|
+
frontmatterLines.push("---");
|
|
4844
|
+
const content = `${frontmatterLines.join("\n")}
|
|
4845
|
+
|
|
4846
|
+
${subagent.content}`;
|
|
4847
|
+
return {
|
|
4848
|
+
filename: `${subagent.filename}.md`,
|
|
4849
|
+
content
|
|
4850
|
+
};
|
|
4851
|
+
});
|
|
4852
|
+
}
|
|
4853
|
+
processContent(subagent) {
|
|
4854
|
+
const frontmatterLines = ["---"];
|
|
4855
|
+
frontmatterLines.push(`name: ${subagent.frontmatter.name}`);
|
|
4856
|
+
frontmatterLines.push(`description: ${subagent.frontmatter.description}`);
|
|
4857
|
+
if (subagent.frontmatter.claudecode?.model) {
|
|
4858
|
+
frontmatterLines.push(`model: ${subagent.frontmatter.claudecode.model}`);
|
|
4859
|
+
}
|
|
4860
|
+
frontmatterLines.push("---");
|
|
4861
|
+
return `${frontmatterLines.join("\n")}
|
|
4862
|
+
|
|
4863
|
+
${subagent.content}`;
|
|
4864
|
+
}
|
|
4865
|
+
};
|
|
4866
|
+
|
|
4867
|
+
// src/parsers/subagent-parser.ts
|
|
4868
|
+
var import_promises3 = require("fs/promises");
|
|
4869
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
4870
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
4871
|
+
|
|
4872
|
+
// src/types/subagent.ts
|
|
4873
|
+
var import_mini8 = require("zod/mini");
|
|
4874
|
+
var ClaudeCodeConfigSchema = import_mini8.z.object({
|
|
4875
|
+
model: import_mini8.z.optional(import_mini8.z.string())
|
|
4876
|
+
});
|
|
4877
|
+
var SubagentFrontmatterSchema = import_mini8.z.object({
|
|
4878
|
+
name: import_mini8.z.string(),
|
|
4879
|
+
description: import_mini8.z.string(),
|
|
4880
|
+
targets: import_mini8.z.optional(import_mini8.z.array(import_mini8.z.string())),
|
|
4881
|
+
// Tool-specific configurations
|
|
4882
|
+
claudecode: import_mini8.z.optional(ClaudeCodeConfigSchema)
|
|
4883
|
+
});
|
|
4884
|
+
|
|
4885
|
+
// src/parsers/subagent-parser.ts
|
|
4886
|
+
init_file();
|
|
4887
|
+
init_logger();
|
|
4888
|
+
async function parseSubagentFile(filepath) {
|
|
4889
|
+
try {
|
|
4890
|
+
const fileContent = await (0, import_promises3.readFile)(filepath, "utf-8");
|
|
4891
|
+
const { data: frontmatter, content } = (0, import_gray_matter2.default)(fileContent);
|
|
4892
|
+
const result = SubagentFrontmatterSchema.safeParse(frontmatter);
|
|
4893
|
+
if (!result.success) {
|
|
4894
|
+
logger.warn(`Invalid frontmatter in ${filepath}: ${result.error.message}`);
|
|
4895
|
+
return null;
|
|
4896
|
+
}
|
|
4897
|
+
const parsedFrontmatter = result.data;
|
|
4898
|
+
if (!parsedFrontmatter.targets) {
|
|
4899
|
+
parsedFrontmatter.targets = ["*"];
|
|
4900
|
+
}
|
|
4901
|
+
const filename = import_node_path16.default.basename(filepath, import_node_path16.default.extname(filepath));
|
|
4902
|
+
return {
|
|
4903
|
+
frontmatter: parsedFrontmatter,
|
|
4904
|
+
content: content.trim(),
|
|
4905
|
+
filename,
|
|
4906
|
+
filepath
|
|
4907
|
+
};
|
|
4908
|
+
} catch (error) {
|
|
4909
|
+
logger.error(`Error parsing subagent file ${filepath}:`, error);
|
|
4910
|
+
return null;
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
async function parseSubagentsFromDirectory(agentsDir) {
|
|
4914
|
+
try {
|
|
4915
|
+
if (!await fileExists(agentsDir)) {
|
|
4916
|
+
logger.debug(`Agents directory does not exist: ${agentsDir}`);
|
|
4917
|
+
return [];
|
|
4918
|
+
}
|
|
4919
|
+
const entries = await (0, import_promises3.readdir)(agentsDir);
|
|
4920
|
+
const mdFiles = entries.filter((file) => file.endsWith(".md"));
|
|
4921
|
+
const files = mdFiles.map((file) => import_node_path16.default.join(agentsDir, file));
|
|
4922
|
+
if (files.length === 0) {
|
|
4923
|
+
logger.debug(`No subagent files found in ${agentsDir}`);
|
|
4924
|
+
return [];
|
|
4925
|
+
}
|
|
4926
|
+
logger.debug(`Found ${files.length} subagent files in ${agentsDir}`);
|
|
4927
|
+
const parsePromises = files.map((file) => parseSubagentFile(file));
|
|
4928
|
+
const results = await Promise.all(parsePromises);
|
|
4929
|
+
const subagents = results.filter((result) => result !== null);
|
|
4930
|
+
logger.info(`Successfully parsed ${subagents.length} subagents`);
|
|
4931
|
+
return subagents;
|
|
4932
|
+
} catch (error) {
|
|
4933
|
+
logger.error(`Error parsing subagents from directory ${agentsDir}:`, error);
|
|
4934
|
+
return [];
|
|
4122
4935
|
}
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
// src/core/subagent-generator.ts
|
|
4939
|
+
init_logger();
|
|
4940
|
+
async function generateSubagents(rulesyncDir, outputDir, tools, rules) {
|
|
4941
|
+
const outputs = [];
|
|
4942
|
+
const subagentsDir = import_node_path17.default.join(rulesyncDir, "subagents");
|
|
4943
|
+
let parsedSubagents = [];
|
|
4123
4944
|
try {
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
logger.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
4128
|
-
return;
|
|
4945
|
+
parsedSubagents = await parseSubagentsFromDirectory(subagentsDir);
|
|
4946
|
+
if (parsedSubagents.length > 0) {
|
|
4947
|
+
logger.debug(`Found ${parsedSubagents.length} subagent files in ${subagentsDir}`);
|
|
4129
4948
|
}
|
|
4130
|
-
|
|
4131
|
-
logger.
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4949
|
+
} catch (error) {
|
|
4950
|
+
logger.debug(`No subagents directory found or error reading: ${error}`);
|
|
4951
|
+
}
|
|
4952
|
+
if (!tools || tools.length === 0) {
|
|
4953
|
+
return outputs;
|
|
4954
|
+
}
|
|
4955
|
+
const config = {
|
|
4956
|
+
aiRulesDir: rulesyncDir,
|
|
4957
|
+
outputPaths: {
|
|
4958
|
+
agentsmd: ".",
|
|
4959
|
+
amazonqcli: ".",
|
|
4960
|
+
augmentcode: ".augment",
|
|
4961
|
+
"augmentcode-legacy": ".",
|
|
4962
|
+
copilot: ".github",
|
|
4963
|
+
cursor: ".cursor",
|
|
4964
|
+
cline: ".",
|
|
4965
|
+
claudecode: ".",
|
|
4966
|
+
codexcli: ".",
|
|
4967
|
+
opencode: ".",
|
|
4968
|
+
qwencode: ".",
|
|
4969
|
+
roo: ".roo",
|
|
4970
|
+
geminicli: ".gemini",
|
|
4971
|
+
kiro: ".kiro",
|
|
4972
|
+
junie: ".junie",
|
|
4973
|
+
windsurf: ".windsurf"
|
|
4974
|
+
},
|
|
4975
|
+
watchEnabled: false,
|
|
4976
|
+
defaultTargets: tools
|
|
4977
|
+
};
|
|
4978
|
+
for (const tool of tools) {
|
|
4979
|
+
try {
|
|
4980
|
+
let generator;
|
|
4981
|
+
switch (tool) {
|
|
4982
|
+
case "claudecode":
|
|
4983
|
+
generator = new ClaudeCodeSubagentGenerator();
|
|
4984
|
+
break;
|
|
4985
|
+
// Add other tool generators here as they are implemented
|
|
4986
|
+
default:
|
|
4987
|
+
logger.debug(`Subagent generation not yet implemented for ${tool}`);
|
|
4988
|
+
continue;
|
|
4989
|
+
}
|
|
4990
|
+
const generatedOutputs = await generator.generate(
|
|
4991
|
+
parsedSubagents.length > 0 ? [] : rules || [],
|
|
4992
|
+
config,
|
|
4993
|
+
outputDir,
|
|
4994
|
+
parsedSubagents
|
|
4995
|
+
);
|
|
4996
|
+
for (const output of generatedOutputs) {
|
|
4997
|
+
outputs.push({
|
|
4998
|
+
tool,
|
|
4999
|
+
filepath: output.filepath,
|
|
5000
|
+
content: output.content
|
|
5001
|
+
});
|
|
5002
|
+
}
|
|
5003
|
+
} catch (error) {
|
|
5004
|
+
logger.error(`Failed to generate subagents for ${tool}:`, error);
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
5007
|
+
return outputs;
|
|
5008
|
+
}
|
|
5009
|
+
|
|
5010
|
+
// src/cli/commands/generate.ts
|
|
5011
|
+
init_logger();
|
|
5012
|
+
|
|
5013
|
+
// src/cli/commands/shared-utils.ts
|
|
5014
|
+
init_logger();
|
|
5015
|
+
function showBackwardCompatibilityWarning(commandName, exampleCommand) {
|
|
5016
|
+
const yellow = "\x1B[33m";
|
|
5017
|
+
const gray = "\x1B[90m";
|
|
5018
|
+
const cyan = "\x1B[36m";
|
|
5019
|
+
const reset = "\x1B[0m";
|
|
5020
|
+
logger.warn(
|
|
5021
|
+
`
|
|
5022
|
+
${yellow}\u26A0\uFE0F Warning: No --features option specified.${reset}
|
|
5023
|
+
${gray}Currently ${commandName} all features for backward compatibility.${reset}
|
|
5024
|
+
${gray}In future versions, this behavior may change.${reset}
|
|
5025
|
+
${gray}Please specify --features explicitly:${reset}
|
|
5026
|
+
${cyan} ${exampleCommand}${reset}
|
|
5027
|
+
${gray}Or use --features * to ${commandName.replace("ing", "")} all features.${reset}
|
|
5028
|
+
`
|
|
5029
|
+
);
|
|
5030
|
+
}
|
|
5031
|
+
|
|
5032
|
+
// src/cli/commands/generate.ts
|
|
5033
|
+
async function generateCommand(options = {}) {
|
|
5034
|
+
try {
|
|
5035
|
+
const cliParser = new CliParser();
|
|
5036
|
+
const cliInputs = {};
|
|
5037
|
+
if (options.tools !== void 0) cliInputs.tools = options.tools;
|
|
5038
|
+
if (options.features !== void 0) cliInputs.features = options.features;
|
|
5039
|
+
if (options.verbose !== void 0) cliInputs.verbose = options.verbose;
|
|
5040
|
+
if (options.delete !== void 0) cliInputs.delete = options.delete;
|
|
5041
|
+
if (options.baseDirs !== void 0) cliInputs.baseDirs = options.baseDirs;
|
|
5042
|
+
if (options.config !== void 0) cliInputs.config = options.config;
|
|
5043
|
+
if (options.noConfig !== void 0) cliInputs.noConfig = options.noConfig;
|
|
5044
|
+
const cliOptions = cliParser.parse(cliInputs);
|
|
5045
|
+
const configResolver = new ConfigResolver();
|
|
5046
|
+
const resolutionResult = await configResolver.resolve({
|
|
5047
|
+
cliOptions
|
|
5048
|
+
});
|
|
5049
|
+
const config = resolutionResult.value;
|
|
5050
|
+
let resolvedFeatures;
|
|
5051
|
+
let showWarning = false;
|
|
5052
|
+
if (cliOptions.features !== void 0) {
|
|
5053
|
+
resolvedFeatures = cliOptions.features;
|
|
5054
|
+
} else if (config.features !== void 0) {
|
|
5055
|
+
resolvedFeatures = config.features;
|
|
5056
|
+
} else {
|
|
5057
|
+
resolvedFeatures = "*";
|
|
5058
|
+
showWarning = true;
|
|
5059
|
+
}
|
|
5060
|
+
if (showWarning) {
|
|
5061
|
+
showBackwardCompatibilityWarning(
|
|
5062
|
+
"generating",
|
|
5063
|
+
"rulesync generate --features rules,commands,mcp,ignore"
|
|
5064
|
+
);
|
|
5065
|
+
}
|
|
5066
|
+
const normalizedFeatures = normalizeFeatures(resolvedFeatures);
|
|
5067
|
+
if (!config.defaultTargets || config.defaultTargets.length === 0) {
|
|
5068
|
+
const errorMessage = `\u274C Error: At least one tool must be specified.
|
|
5069
|
+
|
|
5070
|
+
You can specify tools in three ways:
|
|
5071
|
+
|
|
5072
|
+
1. Use the --targets flag:
|
|
5073
|
+
rulesync generate --targets copilot,cursor
|
|
5074
|
+
|
|
5075
|
+
2. Use the --all flag to generate for all tools:
|
|
5076
|
+
rulesync generate --all
|
|
5077
|
+
|
|
5078
|
+
3. Set targets in rulesync.jsonc:
|
|
5079
|
+
{
|
|
5080
|
+
"targets": ["copilot", "cursor"]
|
|
5081
|
+
}
|
|
5082
|
+
|
|
5083
|
+
Available tools:
|
|
5084
|
+
agentsmd, amazonqcli, augmentcode, augmentcode-legacy, copilot, cursor, cline,
|
|
5085
|
+
claudecode, codexcli, opencode, qwencode, roo, geminicli, kiro, junie, windsurf`;
|
|
5086
|
+
logger.error(errorMessage);
|
|
5087
|
+
process.exit(1);
|
|
5088
|
+
}
|
|
5089
|
+
logger.setVerbose(config.verbose || false);
|
|
5090
|
+
let baseDirs;
|
|
5091
|
+
if (config.baseDir) {
|
|
5092
|
+
baseDirs = Array.isArray(config.baseDir) ? config.baseDir : [config.baseDir];
|
|
5093
|
+
} else if (options.baseDirs) {
|
|
5094
|
+
baseDirs = options.baseDirs;
|
|
5095
|
+
} else {
|
|
5096
|
+
baseDirs = [process.cwd()];
|
|
5097
|
+
}
|
|
5098
|
+
logger.info(`Configuration resolved from: ${resolutionResult.source}`);
|
|
5099
|
+
logger.log("Generating configuration files...");
|
|
5100
|
+
if (!await fileExists(config.aiRulesDir)) {
|
|
5101
|
+
logger.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
|
|
5102
|
+
process.exit(1);
|
|
5103
|
+
}
|
|
5104
|
+
try {
|
|
5105
|
+
logger.info(`Parsing rules from ${config.aiRulesDir}...`);
|
|
5106
|
+
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
5107
|
+
if (rules.length === 0) {
|
|
5108
|
+
logger.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
5109
|
+
return;
|
|
5110
|
+
}
|
|
5111
|
+
logger.info(`Found ${rules.length} rule(s)`);
|
|
5112
|
+
logger.info(`Base directories: ${baseDirs.join(", ")}`);
|
|
5113
|
+
if (config.delete) {
|
|
5114
|
+
logger.info("Deleting existing output directories...");
|
|
5115
|
+
const targetTools = config.defaultTargets;
|
|
5116
|
+
const deleteTasks = [];
|
|
5117
|
+
const commandsDir = (0, import_node_path18.join)(config.aiRulesDir, "commands");
|
|
5118
|
+
const hasCommands = await fileExists(commandsDir);
|
|
5119
|
+
let hasCommandFiles = false;
|
|
5120
|
+
if (hasCommands) {
|
|
5121
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5122
|
+
try {
|
|
5123
|
+
const files = await readdir3(commandsDir);
|
|
5124
|
+
hasCommandFiles = files.some((file) => file.endsWith(".md"));
|
|
5125
|
+
} catch {
|
|
5126
|
+
hasCommandFiles = false;
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
for (const tool of targetTools) {
|
|
5130
|
+
switch (tool) {
|
|
5131
|
+
case "augmentcode":
|
|
5132
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5133
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".augment", "rules")));
|
|
5134
|
+
}
|
|
5135
|
+
if (normalizedFeatures.includes("ignore")) {
|
|
5136
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".augment", "ignore")));
|
|
5137
|
+
}
|
|
5138
|
+
break;
|
|
5139
|
+
case "augmentcode-legacy":
|
|
5140
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5141
|
+
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
5142
|
+
}
|
|
5143
|
+
if (normalizedFeatures.includes("ignore")) {
|
|
5144
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".augment", "ignore")));
|
|
5145
|
+
}
|
|
5146
|
+
break;
|
|
5147
|
+
case "copilot":
|
|
5148
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5149
|
+
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
5150
|
+
}
|
|
5151
|
+
break;
|
|
5152
|
+
case "cursor":
|
|
5153
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5154
|
+
deleteTasks.push(removeDirectory(config.outputPaths.cursor));
|
|
5155
|
+
}
|
|
5156
|
+
break;
|
|
5157
|
+
case "cline":
|
|
5158
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5159
|
+
deleteTasks.push(removeDirectory(config.outputPaths.cline));
|
|
5160
|
+
}
|
|
5161
|
+
break;
|
|
5162
|
+
case "claudecode":
|
|
5163
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5164
|
+
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
5165
|
+
}
|
|
5166
|
+
if (normalizedFeatures.includes("commands") && hasCommandFiles) {
|
|
5167
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".claude", "commands")));
|
|
5168
|
+
}
|
|
5169
|
+
if (normalizedFeatures.includes("subagents")) {
|
|
5170
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".claude", "agents")));
|
|
5171
|
+
}
|
|
5172
|
+
break;
|
|
5173
|
+
case "roo":
|
|
5174
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5175
|
+
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
5176
|
+
}
|
|
5177
|
+
if (normalizedFeatures.includes("commands") && hasCommandFiles) {
|
|
5178
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".roo", "commands")));
|
|
5179
|
+
}
|
|
5180
|
+
break;
|
|
5181
|
+
case "geminicli":
|
|
5182
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5183
|
+
deleteTasks.push(removeDirectory(config.outputPaths.geminicli));
|
|
5184
|
+
}
|
|
5185
|
+
if (normalizedFeatures.includes("commands") && hasCommandFiles) {
|
|
5186
|
+
deleteTasks.push(removeDirectory((0, import_node_path18.join)(".gemini", "commands")));
|
|
5187
|
+
}
|
|
5188
|
+
break;
|
|
5189
|
+
case "kiro":
|
|
5190
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5191
|
+
deleteTasks.push(removeDirectory(config.outputPaths.kiro));
|
|
5192
|
+
}
|
|
5193
|
+
break;
|
|
5194
|
+
case "opencode":
|
|
5195
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5196
|
+
deleteTasks.push(removeDirectory(config.outputPaths.opencode));
|
|
5197
|
+
}
|
|
5198
|
+
break;
|
|
5199
|
+
case "qwencode":
|
|
5200
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5201
|
+
deleteTasks.push(removeDirectory(config.outputPaths.qwencode));
|
|
5202
|
+
}
|
|
5203
|
+
break;
|
|
5204
|
+
case "windsurf":
|
|
5205
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5206
|
+
deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
|
|
5207
|
+
}
|
|
5208
|
+
break;
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
await Promise.all(deleteTasks);
|
|
5212
|
+
logger.info("Deleted existing output directories");
|
|
5213
|
+
}
|
|
5214
|
+
let totalOutputs = 0;
|
|
5215
|
+
if (normalizedFeatures.includes("rules")) {
|
|
5216
|
+
for (const baseDir of baseDirs) {
|
|
5217
|
+
logger.info(`
|
|
5218
|
+
Generating rule configurations for base directory: ${baseDir}`);
|
|
5219
|
+
const outputs = await generateConfigurations(
|
|
5220
|
+
rules,
|
|
5221
|
+
config,
|
|
5222
|
+
config.defaultTargets,
|
|
5223
|
+
baseDir
|
|
5224
|
+
);
|
|
5225
|
+
if (outputs.length === 0) {
|
|
5226
|
+
logger.warn(`\u26A0\uFE0F No rule configurations generated for ${baseDir}`);
|
|
5227
|
+
continue;
|
|
5228
|
+
}
|
|
5229
|
+
for (const output of outputs) {
|
|
5230
|
+
await writeFileContent(output.filepath, output.content);
|
|
5231
|
+
logger.success(`Generated ${output.tool} rule configuration: ${output.filepath}`);
|
|
5232
|
+
}
|
|
5233
|
+
totalOutputs += outputs.length;
|
|
4146
5234
|
}
|
|
5235
|
+
} else {
|
|
5236
|
+
logger.info("\nSkipping rule generation (not in --features)");
|
|
4147
5237
|
}
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
break;
|
|
4158
|
-
case "copilot":
|
|
4159
|
-
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
4160
|
-
break;
|
|
4161
|
-
case "cursor":
|
|
4162
|
-
deleteTasks.push(removeDirectory(config.outputPaths.cursor));
|
|
4163
|
-
break;
|
|
4164
|
-
case "cline":
|
|
4165
|
-
deleteTasks.push(removeDirectory(config.outputPaths.cline));
|
|
4166
|
-
break;
|
|
4167
|
-
case "claudecode":
|
|
4168
|
-
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
4169
|
-
if (hasCommandFiles) {
|
|
4170
|
-
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".claude", "commands")));
|
|
5238
|
+
let totalMcpOutputs = 0;
|
|
5239
|
+
if (normalizedFeatures.includes("mcp")) {
|
|
5240
|
+
logger.info("\nGenerating MCP configurations...");
|
|
5241
|
+
for (const baseDir of baseDirs) {
|
|
5242
|
+
try {
|
|
5243
|
+
const mcpConfig = parseMcpConfig(process.cwd());
|
|
5244
|
+
if (!mcpConfig || !mcpConfig.mcpServers || Object.keys(mcpConfig.mcpServers).length === 0) {
|
|
5245
|
+
logger.info(`No MCP configuration found for ${baseDir}`);
|
|
5246
|
+
continue;
|
|
4171
5247
|
}
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
5248
|
+
const mcpResults = await generateMcpConfigurations(
|
|
5249
|
+
mcpConfig,
|
|
5250
|
+
baseDir === process.cwd() ? "." : baseDir,
|
|
5251
|
+
config.defaultTargets
|
|
5252
|
+
);
|
|
5253
|
+
if (mcpResults.length === 0) {
|
|
5254
|
+
logger.info(`No MCP configurations generated for ${baseDir}`);
|
|
5255
|
+
continue;
|
|
4177
5256
|
}
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
deleteTasks.push(removeDirectory((0, import_node_path13.join)(".gemini", "commands")));
|
|
5257
|
+
for (const result of mcpResults) {
|
|
5258
|
+
await writeFileContent(result.filepath, result.content);
|
|
5259
|
+
logger.success(`Generated ${result.tool} MCP configuration: ${result.filepath}`);
|
|
5260
|
+
totalMcpOutputs++;
|
|
4183
5261
|
}
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
deleteTasks.push(removeDirectory(config.outputPaths.opencode));
|
|
4190
|
-
break;
|
|
4191
|
-
case "windsurf":
|
|
4192
|
-
deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
|
|
4193
|
-
break;
|
|
5262
|
+
} catch (error) {
|
|
5263
|
+
logger.error(
|
|
5264
|
+
`\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
5265
|
+
);
|
|
5266
|
+
}
|
|
4194
5267
|
}
|
|
5268
|
+
} else {
|
|
5269
|
+
logger.info("\nSkipping MCP configuration generation (not in --features)");
|
|
4195
5270
|
}
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
5271
|
+
let totalCommandOutputs = 0;
|
|
5272
|
+
if (normalizedFeatures.includes("commands")) {
|
|
5273
|
+
logger.info("\nGenerating command files...");
|
|
5274
|
+
for (const baseDir of baseDirs) {
|
|
5275
|
+
const commandResults = await generateCommands(
|
|
5276
|
+
process.cwd(),
|
|
5277
|
+
baseDir === process.cwd() ? void 0 : baseDir,
|
|
5278
|
+
config.defaultTargets
|
|
5279
|
+
);
|
|
5280
|
+
if (commandResults.length === 0) {
|
|
5281
|
+
logger.info(`No commands found for ${baseDir}`);
|
|
5282
|
+
continue;
|
|
5283
|
+
}
|
|
5284
|
+
for (const result of commandResults) {
|
|
5285
|
+
await writeFileContent(result.filepath, result.content);
|
|
5286
|
+
logger.success(`Generated ${result.tool} command: ${result.filepath}`);
|
|
5287
|
+
totalCommandOutputs++;
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
} else {
|
|
5291
|
+
logger.info("\nSkipping command file generation (not in --features)");
|
|
4207
5292
|
}
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
logger.
|
|
5293
|
+
const totalIgnoreOutputs = 0;
|
|
5294
|
+
if (normalizedFeatures.includes("ignore")) {
|
|
5295
|
+
logger.info("\nGenerating ignore files...");
|
|
5296
|
+
logger.info("Ignore file generation is not yet implemented");
|
|
5297
|
+
} else {
|
|
5298
|
+
logger.info("\nSkipping ignore file generation (not in --features)");
|
|
4211
5299
|
}
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
);
|
|
4232
|
-
if (mcpResults.length === 0) {
|
|
4233
|
-
logger.info(`No MCP configurations generated for ${baseDir}`);
|
|
4234
|
-
continue;
|
|
4235
|
-
}
|
|
4236
|
-
for (const result of mcpResults) {
|
|
4237
|
-
await writeFileContent(result.filepath, result.content);
|
|
4238
|
-
logger.success(`Generated ${result.tool} MCP configuration: ${result.filepath}`);
|
|
4239
|
-
totalMcpOutputs++;
|
|
5300
|
+
let totalSubagentOutputs = 0;
|
|
5301
|
+
if (normalizedFeatures.includes("subagents")) {
|
|
5302
|
+
logger.info("\nGenerating subagent files...");
|
|
5303
|
+
for (const baseDir of baseDirs) {
|
|
5304
|
+
const subagentResults = await generateSubagents(
|
|
5305
|
+
config.aiRulesDir,
|
|
5306
|
+
baseDir === process.cwd() ? void 0 : baseDir,
|
|
5307
|
+
config.defaultTargets,
|
|
5308
|
+
rules
|
|
5309
|
+
);
|
|
5310
|
+
if (subagentResults.length === 0) {
|
|
5311
|
+
logger.info(`No subagents generated for ${baseDir}`);
|
|
5312
|
+
continue;
|
|
5313
|
+
}
|
|
5314
|
+
for (const result of subagentResults) {
|
|
5315
|
+
await writeFileContent(result.filepath, result.content);
|
|
5316
|
+
logger.success(`Generated ${result.tool} subagent: ${result.filepath}`);
|
|
5317
|
+
totalSubagentOutputs++;
|
|
5318
|
+
}
|
|
4240
5319
|
}
|
|
4241
|
-
}
|
|
4242
|
-
logger.
|
|
4243
|
-
`\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
4244
|
-
);
|
|
5320
|
+
} else {
|
|
5321
|
+
logger.info("\nSkipping subagent file generation (not in --features)");
|
|
4245
5322
|
}
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
await writeFileContent(result.filepath, result.content);
|
|
4261
|
-
logger.success(`Generated ${result.tool} command: ${result.filepath}`);
|
|
4262
|
-
totalCommandOutputs++;
|
|
4263
|
-
}
|
|
4264
|
-
}
|
|
4265
|
-
const totalGenerated = totalOutputs + totalMcpOutputs + totalCommandOutputs;
|
|
4266
|
-
if (totalGenerated > 0) {
|
|
4267
|
-
const parts = [];
|
|
4268
|
-
if (totalOutputs > 0) parts.push(`${totalOutputs} configurations`);
|
|
4269
|
-
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP configurations`);
|
|
4270
|
-
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
4271
|
-
logger.success(
|
|
4272
|
-
`
|
|
5323
|
+
const totalGenerated = totalOutputs + totalMcpOutputs + totalCommandOutputs + totalIgnoreOutputs + totalSubagentOutputs;
|
|
5324
|
+
if (totalGenerated === 0) {
|
|
5325
|
+
const enabledFeatures = normalizedFeatures.join(", ");
|
|
5326
|
+
logger.warn(`\u26A0\uFE0F No files generated for enabled features: ${enabledFeatures}`);
|
|
5327
|
+
return;
|
|
5328
|
+
}
|
|
5329
|
+
if (totalGenerated > 0) {
|
|
5330
|
+
const parts = [];
|
|
5331
|
+
if (totalOutputs > 0) parts.push(`${totalOutputs} configurations`);
|
|
5332
|
+
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP configurations`);
|
|
5333
|
+
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
5334
|
+
if (totalSubagentOutputs > 0) parts.push(`${totalSubagentOutputs} subagents`);
|
|
5335
|
+
logger.success(
|
|
5336
|
+
`
|
|
4273
5337
|
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`
|
|
4274
|
-
|
|
5338
|
+
);
|
|
5339
|
+
}
|
|
5340
|
+
} catch (error) {
|
|
5341
|
+
logger.error("\u274C Failed to generate configurations:", error);
|
|
5342
|
+
process.exit(1);
|
|
4275
5343
|
}
|
|
4276
5344
|
} catch (error) {
|
|
4277
|
-
logger.error("\u274C Failed to
|
|
5345
|
+
logger.error("\u274C Failed to resolve configuration:", error);
|
|
4278
5346
|
process.exit(1);
|
|
4279
5347
|
}
|
|
4280
5348
|
}
|
|
4281
5349
|
|
|
4282
5350
|
// src/cli/commands/gitignore.ts
|
|
4283
5351
|
var import_node_fs2 = require("fs");
|
|
4284
|
-
var
|
|
5352
|
+
var import_node_path19 = require("path");
|
|
4285
5353
|
init_logger();
|
|
4286
5354
|
var gitignoreCommand = async () => {
|
|
4287
|
-
const gitignorePath = (0,
|
|
5355
|
+
const gitignorePath = (0, import_node_path19.join)(process.cwd(), ".gitignore");
|
|
4288
5356
|
const rulesFilesToIgnore = [
|
|
4289
5357
|
"# Generated by rulesync - AI tool configuration files",
|
|
4290
5358
|
"**/.amazonq/rules/",
|
|
@@ -4298,7 +5366,9 @@ var gitignoreCommand = async () => {
|
|
|
4298
5366
|
"**/CLAUDE.md",
|
|
4299
5367
|
"**/.claude/memories/",
|
|
4300
5368
|
"**/.claude/commands/",
|
|
5369
|
+
"**/.claude/agents/",
|
|
4301
5370
|
"**/AGENTS.md",
|
|
5371
|
+
"**/.agents/",
|
|
4302
5372
|
"**/.codexignore",
|
|
4303
5373
|
"**/.roo/rules/",
|
|
4304
5374
|
"**/.rooignore",
|
|
@@ -4306,6 +5376,8 @@ var gitignoreCommand = async () => {
|
|
|
4306
5376
|
"**/GEMINI.md",
|
|
4307
5377
|
"**/.gemini/memories/",
|
|
4308
5378
|
"**/.gemini/commands/",
|
|
5379
|
+
"**/QWEN.md",
|
|
5380
|
+
"**/.qwen/memories/",
|
|
4309
5381
|
"**/.aiexclude",
|
|
4310
5382
|
"**/.aiignore",
|
|
4311
5383
|
"**/.augmentignore",
|
|
@@ -4324,6 +5396,7 @@ var gitignoreCommand = async () => {
|
|
|
4324
5396
|
"**/.vscode/mcp.json",
|
|
4325
5397
|
"**/.codex/mcp-config.json",
|
|
4326
5398
|
"**/.gemini/settings.json",
|
|
5399
|
+
"**/.qwen/settings.json",
|
|
4327
5400
|
"**/.roo/mcp.json"
|
|
4328
5401
|
];
|
|
4329
5402
|
let gitignoreContent = "";
|
|
@@ -4355,11 +5428,155 @@ ${linesToAdd.join("\n")}
|
|
|
4355
5428
|
};
|
|
4356
5429
|
|
|
4357
5430
|
// src/core/importer.ts
|
|
4358
|
-
var
|
|
4359
|
-
var
|
|
5431
|
+
var import_node_path28 = require("path");
|
|
5432
|
+
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
|
|
5433
|
+
|
|
5434
|
+
// src/parsers/agentsmd.ts
|
|
5435
|
+
var import_node_path20 = require("path");
|
|
5436
|
+
async function parseAgentsMdConfiguration(baseDir = process.cwd()) {
|
|
5437
|
+
const errors = [];
|
|
5438
|
+
const rules = [];
|
|
5439
|
+
const projectAgentsPath = (0, import_node_path20.join)(baseDir, "AGENTS.md");
|
|
5440
|
+
if (await fileExists(projectAgentsPath)) {
|
|
5441
|
+
try {
|
|
5442
|
+
const content = await readFileContent(projectAgentsPath);
|
|
5443
|
+
if (content.trim()) {
|
|
5444
|
+
const frontmatter = {
|
|
5445
|
+
root: true,
|
|
5446
|
+
targets: ["agentsmd"],
|
|
5447
|
+
description: "Project-level AGENTS.md instructions",
|
|
5448
|
+
globs: ["**/*"]
|
|
5449
|
+
};
|
|
5450
|
+
rules.push({
|
|
5451
|
+
frontmatter,
|
|
5452
|
+
content: content.trim(),
|
|
5453
|
+
filename: "project-instructions",
|
|
5454
|
+
filepath: projectAgentsPath
|
|
5455
|
+
});
|
|
5456
|
+
}
|
|
5457
|
+
} catch (error) {
|
|
5458
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5459
|
+
errors.push(`Failed to parse AGENTS.md: ${errorMessage}`);
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
const memoriesDir = (0, import_node_path20.join)(baseDir, ".agents", "memories");
|
|
5463
|
+
if (await fileExists(memoriesDir)) {
|
|
5464
|
+
try {
|
|
5465
|
+
const { readdir: readdir3, stat: stat2 } = await import("fs/promises");
|
|
5466
|
+
const memoriesPath = memoriesDir;
|
|
5467
|
+
const memoriesStat = await stat2(memoriesPath);
|
|
5468
|
+
if (memoriesStat.isDirectory()) {
|
|
5469
|
+
const files = await readdir3(memoriesPath);
|
|
5470
|
+
for (const file of files) {
|
|
5471
|
+
if (file.endsWith(".md")) {
|
|
5472
|
+
const filePath = (0, import_node_path20.join)(memoriesPath, file);
|
|
5473
|
+
try {
|
|
5474
|
+
const content = await readFileContent(filePath);
|
|
5475
|
+
if (content.trim()) {
|
|
5476
|
+
const filename = file.replace(/\.md$/, "");
|
|
5477
|
+
const frontmatter = {
|
|
5478
|
+
root: false,
|
|
5479
|
+
targets: ["agentsmd"],
|
|
5480
|
+
description: `AGENTS.md memory: ${filename}`,
|
|
5481
|
+
globs: ["**/*"]
|
|
5482
|
+
};
|
|
5483
|
+
rules.push({
|
|
5484
|
+
frontmatter,
|
|
5485
|
+
content: content.trim(),
|
|
5486
|
+
filename,
|
|
5487
|
+
filepath: filePath
|
|
5488
|
+
});
|
|
5489
|
+
}
|
|
5490
|
+
} catch (error) {
|
|
5491
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5492
|
+
errors.push(`Failed to parse memory file ${file}: ${errorMessage}`);
|
|
5493
|
+
}
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5497
|
+
} catch {
|
|
5498
|
+
}
|
|
5499
|
+
}
|
|
5500
|
+
try {
|
|
5501
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5502
|
+
const files = await readdir3(baseDir);
|
|
5503
|
+
for (const file of files) {
|
|
5504
|
+
if (file === "AGENTS.md") continue;
|
|
5505
|
+
if (file.endsWith(".md") && (file.includes("agents") || file.includes("instructions") || file.includes("guidelines") || file.includes("rules"))) {
|
|
5506
|
+
const filePath = (0, import_node_path20.join)(baseDir, file);
|
|
5507
|
+
try {
|
|
5508
|
+
const content = await readFileContent(filePath);
|
|
5509
|
+
if (content.trim()) {
|
|
5510
|
+
const filename = file.replace(/\.md$/, "");
|
|
5511
|
+
const frontmatter = {
|
|
5512
|
+
root: false,
|
|
5513
|
+
targets: ["agentsmd"],
|
|
5514
|
+
description: `AGENTS.md instructions: ${filename}`,
|
|
5515
|
+
globs: ["**/*"]
|
|
5516
|
+
};
|
|
5517
|
+
rules.push({
|
|
5518
|
+
frontmatter,
|
|
5519
|
+
content: content.trim(),
|
|
5520
|
+
filename,
|
|
5521
|
+
filepath: filePath
|
|
5522
|
+
});
|
|
5523
|
+
}
|
|
5524
|
+
} catch (error) {
|
|
5525
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5526
|
+
errors.push(`Failed to parse ${file}: ${errorMessage}`);
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
for (const file of files) {
|
|
5531
|
+
const filePath = (0, import_node_path20.join)(baseDir, file);
|
|
5532
|
+
try {
|
|
5533
|
+
const { stat: stat2 } = await import("fs/promises");
|
|
5534
|
+
const stats = await stat2(filePath);
|
|
5535
|
+
if (stats.isDirectory() && !file.startsWith(".") && file !== "node_modules") {
|
|
5536
|
+
const subAgentsPath = (0, import_node_path20.join)(filePath, "AGENTS.md");
|
|
5537
|
+
if (await fileExists(subAgentsPath)) {
|
|
5538
|
+
try {
|
|
5539
|
+
const content = await readFileContent(subAgentsPath);
|
|
5540
|
+
if (content.trim()) {
|
|
5541
|
+
const frontmatter = {
|
|
5542
|
+
root: false,
|
|
5543
|
+
targets: ["agentsmd"],
|
|
5544
|
+
description: `Directory-specific AGENTS.md instructions: ${file}`,
|
|
5545
|
+
globs: [`${file}/**/*`]
|
|
5546
|
+
};
|
|
5547
|
+
rules.push({
|
|
5548
|
+
frontmatter,
|
|
5549
|
+
content: content.trim(),
|
|
5550
|
+
filename: `${file}-agents`,
|
|
5551
|
+
filepath: subAgentsPath
|
|
5552
|
+
});
|
|
5553
|
+
}
|
|
5554
|
+
} catch (error) {
|
|
5555
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5556
|
+
errors.push(`Failed to parse ${subAgentsPath}: ${errorMessage}`);
|
|
5557
|
+
}
|
|
5558
|
+
}
|
|
5559
|
+
}
|
|
5560
|
+
} catch {
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5563
|
+
} catch (error) {
|
|
5564
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5565
|
+
errors.push(`Failed to scan directory for AGENTS.md files: ${errorMessage}`);
|
|
5566
|
+
}
|
|
5567
|
+
if (rules.length === 0) {
|
|
5568
|
+
errors.push(
|
|
5569
|
+
"No AGENTS.md configuration files found. Expected to find AGENTS.md in the project root or memory files in .agents/memories/."
|
|
5570
|
+
);
|
|
5571
|
+
}
|
|
5572
|
+
return {
|
|
5573
|
+
rules,
|
|
5574
|
+
errors
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
4360
5577
|
|
|
4361
5578
|
// src/parsers/shared-helpers.ts
|
|
4362
|
-
var
|
|
5579
|
+
var import_node_path21 = require("path");
|
|
4363
5580
|
init_file();
|
|
4364
5581
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
4365
5582
|
const errors = [];
|
|
@@ -4413,11 +5630,11 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
4413
5630
|
const dirPath = resolvePath(dirConfig.directory, baseDir);
|
|
4414
5631
|
if (await fileExists(dirPath)) {
|
|
4415
5632
|
const result = await safeAsyncOperation(async () => {
|
|
4416
|
-
const { readdir:
|
|
4417
|
-
const files = await
|
|
5633
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5634
|
+
const files = await readdir3(dirPath);
|
|
4418
5635
|
for (const file of files) {
|
|
4419
5636
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
4420
|
-
const filePath = (0,
|
|
5637
|
+
const filePath = (0, import_node_path21.join)(dirPath, file);
|
|
4421
5638
|
const fileResult = await safeAsyncOperation(async () => {
|
|
4422
5639
|
const rawContent = await readFileContent(filePath);
|
|
4423
5640
|
let content;
|
|
@@ -4564,14 +5781,14 @@ function parseMainFile(content, filepath, config) {
|
|
|
4564
5781
|
async function parseMemoryFiles(memoryDir, config) {
|
|
4565
5782
|
const rules = [];
|
|
4566
5783
|
try {
|
|
4567
|
-
const { readdir:
|
|
4568
|
-
const files = await
|
|
5784
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5785
|
+
const files = await readdir3(memoryDir);
|
|
4569
5786
|
for (const file of files) {
|
|
4570
5787
|
if (file.endsWith(".md")) {
|
|
4571
|
-
const filePath = (0,
|
|
5788
|
+
const filePath = (0, import_node_path21.join)(memoryDir, file);
|
|
4572
5789
|
const content = await readFileContent(filePath);
|
|
4573
5790
|
if (content.trim()) {
|
|
4574
|
-
const filename = (0,
|
|
5791
|
+
const filename = (0, import_node_path21.basename)(file, ".md");
|
|
4575
5792
|
const frontmatter = {
|
|
4576
5793
|
root: false,
|
|
4577
5794
|
targets: [config.tool],
|
|
@@ -4594,14 +5811,14 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
4594
5811
|
async function parseCommandsFiles(commandsDir, config) {
|
|
4595
5812
|
const rules = [];
|
|
4596
5813
|
try {
|
|
4597
|
-
const { readdir:
|
|
4598
|
-
const files = await
|
|
5814
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5815
|
+
const files = await readdir3(commandsDir);
|
|
4599
5816
|
for (const file of files) {
|
|
4600
5817
|
if (file.endsWith(".md")) {
|
|
4601
|
-
const filePath = (0,
|
|
5818
|
+
const filePath = (0, import_node_path21.join)(commandsDir, file);
|
|
4602
5819
|
const content = await readFileContent(filePath);
|
|
4603
5820
|
if (content.trim()) {
|
|
4604
|
-
const filename = (0,
|
|
5821
|
+
const filename = (0, import_node_path21.basename)(file, ".md");
|
|
4605
5822
|
let frontmatter;
|
|
4606
5823
|
let ruleContent;
|
|
4607
5824
|
try {
|
|
@@ -4690,7 +5907,7 @@ async function parseAmazonqcliConfiguration(baseDir = process.cwd()) {
|
|
|
4690
5907
|
}
|
|
4691
5908
|
|
|
4692
5909
|
// src/parsers/augmentcode.ts
|
|
4693
|
-
var
|
|
5910
|
+
var import_node_path22 = require("path");
|
|
4694
5911
|
|
|
4695
5912
|
// src/utils/parser-helpers.ts
|
|
4696
5913
|
function createParseResult() {
|
|
@@ -4738,7 +5955,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
4738
5955
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
4739
5956
|
const result = createParseResult();
|
|
4740
5957
|
if (config.rulesDir) {
|
|
4741
|
-
const rulesDir = (0,
|
|
5958
|
+
const rulesDir = (0, import_node_path22.join)(baseDir, config.rulesDir);
|
|
4742
5959
|
if (await fileExists(rulesDir)) {
|
|
4743
5960
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
4744
5961
|
addRules(result, rulesResult.rules);
|
|
@@ -4751,7 +5968,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
4751
5968
|
}
|
|
4752
5969
|
}
|
|
4753
5970
|
if (config.legacyFilePath) {
|
|
4754
|
-
const legacyPath = (0,
|
|
5971
|
+
const legacyPath = (0, import_node_path22.join)(baseDir, config.legacyFilePath);
|
|
4755
5972
|
if (await fileExists(legacyPath)) {
|
|
4756
5973
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
4757
5974
|
if (legacyResult.rule) {
|
|
@@ -4771,11 +5988,11 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
4771
5988
|
const rules = [];
|
|
4772
5989
|
const errors = [];
|
|
4773
5990
|
try {
|
|
4774
|
-
const { readdir:
|
|
4775
|
-
const files = await
|
|
5991
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5992
|
+
const files = await readdir3(rulesDir);
|
|
4776
5993
|
for (const file of files) {
|
|
4777
5994
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
4778
|
-
const filePath = (0,
|
|
5995
|
+
const filePath = (0, import_node_path22.join)(rulesDir, file);
|
|
4779
5996
|
try {
|
|
4780
5997
|
const rawContent = await readFileContent(filePath);
|
|
4781
5998
|
const parsed = parseFrontmatter(rawContent);
|
|
@@ -4783,7 +6000,7 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
4783
6000
|
const description = extractStringField(parsed.data, "description", "");
|
|
4784
6001
|
const tags = extractArrayField(parsed.data, "tags");
|
|
4785
6002
|
const isRoot = ruleType === "always";
|
|
4786
|
-
const filename = (0,
|
|
6003
|
+
const filename = (0, import_node_path22.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
4787
6004
|
const frontmatter = {
|
|
4788
6005
|
root: isRoot,
|
|
4789
6006
|
targets: [config.targetName],
|
|
@@ -4841,8 +6058,9 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
|
4841
6058
|
}
|
|
4842
6059
|
|
|
4843
6060
|
// src/parsers/claudecode.ts
|
|
6061
|
+
init_file();
|
|
4844
6062
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
4845
|
-
|
|
6063
|
+
const memoryResult = await parseMemoryBasedConfiguration(baseDir, {
|
|
4846
6064
|
tool: "claudecode",
|
|
4847
6065
|
mainFileName: "CLAUDE.md",
|
|
4848
6066
|
memoryDirPath: ".claude/memories",
|
|
@@ -4852,6 +6070,24 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
4852
6070
|
filenamePrefix: "claude",
|
|
4853
6071
|
commandsDirPath: ".claude/commands"
|
|
4854
6072
|
});
|
|
6073
|
+
const result = {
|
|
6074
|
+
rules: memoryResult.rules,
|
|
6075
|
+
errors: memoryResult.errors
|
|
6076
|
+
};
|
|
6077
|
+
if (memoryResult.ignorePatterns) {
|
|
6078
|
+
result.ignorePatterns = memoryResult.ignorePatterns;
|
|
6079
|
+
}
|
|
6080
|
+
if (memoryResult.mcpServers) {
|
|
6081
|
+
result.mcpServers = memoryResult.mcpServers;
|
|
6082
|
+
}
|
|
6083
|
+
const agentsDir = resolvePath(".claude/agents", baseDir);
|
|
6084
|
+
if (await fileExists(agentsDir)) {
|
|
6085
|
+
const subagents = await parseSubagentsFromDirectory(agentsDir);
|
|
6086
|
+
if (subagents.length > 0) {
|
|
6087
|
+
result.subagents = subagents;
|
|
6088
|
+
}
|
|
6089
|
+
}
|
|
6090
|
+
return result;
|
|
4855
6091
|
}
|
|
4856
6092
|
|
|
4857
6093
|
// src/parsers/cline.ts
|
|
@@ -4875,7 +6111,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
4875
6111
|
}
|
|
4876
6112
|
|
|
4877
6113
|
// src/parsers/codexcli.ts
|
|
4878
|
-
var
|
|
6114
|
+
var import_node_path23 = require("path");
|
|
4879
6115
|
|
|
4880
6116
|
// src/parsers/copilot.ts
|
|
4881
6117
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -4898,9 +6134,9 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
4898
6134
|
}
|
|
4899
6135
|
|
|
4900
6136
|
// src/parsers/cursor.ts
|
|
4901
|
-
var
|
|
6137
|
+
var import_node_path24 = require("path");
|
|
4902
6138
|
var import_js_yaml = require("js-yaml");
|
|
4903
|
-
var
|
|
6139
|
+
var import_mini9 = require("zod/mini");
|
|
4904
6140
|
var customMatterOptions = {
|
|
4905
6141
|
engines: {
|
|
4906
6142
|
yaml: {
|
|
@@ -4928,7 +6164,7 @@ var customMatterOptions = {
|
|
|
4928
6164
|
}
|
|
4929
6165
|
};
|
|
4930
6166
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
4931
|
-
const FrontmatterSchema =
|
|
6167
|
+
const FrontmatterSchema = import_mini9.z.record(import_mini9.z.string(), import_mini9.z.unknown());
|
|
4932
6168
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
4933
6169
|
if (!parseResult.success) {
|
|
4934
6170
|
return {
|
|
@@ -5022,7 +6258,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5022
6258
|
const rules = [];
|
|
5023
6259
|
let ignorePatterns;
|
|
5024
6260
|
let mcpServers;
|
|
5025
|
-
const cursorFilePath = (0,
|
|
6261
|
+
const cursorFilePath = (0, import_node_path24.join)(baseDir, ".cursorrules");
|
|
5026
6262
|
if (await fileExists(cursorFilePath)) {
|
|
5027
6263
|
try {
|
|
5028
6264
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -5043,20 +6279,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5043
6279
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
5044
6280
|
}
|
|
5045
6281
|
}
|
|
5046
|
-
const cursorRulesDir = (0,
|
|
6282
|
+
const cursorRulesDir = (0, import_node_path24.join)(baseDir, ".cursor", "rules");
|
|
5047
6283
|
if (await fileExists(cursorRulesDir)) {
|
|
5048
6284
|
try {
|
|
5049
|
-
const { readdir:
|
|
5050
|
-
const files = await
|
|
6285
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
6286
|
+
const files = await readdir3(cursorRulesDir);
|
|
5051
6287
|
for (const file of files) {
|
|
5052
6288
|
if (file.endsWith(".mdc")) {
|
|
5053
|
-
const filePath = (0,
|
|
6289
|
+
const filePath = (0, import_node_path24.join)(cursorRulesDir, file);
|
|
5054
6290
|
try {
|
|
5055
6291
|
const rawContent = await readFileContent(filePath);
|
|
5056
6292
|
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
5057
6293
|
const content = parsed.content;
|
|
5058
6294
|
if (content) {
|
|
5059
|
-
const filename = (0,
|
|
6295
|
+
const filename = (0, import_node_path24.basename)(file, ".mdc");
|
|
5060
6296
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
5061
6297
|
rules.push({
|
|
5062
6298
|
frontmatter,
|
|
@@ -5079,7 +6315,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5079
6315
|
if (rules.length === 0) {
|
|
5080
6316
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
5081
6317
|
}
|
|
5082
|
-
const cursorIgnorePath = (0,
|
|
6318
|
+
const cursorIgnorePath = (0, import_node_path24.join)(baseDir, ".cursorignore");
|
|
5083
6319
|
if (await fileExists(cursorIgnorePath)) {
|
|
5084
6320
|
try {
|
|
5085
6321
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -5092,7 +6328,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5092
6328
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
5093
6329
|
}
|
|
5094
6330
|
}
|
|
5095
|
-
const cursorMcpPath = (0,
|
|
6331
|
+
const cursorMcpPath = (0, import_node_path24.join)(baseDir, ".cursor", "mcp.json");
|
|
5096
6332
|
if (await fileExists(cursorMcpPath)) {
|
|
5097
6333
|
try {
|
|
5098
6334
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -5115,6 +6351,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5115
6351
|
}
|
|
5116
6352
|
|
|
5117
6353
|
// src/parsers/geminicli.ts
|
|
6354
|
+
var import_node_path25 = require("path");
|
|
5118
6355
|
async function parseAiexclude(aiexcludePath) {
|
|
5119
6356
|
try {
|
|
5120
6357
|
const content = await readFileContent(aiexcludePath);
|
|
@@ -5124,8 +6361,51 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
5124
6361
|
return [];
|
|
5125
6362
|
}
|
|
5126
6363
|
}
|
|
6364
|
+
async function parseGeminiCommands(commandsDir) {
|
|
6365
|
+
const rules = [];
|
|
6366
|
+
try {
|
|
6367
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
6368
|
+
const { parse } = await import("smol-toml");
|
|
6369
|
+
const files = await readdir3(commandsDir);
|
|
6370
|
+
for (const file of files) {
|
|
6371
|
+
if (file.endsWith(".toml")) {
|
|
6372
|
+
const filePath = (0, import_node_path25.join)(commandsDir, file);
|
|
6373
|
+
const content = await readFileContent(filePath);
|
|
6374
|
+
if (content.trim()) {
|
|
6375
|
+
const filename = (0, import_node_path25.basename)(file, ".toml");
|
|
6376
|
+
try {
|
|
6377
|
+
const parsed = parse(content);
|
|
6378
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
6379
|
+
continue;
|
|
6380
|
+
}
|
|
6381
|
+
const commandConfig = parsed;
|
|
6382
|
+
if (typeof commandConfig.prompt === "string") {
|
|
6383
|
+
const description = typeof commandConfig.description === "string" ? commandConfig.description : `Command: ${filename}`;
|
|
6384
|
+
const frontmatter = {
|
|
6385
|
+
root: false,
|
|
6386
|
+
targets: ["geminicli"],
|
|
6387
|
+
description,
|
|
6388
|
+
globs: ["**/*"]
|
|
6389
|
+
};
|
|
6390
|
+
rules.push({
|
|
6391
|
+
frontmatter,
|
|
6392
|
+
content: commandConfig.prompt,
|
|
6393
|
+
filename,
|
|
6394
|
+
filepath: filePath,
|
|
6395
|
+
type: "command"
|
|
6396
|
+
});
|
|
6397
|
+
}
|
|
6398
|
+
} catch {
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
6401
|
+
}
|
|
6402
|
+
}
|
|
6403
|
+
} catch {
|
|
6404
|
+
}
|
|
6405
|
+
return rules;
|
|
6406
|
+
}
|
|
5127
6407
|
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
5128
|
-
|
|
6408
|
+
const result = await parseMemoryBasedConfiguration(baseDir, {
|
|
5129
6409
|
tool: "geminicli",
|
|
5130
6410
|
mainFileName: "GEMINI.md",
|
|
5131
6411
|
memoryDirPath: ".gemini/memories",
|
|
@@ -5136,17 +6416,23 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
5136
6416
|
additionalIgnoreFile: {
|
|
5137
6417
|
path: ".aiexclude",
|
|
5138
6418
|
parser: parseAiexclude
|
|
5139
|
-
}
|
|
5140
|
-
commandsDirPath
|
|
6419
|
+
}
|
|
6420
|
+
// commandsDirPath is removed - Gemini uses .toml files which need special handling
|
|
5141
6421
|
});
|
|
6422
|
+
const commandsDir = resolvePath(".gemini/commands", baseDir);
|
|
6423
|
+
if (await fileExists(commandsDir)) {
|
|
6424
|
+
const commandsRules = await parseGeminiCommands(commandsDir);
|
|
6425
|
+
result.rules.push(...commandsRules);
|
|
6426
|
+
}
|
|
6427
|
+
return result;
|
|
5142
6428
|
}
|
|
5143
6429
|
|
|
5144
6430
|
// src/parsers/junie.ts
|
|
5145
|
-
var
|
|
6431
|
+
var import_node_path26 = require("path");
|
|
5146
6432
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
5147
6433
|
const errors = [];
|
|
5148
6434
|
const rules = [];
|
|
5149
|
-
const guidelinesPath = (0,
|
|
6435
|
+
const guidelinesPath = (0, import_node_path26.join)(baseDir, ".junie", "guidelines.md");
|
|
5150
6436
|
if (!await fileExists(guidelinesPath)) {
|
|
5151
6437
|
errors.push(".junie/guidelines.md file not found");
|
|
5152
6438
|
return { rules, errors };
|
|
@@ -5203,6 +6489,22 @@ async function parseOpenCodeConfiguration(baseDir = process.cwd()) {
|
|
|
5203
6489
|
});
|
|
5204
6490
|
}
|
|
5205
6491
|
|
|
6492
|
+
// src/parsers/qwencode.ts
|
|
6493
|
+
async function parseQwenConfiguration(baseDir = process.cwd()) {
|
|
6494
|
+
return parseMemoryBasedConfiguration(baseDir, {
|
|
6495
|
+
tool: "qwencode",
|
|
6496
|
+
mainFileName: "QWEN.md",
|
|
6497
|
+
memoryDirPath: ".qwen/memories",
|
|
6498
|
+
settingsPath: ".qwen/settings.json",
|
|
6499
|
+
mainDescription: "Main Qwen Code configuration",
|
|
6500
|
+
memoryDescription: "Memory file",
|
|
6501
|
+
filenamePrefix: "qwen",
|
|
6502
|
+
// Qwen Code uses git-aware filtering instead of dedicated ignore files
|
|
6503
|
+
// additionalIgnoreFile is omitted
|
|
6504
|
+
commandsDirPath: ".qwen/commands"
|
|
6505
|
+
});
|
|
6506
|
+
}
|
|
6507
|
+
|
|
5206
6508
|
// src/parsers/roo.ts
|
|
5207
6509
|
async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
5208
6510
|
return parseConfigurationFiles(baseDir, {
|
|
@@ -5224,8 +6526,8 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
5224
6526
|
}
|
|
5225
6527
|
|
|
5226
6528
|
// src/parsers/windsurf.ts
|
|
5227
|
-
var
|
|
5228
|
-
var
|
|
6529
|
+
var import_promises4 = require("fs/promises");
|
|
6530
|
+
var import_node_path27 = require("path");
|
|
5229
6531
|
init_logger();
|
|
5230
6532
|
|
|
5231
6533
|
// src/core/importer.ts
|
|
@@ -5233,6 +6535,8 @@ init_logger();
|
|
|
5233
6535
|
async function importConfiguration(options) {
|
|
5234
6536
|
const {
|
|
5235
6537
|
tool,
|
|
6538
|
+
features = ["rules", "commands", "mcp", "ignore", "subagents"],
|
|
6539
|
+
// Default to all features for backward compatibility
|
|
5236
6540
|
baseDir = process.cwd(),
|
|
5237
6541
|
rulesDir = ".rulesync",
|
|
5238
6542
|
verbose = false,
|
|
@@ -5242,11 +6546,18 @@ async function importConfiguration(options) {
|
|
|
5242
6546
|
let rules = [];
|
|
5243
6547
|
let ignorePatterns;
|
|
5244
6548
|
let mcpServers;
|
|
6549
|
+
let subagents;
|
|
5245
6550
|
if (verbose) {
|
|
5246
6551
|
logger.log(`Importing ${tool} configuration from ${baseDir}...`);
|
|
5247
6552
|
}
|
|
5248
6553
|
try {
|
|
5249
6554
|
switch (tool) {
|
|
6555
|
+
case "agentsmd": {
|
|
6556
|
+
const agentsmdResult = await parseAgentsMdConfiguration(baseDir);
|
|
6557
|
+
rules = agentsmdResult.rules;
|
|
6558
|
+
errors.push(...agentsmdResult.errors);
|
|
6559
|
+
break;
|
|
6560
|
+
}
|
|
5250
6561
|
case "amazonqcli": {
|
|
5251
6562
|
const amazonqResult = await parseAmazonqcliConfiguration(baseDir);
|
|
5252
6563
|
rules = amazonqResult.rules;
|
|
@@ -5272,6 +6583,7 @@ async function importConfiguration(options) {
|
|
|
5272
6583
|
errors.push(...claudeResult.errors);
|
|
5273
6584
|
ignorePatterns = claudeResult.ignorePatterns;
|
|
5274
6585
|
mcpServers = claudeResult.mcpServers;
|
|
6586
|
+
subagents = claudeResult.subagents;
|
|
5275
6587
|
break;
|
|
5276
6588
|
}
|
|
5277
6589
|
case "cursor": {
|
|
@@ -5322,6 +6634,13 @@ async function importConfiguration(options) {
|
|
|
5322
6634
|
mcpServers = opencodeResult.mcpServers;
|
|
5323
6635
|
break;
|
|
5324
6636
|
}
|
|
6637
|
+
case "qwencode": {
|
|
6638
|
+
const qwenResult = await parseQwenConfiguration(baseDir);
|
|
6639
|
+
rules = qwenResult.rules;
|
|
6640
|
+
errors.push(...qwenResult.errors);
|
|
6641
|
+
mcpServers = qwenResult.mcpServers;
|
|
6642
|
+
break;
|
|
6643
|
+
}
|
|
5325
6644
|
default:
|
|
5326
6645
|
errors.push(`Unsupported tool: ${tool}`);
|
|
5327
6646
|
return { success: false, rulesCreated: 0, errors };
|
|
@@ -5331,10 +6650,20 @@ async function importConfiguration(options) {
|
|
|
5331
6650
|
errors.push(`Failed to parse ${tool} configuration: ${errorMessage}`);
|
|
5332
6651
|
return { success: false, rulesCreated: 0, errors };
|
|
5333
6652
|
}
|
|
5334
|
-
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
6653
|
+
if (rules.length === 0 && !ignorePatterns && !mcpServers && !subagents) {
|
|
5335
6654
|
return { success: false, rulesCreated: 0, errors };
|
|
5336
6655
|
}
|
|
5337
|
-
const
|
|
6656
|
+
const rulesEnabled = features.includes("rules") || features.includes("commands");
|
|
6657
|
+
const ignoreEnabled = features.includes("ignore");
|
|
6658
|
+
const mcpEnabled = features.includes("mcp");
|
|
6659
|
+
const subagentsEnabled = features.includes("subagents");
|
|
6660
|
+
if (!rulesEnabled && !ignoreEnabled && !mcpEnabled && !subagentsEnabled) {
|
|
6661
|
+
if (verbose) {
|
|
6662
|
+
logger.log("No relevant features enabled for import");
|
|
6663
|
+
}
|
|
6664
|
+
return { success: false, rulesCreated: 0, errors: ["No features enabled for import"] };
|
|
6665
|
+
}
|
|
6666
|
+
const rulesDirPath = (0, import_node_path28.join)(baseDir, rulesDir);
|
|
5338
6667
|
try {
|
|
5339
6668
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
5340
6669
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -5344,37 +6673,49 @@ async function importConfiguration(options) {
|
|
|
5344
6673
|
return { success: false, rulesCreated: 0, errors };
|
|
5345
6674
|
}
|
|
5346
6675
|
let rulesCreated = 0;
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
targetDir = (0, import_node_path21.join)(rulesDirPath, "rules");
|
|
6676
|
+
if (rulesEnabled) {
|
|
6677
|
+
for (const rule of rules) {
|
|
6678
|
+
try {
|
|
6679
|
+
const baseFilename = rule.filename;
|
|
6680
|
+
let targetDir = rulesDirPath;
|
|
6681
|
+
if (rule.type === "command") {
|
|
6682
|
+
if (!features.includes("commands")) {
|
|
6683
|
+
continue;
|
|
6684
|
+
}
|
|
6685
|
+
targetDir = (0, import_node_path28.join)(rulesDirPath, "commands");
|
|
5358
6686
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
5359
6687
|
await mkdir3(targetDir, { recursive: true });
|
|
6688
|
+
} else {
|
|
6689
|
+
if (!features.includes("rules")) {
|
|
6690
|
+
continue;
|
|
6691
|
+
}
|
|
6692
|
+
if (!useLegacyLocation) {
|
|
6693
|
+
targetDir = (0, import_node_path28.join)(rulesDirPath, "rules");
|
|
6694
|
+
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
6695
|
+
await mkdir3(targetDir, { recursive: true });
|
|
6696
|
+
}
|
|
5360
6697
|
}
|
|
6698
|
+
const filePath = (0, import_node_path28.join)(targetDir, `${baseFilename}.md`);
|
|
6699
|
+
const content = generateRuleFileContent(rule);
|
|
6700
|
+
await writeFileContent(filePath, content);
|
|
6701
|
+
rulesCreated++;
|
|
6702
|
+
if (verbose) {
|
|
6703
|
+
logger.success(`Created rule file: ${filePath}`);
|
|
6704
|
+
}
|
|
6705
|
+
} catch (error) {
|
|
6706
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6707
|
+
errors.push(`Failed to create rule file for ${rule.filename}: ${errorMessage}`);
|
|
5361
6708
|
}
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
if (verbose) {
|
|
5367
|
-
logger.success(`Created rule file: ${filePath}`);
|
|
5368
|
-
}
|
|
5369
|
-
} catch (error) {
|
|
5370
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5371
|
-
errors.push(`Failed to create rule file for ${rule.filename}: ${errorMessage}`);
|
|
6709
|
+
}
|
|
6710
|
+
} else {
|
|
6711
|
+
if (verbose && rules.length > 0) {
|
|
6712
|
+
logger.log(`Skipping ${rules.length} rule(s) (rules/commands features not enabled)`);
|
|
5372
6713
|
}
|
|
5373
6714
|
}
|
|
5374
6715
|
let ignoreFileCreated = false;
|
|
5375
|
-
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
6716
|
+
if (ignoreEnabled && ignorePatterns && ignorePatterns.length > 0) {
|
|
5376
6717
|
try {
|
|
5377
|
-
const rulesyncignorePath = (0,
|
|
6718
|
+
const rulesyncignorePath = (0, import_node_path28.join)(baseDir, ".rulesyncignore");
|
|
5378
6719
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
5379
6720
|
`;
|
|
5380
6721
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -5386,11 +6727,13 @@ async function importConfiguration(options) {
|
|
|
5386
6727
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5387
6728
|
errors.push(`Failed to create .rulesyncignore: ${errorMessage}`);
|
|
5388
6729
|
}
|
|
6730
|
+
} else if (verbose && ignorePatterns && ignorePatterns.length > 0 && !ignoreEnabled) {
|
|
6731
|
+
logger.log(`Skipping ignore patterns (ignore feature not enabled)`);
|
|
5389
6732
|
}
|
|
5390
6733
|
let mcpFileCreated = false;
|
|
5391
|
-
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
6734
|
+
if (mcpEnabled && mcpServers && Object.keys(mcpServers).length > 0) {
|
|
5392
6735
|
try {
|
|
5393
|
-
const mcpPath = (0,
|
|
6736
|
+
const mcpPath = (0, import_node_path28.join)(baseDir, rulesDir, ".mcp.json");
|
|
5394
6737
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
5395
6738
|
`;
|
|
5396
6739
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -5402,14 +6745,51 @@ async function importConfiguration(options) {
|
|
|
5402
6745
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5403
6746
|
errors.push(`Failed to create .mcp.json: ${errorMessage}`);
|
|
5404
6747
|
}
|
|
6748
|
+
} else if (verbose && mcpServers && Object.keys(mcpServers).length > 0 && !mcpEnabled) {
|
|
6749
|
+
logger.log(`Skipping MCP configuration (mcp feature not enabled)`);
|
|
5405
6750
|
}
|
|
5406
|
-
|
|
5407
|
-
|
|
6751
|
+
let subagentsCreated = 0;
|
|
6752
|
+
if (subagentsEnabled && subagents && subagents.length > 0) {
|
|
6753
|
+
try {
|
|
6754
|
+
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
6755
|
+
const subagentsDir = (0, import_node_path28.join)(baseDir, rulesDir, "subagents");
|
|
6756
|
+
await mkdir3(subagentsDir, { recursive: true });
|
|
6757
|
+
for (const subagent of subagents) {
|
|
6758
|
+
try {
|
|
6759
|
+
const filename = `${subagent.filename}.md`;
|
|
6760
|
+
const filepath = (0, import_node_path28.join)(subagentsDir, filename);
|
|
6761
|
+
const content = generateSubagentFileContent(subagent);
|
|
6762
|
+
await writeFileContent(filepath, content);
|
|
6763
|
+
subagentsCreated++;
|
|
6764
|
+
if (verbose) {
|
|
6765
|
+
logger.success(`Created subagent: ${filename}`);
|
|
6766
|
+
}
|
|
6767
|
+
} catch (error) {
|
|
6768
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6769
|
+
errors.push(`Failed to create subagent ${subagent.filename}: ${errorMessage}`);
|
|
6770
|
+
}
|
|
6771
|
+
}
|
|
6772
|
+
if (verbose && subagentsCreated > 0) {
|
|
6773
|
+
logger.success(`Created ${subagentsCreated} subagent files`);
|
|
6774
|
+
}
|
|
6775
|
+
} catch (error) {
|
|
6776
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6777
|
+
errors.push(`Failed to create subagents directory: ${errorMessage}`);
|
|
6778
|
+
}
|
|
6779
|
+
} else if (verbose && subagents && subagents.length > 0 && !subagentsEnabled) {
|
|
6780
|
+
logger.log(`Skipping subagents (subagents feature not enabled)`);
|
|
6781
|
+
}
|
|
6782
|
+
const result = {
|
|
6783
|
+
success: errors.length === 0 && (rulesCreated > 0 || ignoreFileCreated || mcpFileCreated || subagentsCreated > 0),
|
|
5408
6784
|
rulesCreated,
|
|
5409
6785
|
errors,
|
|
5410
6786
|
ignoreFileCreated,
|
|
5411
6787
|
mcpFileCreated
|
|
5412
6788
|
};
|
|
6789
|
+
if (subagentsCreated > 0) {
|
|
6790
|
+
result.subagentsCreated = subagentsCreated;
|
|
6791
|
+
}
|
|
6792
|
+
return result;
|
|
5413
6793
|
}
|
|
5414
6794
|
function generateRuleFileContent(rule) {
|
|
5415
6795
|
if (rule.type === "command") {
|
|
@@ -5417,69 +6797,109 @@ function generateRuleFileContent(rule) {
|
|
|
5417
6797
|
description: rule.frontmatter.description,
|
|
5418
6798
|
targets: rule.frontmatter.targets
|
|
5419
6799
|
};
|
|
5420
|
-
const frontmatter2 =
|
|
6800
|
+
const frontmatter2 = import_gray_matter3.default.stringify("", simplifiedFrontmatter);
|
|
5421
6801
|
return frontmatter2 + rule.content;
|
|
5422
6802
|
}
|
|
5423
|
-
const frontmatter =
|
|
6803
|
+
const frontmatter = import_gray_matter3.default.stringify("", rule.frontmatter);
|
|
5424
6804
|
return frontmatter + rule.content;
|
|
5425
6805
|
}
|
|
6806
|
+
function generateSubagentFileContent(subagent) {
|
|
6807
|
+
const frontmatter = import_gray_matter3.default.stringify("", subagent.frontmatter);
|
|
6808
|
+
return frontmatter + subagent.content;
|
|
6809
|
+
}
|
|
5426
6810
|
|
|
5427
6811
|
// src/cli/commands/import.ts
|
|
5428
6812
|
init_logger();
|
|
5429
6813
|
async function importCommand(options = {}) {
|
|
5430
6814
|
logger.setVerbose(options.verbose || false);
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
if (options.
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
if (
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
logger.error(
|
|
5444
|
-
"\u274C Please specify one tool to import from (--amazonqcli, --augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli, --opencode)"
|
|
6815
|
+
let resolvedFeatures;
|
|
6816
|
+
let showWarning = false;
|
|
6817
|
+
if (options.features !== void 0) {
|
|
6818
|
+
resolvedFeatures = options.features;
|
|
6819
|
+
} else {
|
|
6820
|
+
resolvedFeatures = "*";
|
|
6821
|
+
showWarning = true;
|
|
6822
|
+
}
|
|
6823
|
+
if (showWarning) {
|
|
6824
|
+
showBackwardCompatibilityWarning(
|
|
6825
|
+
"importing",
|
|
6826
|
+
"rulesync import --targets cursor,copilot --features rules,mcp,ignore"
|
|
5445
6827
|
);
|
|
6828
|
+
}
|
|
6829
|
+
const normalizedFeatures = normalizeFeatures(resolvedFeatures);
|
|
6830
|
+
let tools = [];
|
|
6831
|
+
if (options.targets && options.targets.length > 0) {
|
|
6832
|
+
tools = options.targets;
|
|
6833
|
+
} else {
|
|
6834
|
+
if (options.agentsmd) tools.push("agentsmd");
|
|
6835
|
+
if (options.amazonqcli) tools.push("amazonqcli");
|
|
6836
|
+
if (options.augmentcode) tools.push("augmentcode");
|
|
6837
|
+
if (options["augmentcode-legacy"]) tools.push("augmentcode-legacy");
|
|
6838
|
+
if (options.claudecode) tools.push("claudecode");
|
|
6839
|
+
if (options.cursor) tools.push("cursor");
|
|
6840
|
+
if (options.copilot) tools.push("copilot");
|
|
6841
|
+
if (options.cline) tools.push("cline");
|
|
6842
|
+
if (options.roo) tools.push("roo");
|
|
6843
|
+
if (options.geminicli) tools.push("geminicli");
|
|
6844
|
+
if (options.junie) tools.push("junie");
|
|
6845
|
+
if (options.qwencode) tools.push("qwencode");
|
|
6846
|
+
if (options.opencode) tools.push("opencode");
|
|
6847
|
+
}
|
|
6848
|
+
if (tools.length === 0) {
|
|
6849
|
+
logger.error("\u274C Please specify a tool to import from using --targets <tool>.");
|
|
6850
|
+
logger.info("Example: rulesync import --targets cursor");
|
|
5446
6851
|
process.exit(1);
|
|
5447
6852
|
}
|
|
5448
6853
|
if (tools.length > 1) {
|
|
5449
6854
|
logger.error(
|
|
5450
|
-
|
|
6855
|
+
`\u274C Import command only supports a single target.
|
|
6856
|
+
You specified: ${tools.join(", ")}
|
|
6857
|
+
|
|
6858
|
+
Please run the command separately for each tool:`
|
|
5451
6859
|
);
|
|
6860
|
+
for (const tool2 of tools) {
|
|
6861
|
+
logger.info(` rulesync import --targets ${tool2}`);
|
|
6862
|
+
}
|
|
5452
6863
|
process.exit(1);
|
|
5453
6864
|
}
|
|
5454
6865
|
const tool = tools[0];
|
|
5455
6866
|
if (!tool) {
|
|
5456
|
-
logger.error("
|
|
6867
|
+
logger.error("\u274C Unexpected error: No tool selected");
|
|
5457
6868
|
process.exit(1);
|
|
5458
6869
|
}
|
|
5459
6870
|
logger.log(`Importing configuration files from ${tool}...`);
|
|
5460
6871
|
try {
|
|
5461
6872
|
const result = await importConfiguration({
|
|
5462
6873
|
tool,
|
|
6874
|
+
features: normalizedFeatures,
|
|
5463
6875
|
verbose: options.verbose ?? false,
|
|
5464
6876
|
useLegacyLocation: options.legacy ?? false
|
|
5465
6877
|
});
|
|
5466
6878
|
if (result.success) {
|
|
5467
|
-
logger.success(
|
|
6879
|
+
logger.success(`\u2705 Imported ${result.rulesCreated} rule(s) from ${tool}`);
|
|
5468
6880
|
if (result.ignoreFileCreated) {
|
|
5469
|
-
logger.success("Created .rulesyncignore file from ignore patterns");
|
|
6881
|
+
logger.success(" Created .rulesyncignore file from ignore patterns");
|
|
5470
6882
|
}
|
|
5471
6883
|
if (result.mcpFileCreated) {
|
|
5472
|
-
logger.success("Created .rulesync/.mcp.json file from MCP configuration");
|
|
6884
|
+
logger.success(" Created .rulesync/.mcp.json file from MCP configuration");
|
|
6885
|
+
}
|
|
6886
|
+
if (result.subagentsCreated) {
|
|
6887
|
+
logger.success(` Created ${result.subagentsCreated} subagent files`);
|
|
5473
6888
|
}
|
|
6889
|
+
logger.success(`
|
|
6890
|
+
\u{1F389} Successfully imported from ${tool}`);
|
|
5474
6891
|
logger.log("You can now run 'rulesync generate' to create tool-specific configurations.");
|
|
5475
6892
|
} else if (result.errors.length > 0) {
|
|
5476
6893
|
logger.warn(`\u26A0\uFE0F Failed to import from ${tool}: ${result.errors[0]}`);
|
|
5477
6894
|
if (result.errors.length > 1) {
|
|
5478
|
-
logger.info("
|
|
6895
|
+
logger.info(" Detailed errors:");
|
|
5479
6896
|
for (const error of result.errors) {
|
|
5480
|
-
logger.info(`
|
|
6897
|
+
logger.info(` - ${error}`);
|
|
5481
6898
|
}
|
|
5482
6899
|
}
|
|
6900
|
+
logger.error(`
|
|
6901
|
+
\u274C Failed to import from ${tool}.`);
|
|
6902
|
+
process.exit(1);
|
|
5483
6903
|
}
|
|
5484
6904
|
} catch (error) {
|
|
5485
6905
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -5489,7 +6909,7 @@ async function importCommand(options = {}) {
|
|
|
5489
6909
|
}
|
|
5490
6910
|
|
|
5491
6911
|
// src/cli/commands/init.ts
|
|
5492
|
-
var
|
|
6912
|
+
var import_node_path29 = require("path");
|
|
5493
6913
|
init_logger();
|
|
5494
6914
|
async function initCommand(options = {}) {
|
|
5495
6915
|
const configResult = await loadConfig();
|
|
@@ -5498,7 +6918,7 @@ async function initCommand(options = {}) {
|
|
|
5498
6918
|
logger.log("Initializing rulesync...");
|
|
5499
6919
|
await ensureDir(aiRulesDir);
|
|
5500
6920
|
const useLegacy = options.legacy ?? config.legacy ?? false;
|
|
5501
|
-
const rulesDir = useLegacy ? aiRulesDir : (0,
|
|
6921
|
+
const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path29.join)(aiRulesDir, "rules");
|
|
5502
6922
|
if (!useLegacy) {
|
|
5503
6923
|
await ensureDir(rulesDir);
|
|
5504
6924
|
}
|
|
@@ -5544,7 +6964,7 @@ globs: ["**/*"]
|
|
|
5544
6964
|
- Follow single responsibility principle
|
|
5545
6965
|
`
|
|
5546
6966
|
};
|
|
5547
|
-
const filepath = (0,
|
|
6967
|
+
const filepath = (0, import_node_path29.join)(rulesDir, sampleFile.filename);
|
|
5548
6968
|
if (!await fileExists(filepath)) {
|
|
5549
6969
|
await writeFileContent(filepath, sampleFile.content);
|
|
5550
6970
|
logger.success(`Created ${filepath}`);
|
|
@@ -5661,11 +7081,11 @@ async function watchCommand() {
|
|
|
5661
7081
|
persistent: true
|
|
5662
7082
|
});
|
|
5663
7083
|
let isGenerating = false;
|
|
5664
|
-
const handleChange = async (
|
|
7084
|
+
const handleChange = async (path8) => {
|
|
5665
7085
|
if (isGenerating) return;
|
|
5666
7086
|
isGenerating = true;
|
|
5667
7087
|
logger.log(`
|
|
5668
|
-
\u{1F4DD} Detected change in ${
|
|
7088
|
+
\u{1F4DD} Detected change in ${path8}`);
|
|
5669
7089
|
try {
|
|
5670
7090
|
await generateCommand({ verbose: false });
|
|
5671
7091
|
logger.success("Regenerated configuration files");
|
|
@@ -5675,10 +7095,10 @@ async function watchCommand() {
|
|
|
5675
7095
|
isGenerating = false;
|
|
5676
7096
|
}
|
|
5677
7097
|
};
|
|
5678
|
-
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (
|
|
7098
|
+
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (path8) => {
|
|
5679
7099
|
logger.log(`
|
|
5680
|
-
\u{1F5D1}\uFE0F Removed ${
|
|
5681
|
-
handleChange(
|
|
7100
|
+
\u{1F5D1}\uFE0F Removed ${path8}`);
|
|
7101
|
+
handleChange(path8);
|
|
5682
7102
|
}).on("error", (error) => {
|
|
5683
7103
|
logger.error("Watcher error:", error);
|
|
5684
7104
|
});
|
|
@@ -5689,44 +7109,180 @@ async function watchCommand() {
|
|
|
5689
7109
|
});
|
|
5690
7110
|
}
|
|
5691
7111
|
|
|
7112
|
+
// src/cli/utils/targets-parser.ts
|
|
7113
|
+
init_logger();
|
|
7114
|
+
function parseTargets(targetsInput) {
|
|
7115
|
+
if (!targetsInput) {
|
|
7116
|
+
return [];
|
|
7117
|
+
}
|
|
7118
|
+
let targetStrings;
|
|
7119
|
+
if (Array.isArray(targetsInput)) {
|
|
7120
|
+
targetStrings = targetsInput;
|
|
7121
|
+
} else {
|
|
7122
|
+
targetStrings = targetsInput.split(",").map((target) => target.trim()).filter((target) => target.length > 0);
|
|
7123
|
+
}
|
|
7124
|
+
const results = [];
|
|
7125
|
+
const errors = [];
|
|
7126
|
+
let hasWildcard = false;
|
|
7127
|
+
for (const targetString of targetStrings) {
|
|
7128
|
+
if (targetString === "*" || targetString === "all") {
|
|
7129
|
+
hasWildcard = true;
|
|
7130
|
+
results.push(...ALL_TOOL_TARGETS);
|
|
7131
|
+
} else if (isValidToolTarget(targetString)) {
|
|
7132
|
+
results.push(targetString);
|
|
7133
|
+
} else {
|
|
7134
|
+
errors.push(targetString);
|
|
7135
|
+
}
|
|
7136
|
+
}
|
|
7137
|
+
if (hasWildcard && targetStrings.length > 1) {
|
|
7138
|
+
throw new Error(
|
|
7139
|
+
"Cannot use '*' (all tools) with specific tool targets. Use either '--targets *' for all tools, or specify individual tools."
|
|
7140
|
+
);
|
|
7141
|
+
}
|
|
7142
|
+
if (errors.length > 0) {
|
|
7143
|
+
const validTargets = ALL_TOOL_TARGETS.join(", ");
|
|
7144
|
+
throw new Error(
|
|
7145
|
+
`Invalid tool targets: ${errors.join(", ")}. Valid targets are: ${validTargets}, *, all`
|
|
7146
|
+
);
|
|
7147
|
+
}
|
|
7148
|
+
return [...new Set(results)];
|
|
7149
|
+
}
|
|
7150
|
+
function isValidToolTarget(target) {
|
|
7151
|
+
return ALL_TOOL_TARGETS.includes(target);
|
|
7152
|
+
}
|
|
7153
|
+
function checkDeprecatedFlags(options) {
|
|
7154
|
+
const deprecatedTools = [];
|
|
7155
|
+
const flagToToolMap = {
|
|
7156
|
+
agentsmd: "agentsmd",
|
|
7157
|
+
amazonqcli: "amazonqcli",
|
|
7158
|
+
augmentcode: "augmentcode",
|
|
7159
|
+
"augmentcode-legacy": "augmentcode-legacy",
|
|
7160
|
+
copilot: "copilot",
|
|
7161
|
+
cursor: "cursor",
|
|
7162
|
+
cline: "cline",
|
|
7163
|
+
codexcli: "codexcli",
|
|
7164
|
+
claudecode: "claudecode",
|
|
7165
|
+
roo: "roo",
|
|
7166
|
+
geminicli: "geminicli",
|
|
7167
|
+
junie: "junie",
|
|
7168
|
+
qwencode: "qwencode",
|
|
7169
|
+
kiro: "kiro",
|
|
7170
|
+
opencode: "opencode",
|
|
7171
|
+
windsurf: "windsurf"
|
|
7172
|
+
};
|
|
7173
|
+
for (const [flag, tool] of Object.entries(flagToToolMap)) {
|
|
7174
|
+
if (options[flag]) {
|
|
7175
|
+
deprecatedTools.push(tool);
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
return deprecatedTools;
|
|
7179
|
+
}
|
|
7180
|
+
function getDeprecationWarning(deprecatedTools, command = "generate") {
|
|
7181
|
+
const toolsStr = deprecatedTools.join(",");
|
|
7182
|
+
return [
|
|
7183
|
+
"\u26A0\uFE0F DEPRECATED: Individual tool flags are deprecated and will be removed in a future version.",
|
|
7184
|
+
` Current: rulesync ${command} ${deprecatedTools.map((t) => `--${t}`).join(" ")}`,
|
|
7185
|
+
` New: rulesync ${command} --targets ${toolsStr}`,
|
|
7186
|
+
" Please update your scripts to use the new --targets flag."
|
|
7187
|
+
].join("\n");
|
|
7188
|
+
}
|
|
7189
|
+
function mergeAndDeduplicateTools(targetsTools, deprecatedTools, allFlag) {
|
|
7190
|
+
if (allFlag) {
|
|
7191
|
+
logger.warn(
|
|
7192
|
+
[
|
|
7193
|
+
"\u26A0\uFE0F DEPRECATED: The --all flag is deprecated and will be removed in a future version.",
|
|
7194
|
+
" Current: rulesync generate --all",
|
|
7195
|
+
" New: rulesync generate --targets *",
|
|
7196
|
+
" Please update your scripts to use the new --targets flag."
|
|
7197
|
+
].join("\n")
|
|
7198
|
+
);
|
|
7199
|
+
return [...ALL_TOOL_TARGETS];
|
|
7200
|
+
}
|
|
7201
|
+
const allTools = [...targetsTools, ...deprecatedTools];
|
|
7202
|
+
return [...new Set(allTools)];
|
|
7203
|
+
}
|
|
7204
|
+
|
|
5692
7205
|
// src/cli/index.ts
|
|
5693
7206
|
var program = new import_commander.Command();
|
|
5694
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
7207
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.67.0");
|
|
5695
7208
|
program.command("init").description("Initialize rulesync in current directory").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(initCommand);
|
|
5696
7209
|
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);
|
|
5697
7210
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
5698
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("
|
|
5699
|
-
|
|
7211
|
+
program.command("import").description("Import configurations from AI tools to rulesync format").option("-t, --targets <tool>", "Tool to import from (e.g., 'copilot', 'cursor', 'cline')").option(
|
|
7212
|
+
"--features <features>",
|
|
7213
|
+
`Comma-separated list of features to import (${FEATURE_TYPES.join(",")}) or '*' for all`,
|
|
7214
|
+
(value) => {
|
|
7215
|
+
if (value === "*") return "*";
|
|
7216
|
+
return value.split(",").map((f) => f.trim()).filter(Boolean);
|
|
7217
|
+
}
|
|
7218
|
+
).option("--agentsmd", "[DEPRECATED] Import from AGENTS.md (use --targets agentsmd)").option("--augmentcode", "[DEPRECATED] Import from AugmentCode (use --targets augmentcode)").option(
|
|
7219
|
+
"--augmentcode-legacy",
|
|
7220
|
+
"[DEPRECATED] Import from AugmentCode legacy format (use --targets augmentcode-legacy)"
|
|
7221
|
+
).option("--claudecode", "[DEPRECATED] Import from Claude Code (use --targets claudecode)").option("--cursor", "[DEPRECATED] Import from Cursor (use --targets cursor)").option("--copilot", "[DEPRECATED] Import from GitHub Copilot (use --targets copilot)").option("--cline", "[DEPRECATED] Import from Cline (use --targets cline)").option("--roo", "[DEPRECATED] Import from Roo Code (use --targets roo)").option("--geminicli", "[DEPRECATED] Import from Gemini CLI (use --targets geminicli)").option("--junie", "[DEPRECATED] Import from JetBrains Junie (use --targets junie)").option("--qwencode", "[DEPRECATED] Import from Qwen Code (use --targets qwencode)").option("--opencode", "[DEPRECATED] Import from OpenCode (use --targets opencode)").option("-v, --verbose", "Verbose output").option("--legacy", "Use legacy file location (.rulesync/*.md instead of .rulesync/rules/*.md)").action(async (options) => {
|
|
7222
|
+
try {
|
|
7223
|
+
let tools = [];
|
|
7224
|
+
const targetsTools = options.targets ? parseTargets(options.targets) : [];
|
|
7225
|
+
const deprecatedTools = checkDeprecatedFlags(options);
|
|
7226
|
+
if (deprecatedTools.length > 0) {
|
|
7227
|
+
logger.warn(getDeprecationWarning(deprecatedTools, "import"));
|
|
7228
|
+
}
|
|
7229
|
+
tools = mergeAndDeduplicateTools(targetsTools, deprecatedTools, false);
|
|
7230
|
+
const importOptions = {
|
|
7231
|
+
...tools.length > 0 && { targets: tools },
|
|
7232
|
+
...options.features && { features: options.features },
|
|
7233
|
+
verbose: options.verbose,
|
|
7234
|
+
legacy: options.legacy
|
|
7235
|
+
};
|
|
7236
|
+
await importCommand(importOptions);
|
|
7237
|
+
} catch (error) {
|
|
7238
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
7239
|
+
process.exit(1);
|
|
7240
|
+
}
|
|
7241
|
+
});
|
|
7242
|
+
program.command("generate").description("Generate configuration files for AI tools").option("--all", "[DEPRECATED] Generate for all supported AI tools (use --targets * instead)").option(
|
|
7243
|
+
"-t, --targets <tools>",
|
|
7244
|
+
"Comma-separated list of tools to generate for (e.g., 'copilot,cursor,cline' or '*' for all)"
|
|
7245
|
+
).option(
|
|
7246
|
+
"--features <features>",
|
|
7247
|
+
`Comma-separated list of features to generate (${FEATURE_TYPES.join(",")}) or '*' for all`,
|
|
7248
|
+
(value) => {
|
|
7249
|
+
if (value === "*") return "*";
|
|
7250
|
+
return value.split(",").map((f) => f.trim()).filter(Boolean);
|
|
7251
|
+
}
|
|
7252
|
+
).option("--agentsmd", "[DEPRECATED] Generate only for AGENTS.md (use --targets agentsmd)").option(
|
|
7253
|
+
"--amazonqcli",
|
|
7254
|
+
"[DEPRECATED] Generate only for Amazon Q Developer CLI (use --targets amazonqcli)"
|
|
7255
|
+
).option("--augmentcode", "[DEPRECATED] Generate only for AugmentCode (use --targets augmentcode)").option(
|
|
7256
|
+
"--augmentcode-legacy",
|
|
7257
|
+
"[DEPRECATED] Generate only for AugmentCode legacy format (use --targets augmentcode-legacy)"
|
|
7258
|
+
).option("--copilot", "[DEPRECATED] Generate only for GitHub Copilot (use --targets copilot)").option("--cursor", "[DEPRECATED] Generate only for Cursor (use --targets cursor)").option("--cline", "[DEPRECATED] Generate only for Cline (use --targets cline)").option("--codexcli", "[DEPRECATED] Generate only for OpenAI Codex CLI (use --targets codexcli)").option("--claudecode", "[DEPRECATED] Generate only for Claude Code (use --targets claudecode)").option("--roo", "[DEPRECATED] Generate only for Roo Code (use --targets roo)").option("--geminicli", "[DEPRECATED] Generate only for Gemini CLI (use --targets geminicli)").option("--junie", "[DEPRECATED] Generate only for JetBrains Junie (use --targets junie)").option("--qwencode", "[DEPRECATED] Generate only for Qwen Code (use --targets qwencode)").option("--kiro", "[DEPRECATED] Generate only for Kiro IDE (use --targets kiro)").option("--opencode", "[DEPRECATED] Generate only for OpenCode (use --targets opencode)").option("--windsurf", "[DEPRECATED] Generate only for Windsurf (use --targets windsurf)").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
5700
7259
|
"-b, --base-dir <paths>",
|
|
5701
7260
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
5702
7261
|
).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
if (options.baseDir) {
|
|
5727
|
-
generateOptions.baseDirs = options.baseDir.split(",").map((dir) => dir.trim()).filter((dir) => dir.length > 0);
|
|
7262
|
+
try {
|
|
7263
|
+
let tools = [];
|
|
7264
|
+
const targetsTools = options.targets ? parseTargets(options.targets) : [];
|
|
7265
|
+
const deprecatedTools = checkDeprecatedFlags(options);
|
|
7266
|
+
if (deprecatedTools.length > 0) {
|
|
7267
|
+
logger.warn(getDeprecationWarning(deprecatedTools, "generate"));
|
|
7268
|
+
}
|
|
7269
|
+
tools = mergeAndDeduplicateTools(targetsTools, deprecatedTools, options.all === true);
|
|
7270
|
+
const generateOptions = {
|
|
7271
|
+
verbose: options.verbose,
|
|
7272
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
7273
|
+
features: options.features,
|
|
7274
|
+
delete: options.delete,
|
|
7275
|
+
config: options.config,
|
|
7276
|
+
noConfig: options.noConfig
|
|
7277
|
+
};
|
|
7278
|
+
if (options.baseDir) {
|
|
7279
|
+
generateOptions.baseDirs = options.baseDir.split(",").map((dir) => dir.trim()).filter((dir) => dir.length > 0);
|
|
7280
|
+
}
|
|
7281
|
+
await generateCommand(generateOptions);
|
|
7282
|
+
} catch (error) {
|
|
7283
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
7284
|
+
process.exit(1);
|
|
5728
7285
|
}
|
|
5729
|
-
await generateCommand(generateOptions);
|
|
5730
7286
|
});
|
|
5731
7287
|
program.command("validate").description("Validate rulesync configuration").action(validateCommand);
|
|
5732
7288
|
program.command("status").description("Show current status of rulesync").action(statusCommand);
|