rulesync 0.65.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 +86 -47
- package/dist/{amazonqcli-MW7XTVPN.js → amazonqcli-PWXCSRAN.js} +2 -2
- package/dist/{augmentcode-WCZCL7VR.js → augmentcode-4AFYW4BU.js} +2 -2
- package/dist/{chunk-YC2BC7Z2.js → chunk-35VMCHXQ.js} +1 -1
- package/dist/{chunk-6SLEITCQ.js → chunk-3QGD3CH5.js} +1 -1
- package/dist/{chunk-VRWNZTGW.js → chunk-5GKH5TQ4.js} +1 -1
- package/dist/{chunk-4NWMCTN5.js → chunk-7BIZ5Y6F.js} +1 -1
- package/dist/{chunk-LTWEI4PW.js → chunk-7QVQO6MQ.js} +1 -1
- package/dist/{chunk-UGY5ALND.js → chunk-B2HD24KC.js} +1 -1
- package/dist/{chunk-M2AUM37M.js → chunk-CS7AV6JT.js} +1 -0
- package/dist/{chunk-6AXPFPKI.js → chunk-KONQNQY3.js} +1 -1
- package/dist/{chunk-FL5BF6JM.js → chunk-OARJESSZ.js} +1 -1
- package/dist/{chunk-JXOLLTNV.js → chunk-V36ICGOY.js} +1 -1
- package/dist/{chunk-GIAQWZQ4.js → chunk-WCON5BAI.js} +1 -1
- package/dist/{chunk-DM2B7XUB.js → chunk-WFOWHPBC.js} +1 -1
- package/dist/{chunk-N6DASHJL.js → chunk-WYYQXVHC.js} +1 -1
- package/dist/{chunk-I4NVS7GE.js → chunk-YZUDL4GW.js} +1 -1
- package/dist/{chunk-TX2CE4RR.js → chunk-ZMGXHLYP.js} +1 -1
- package/dist/{claudecode-RZSJPPBU.js → claudecode-OC7VHCF6.js} +3 -3
- package/dist/{cline-JTWWBQQ4.js → cline-A4KFSAQE.js} +3 -3
- package/dist/{codexcli-ATMFGRJR.js → codexcli-YP3X7FWB.js} +3 -3
- package/dist/{copilot-H3CLGKDP.js → copilot-3LIMXQ7O.js} +2 -2
- package/dist/{cursor-ZUN5RZU6.js → cursor-QV72CDJC.js} +3 -3
- package/dist/{geminicli-Q5HPIQCU.js → geminicli-XPSJJS65.js} +3 -3
- package/dist/index.cjs +1888 -518
- package/dist/index.js +1866 -511
- package/dist/{junie-JCLVC3MI.js → junie-265XIW43.js} +3 -3
- package/dist/{kiro-CNF6433S.js → kiro-6OHFHN5X.js} +2 -2
- package/dist/{opencode-EBS3CED2.js → opencode-C5QAYVJ5.js} +2 -2
- package/dist/{qwencode-JIT6KW7E.js → qwencode-5RR24UW6.js} +3 -3
- package/dist/{roo-KBTRH4TZ.js → roo-5IXVBUHD.js} +3 -3
- package/dist/{windsurf-ZAAWL6JJ.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",
|
|
@@ -57,10 +58,10 @@ var init_tool_targets = __esm({
|
|
|
57
58
|
"junie",
|
|
58
59
|
"windsurf"
|
|
59
60
|
];
|
|
60
|
-
ToolTargetSchema =
|
|
61
|
-
ToolTargetsSchema =
|
|
62
|
-
WildcardTargetSchema =
|
|
63
|
-
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]);
|
|
64
65
|
}
|
|
65
66
|
});
|
|
66
67
|
|
|
@@ -162,8 +163,8 @@ async function findRuleFiles(aiRulesDir) {
|
|
|
162
163
|
newLocationFiles.map((file) => file.split("/").pop()?.replace(/\.md$/, ""))
|
|
163
164
|
);
|
|
164
165
|
const filteredLegacyFiles = legacyLocationFiles.filter((file) => {
|
|
165
|
-
const
|
|
166
|
-
return !newLocationBasenames.has(
|
|
166
|
+
const basename7 = file.split("/").pop()?.replace(/\.md$/, "");
|
|
167
|
+
return !newLocationBasenames.has(basename7);
|
|
167
168
|
});
|
|
168
169
|
return [...newLocationFiles, ...filteredLegacyFiles];
|
|
169
170
|
}
|
|
@@ -1305,103 +1306,120 @@ var init_opencode = __esm({
|
|
|
1305
1306
|
// src/cli/index.ts
|
|
1306
1307
|
var import_commander = require("commander");
|
|
1307
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
|
+
|
|
1378
|
+
// src/cli/commands/add.ts
|
|
1379
|
+
var import_promises = require("fs/promises");
|
|
1380
|
+
var path = __toESM(require("path"), 1);
|
|
1381
|
+
|
|
1382
|
+
// src/utils/config-loader.ts
|
|
1383
|
+
var import_c12 = require("c12");
|
|
1384
|
+
var import_core = require("zod/v4/core");
|
|
1385
|
+
|
|
1308
1386
|
// src/types/claudecode.ts
|
|
1309
|
-
var
|
|
1310
|
-
var ClaudeSettingsSchema =
|
|
1311
|
-
permissions:
|
|
1312
|
-
|
|
1313
|
-
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()), [])
|
|
1314
1392
|
}),
|
|
1315
1393
|
{ deny: [] }
|
|
1316
1394
|
)
|
|
1317
1395
|
});
|
|
1318
1396
|
|
|
1319
1397
|
// src/types/shared.ts
|
|
1320
|
-
var
|
|
1398
|
+
var import_mini4 = require("zod/mini");
|
|
1321
1399
|
init_tool_targets();
|
|
1322
|
-
var OutputSchema =
|
|
1400
|
+
var OutputSchema = import_mini4.z.object({
|
|
1323
1401
|
tool: ToolTargetSchema,
|
|
1324
|
-
filepath:
|
|
1325
|
-
content:
|
|
1402
|
+
filepath: import_mini4.z.string(),
|
|
1403
|
+
content: import_mini4.z.string()
|
|
1326
1404
|
});
|
|
1327
|
-
var BaseFrontmatterSchema =
|
|
1328
|
-
description:
|
|
1405
|
+
var BaseFrontmatterSchema = import_mini4.z.object({
|
|
1406
|
+
description: import_mini4.z.optional(import_mini4.z.string())
|
|
1329
1407
|
});
|
|
1330
1408
|
|
|
1331
1409
|
// src/types/commands.ts
|
|
1332
1410
|
var CommandFrontmatterSchema = BaseFrontmatterSchema;
|
|
1333
1411
|
|
|
1334
1412
|
// src/types/config.ts
|
|
1335
|
-
var import_mini4 = require("zod/mini");
|
|
1336
|
-
init_tool_targets();
|
|
1337
|
-
var ConfigSchema = import_mini4.z.object({
|
|
1338
|
-
aiRulesDir: import_mini4.z.string(),
|
|
1339
|
-
outputPaths: import_mini4.z.record(ToolTargetSchema, import_mini4.z.string()),
|
|
1340
|
-
watchEnabled: import_mini4.z.boolean(),
|
|
1341
|
-
defaultTargets: ToolTargetsSchema,
|
|
1342
|
-
claudecodeCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
1343
|
-
geminicliCommands: import_mini4.z.optional(import_mini4.z.string()),
|
|
1344
|
-
legacy: import_mini4.z.optional(import_mini4.z.boolean())
|
|
1345
|
-
});
|
|
1346
|
-
|
|
1347
|
-
// src/types/config-options.ts
|
|
1348
1413
|
var import_mini5 = require("zod/mini");
|
|
1349
1414
|
init_tool_targets();
|
|
1350
|
-
var
|
|
1351
|
-
amazonqcli: import_mini5.z.optional(import_mini5.z.string()),
|
|
1352
|
-
augmentcode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1353
|
-
"augmentcode-legacy": import_mini5.z.optional(import_mini5.z.string()),
|
|
1354
|
-
copilot: import_mini5.z.optional(import_mini5.z.string()),
|
|
1355
|
-
cursor: import_mini5.z.optional(import_mini5.z.string()),
|
|
1356
|
-
cline: import_mini5.z.optional(import_mini5.z.string()),
|
|
1357
|
-
claudecode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1358
|
-
codexcli: import_mini5.z.optional(import_mini5.z.string()),
|
|
1359
|
-
opencode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1360
|
-
qwencode: import_mini5.z.optional(import_mini5.z.string()),
|
|
1361
|
-
roo: import_mini5.z.optional(import_mini5.z.string()),
|
|
1362
|
-
geminicli: import_mini5.z.optional(import_mini5.z.string()),
|
|
1363
|
-
kiro: import_mini5.z.optional(import_mini5.z.string()),
|
|
1364
|
-
junie: import_mini5.z.optional(import_mini5.z.string()),
|
|
1365
|
-
windsurf: import_mini5.z.optional(import_mini5.z.string())
|
|
1366
|
-
});
|
|
1367
|
-
var ConfigOptionsSchema = import_mini5.z.object({
|
|
1368
|
-
aiRulesDir: import_mini5.z.optional(import_mini5.z.string()),
|
|
1369
|
-
outputPaths: import_mini5.z.optional(OutputPathsSchema),
|
|
1370
|
-
watchEnabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1371
|
-
defaultTargets: import_mini5.z.optional(ToolTargetsSchema),
|
|
1372
|
-
targets: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
1373
|
-
exclude: import_mini5.z.optional(import_mini5.z.array(ToolTargetSchema)),
|
|
1374
|
-
verbose: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1375
|
-
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1376
|
-
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
1377
|
-
legacy: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1378
|
-
watch: import_mini5.z.optional(
|
|
1379
|
-
import_mini5.z.object({
|
|
1380
|
-
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1381
|
-
interval: import_mini5.z.optional(import_mini5.z.number()),
|
|
1382
|
-
ignore: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
1383
|
-
})
|
|
1384
|
-
)
|
|
1385
|
-
});
|
|
1386
|
-
var MergedConfigSchema = import_mini5.z.object({
|
|
1415
|
+
var ConfigSchema = import_mini5.z.object({
|
|
1387
1416
|
aiRulesDir: import_mini5.z.string(),
|
|
1388
1417
|
outputPaths: import_mini5.z.record(ToolTargetSchema, import_mini5.z.string()),
|
|
1389
1418
|
watchEnabled: import_mini5.z.boolean(),
|
|
1390
1419
|
defaultTargets: ToolTargetsSchema,
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
delete: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1395
|
-
baseDir: import_mini5.z.optional(import_mini5.z.union([import_mini5.z.string(), import_mini5.z.array(import_mini5.z.string())])),
|
|
1396
|
-
configPath: import_mini5.z.optional(import_mini5.z.string()),
|
|
1397
|
-
legacy: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1398
|
-
watch: import_mini5.z.optional(
|
|
1399
|
-
import_mini5.z.object({
|
|
1400
|
-
enabled: import_mini5.z.optional(import_mini5.z.boolean()),
|
|
1401
|
-
interval: import_mini5.z.optional(import_mini5.z.number()),
|
|
1402
|
-
ignore: import_mini5.z.optional(import_mini5.z.array(import_mini5.z.string()))
|
|
1403
|
-
})
|
|
1404
|
-
)
|
|
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())
|
|
1405
1423
|
});
|
|
1406
1424
|
|
|
1407
1425
|
// src/types/mcp.ts
|
|
@@ -1459,20 +1477,13 @@ var GenerateOptionsSchema = import_mini7.z.object({
|
|
|
1459
1477
|
// src/types/index.ts
|
|
1460
1478
|
init_tool_targets();
|
|
1461
1479
|
|
|
1462
|
-
// src/cli/commands/add.ts
|
|
1463
|
-
var import_promises = require("fs/promises");
|
|
1464
|
-
var path = __toESM(require("path"), 1);
|
|
1465
|
-
|
|
1466
|
-
// src/utils/config-loader.ts
|
|
1467
|
-
var import_c12 = require("c12");
|
|
1468
|
-
var import_core = require("zod/v4/core");
|
|
1469
|
-
|
|
1470
1480
|
// src/utils/config.ts
|
|
1471
1481
|
init_tool_targets();
|
|
1472
1482
|
function getDefaultConfig() {
|
|
1473
1483
|
return {
|
|
1474
1484
|
aiRulesDir: ".rulesync",
|
|
1475
1485
|
outputPaths: {
|
|
1486
|
+
agentsmd: ".agents/memories",
|
|
1476
1487
|
amazonqcli: ".amazonq/rules",
|
|
1477
1488
|
augmentcode: ".",
|
|
1478
1489
|
"augmentcode-legacy": ".",
|
|
@@ -1590,6 +1601,11 @@ function generateMinimalConfig(options) {
|
|
|
1590
1601
|
if (comma) lines[lines.length - 1] += comma;
|
|
1591
1602
|
lines.push(` "exclude": ${JSON.stringify(options.exclude)}`);
|
|
1592
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
|
+
}
|
|
1593
1609
|
if (options.aiRulesDir) {
|
|
1594
1610
|
const comma = lines.length > 1 ? "," : "";
|
|
1595
1611
|
if (comma) lines[lines.length - 1] += comma;
|
|
@@ -1630,6 +1646,7 @@ function generateMinimalConfig(options) {
|
|
|
1630
1646
|
function generateSampleConfig(options) {
|
|
1631
1647
|
const targets = options?.targets || ALL_TOOL_TARGETS;
|
|
1632
1648
|
const excludeValue = options?.exclude ? JSON.stringify(options.exclude) : null;
|
|
1649
|
+
const featuresValue = options?.features || ["rules", "commands", "mcp", "ignore", "subagents"];
|
|
1633
1650
|
const aiRulesDir = options?.aiRulesDir || null;
|
|
1634
1651
|
const baseDir = options?.baseDir || null;
|
|
1635
1652
|
const deleteFlag = options?.delete || false;
|
|
@@ -1641,6 +1658,10 @@ function generateSampleConfig(options) {
|
|
|
1641
1658
|
|
|
1642
1659
|
// Tools to exclude from generation (overrides targets)
|
|
1643
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)},
|
|
1644
1665
|
${aiRulesDir ? `
|
|
1645
1666
|
// Directory containing AI rule files
|
|
1646
1667
|
"aiRulesDir": "${aiRulesDir}",` : ""}
|
|
@@ -1671,23 +1692,6 @@ function generateSampleConfig(options) {
|
|
|
1671
1692
|
}
|
|
1672
1693
|
`;
|
|
1673
1694
|
}
|
|
1674
|
-
function mergeWithCliOptions(config, cliOptions) {
|
|
1675
|
-
const merged = { ...config };
|
|
1676
|
-
if (cliOptions.verbose !== void 0) {
|
|
1677
|
-
merged.verbose = cliOptions.verbose;
|
|
1678
|
-
}
|
|
1679
|
-
if (cliOptions.delete !== void 0) {
|
|
1680
|
-
merged.delete = cliOptions.delete;
|
|
1681
|
-
}
|
|
1682
|
-
if (cliOptions.baseDirs && cliOptions.baseDirs.length > 0) {
|
|
1683
|
-
merged.baseDir = cliOptions.baseDirs;
|
|
1684
|
-
}
|
|
1685
|
-
if (cliOptions.tools && cliOptions.tools.length > 0) {
|
|
1686
|
-
merged.defaultTargets = cliOptions.tools;
|
|
1687
|
-
merged.exclude = void 0;
|
|
1688
|
-
}
|
|
1689
|
-
return merged;
|
|
1690
|
-
}
|
|
1691
1695
|
|
|
1692
1696
|
// src/cli/commands/add.ts
|
|
1693
1697
|
init_logger();
|
|
@@ -1796,6 +1800,11 @@ Default Targets: ${config.defaultTargets.join(", ")}`);
|
|
|
1796
1800
|
if (config.exclude && config.exclude.length > 0) {
|
|
1797
1801
|
logger.log(`Excluded Targets: ${config.exclude.join(", ")}`);
|
|
1798
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
|
+
}
|
|
1799
1808
|
logger.log("\nOutput Paths:");
|
|
1800
1809
|
for (const [tool, outputPath] of Object.entries(config.outputPaths)) {
|
|
1801
1810
|
logger.log(` ${tool}: ${outputPath}`);
|
|
@@ -1926,6 +1935,10 @@ const config: ConfigOptions = {
|
|
|
1926
1935
|
// Available: ${ALL_TOOL_TARGETS.join(", ")}
|
|
1927
1936
|
targets: ${JSON.stringify(ALL_TOOL_TARGETS)},
|
|
1928
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
|
+
|
|
1929
1942
|
// Custom output paths for specific tools
|
|
1930
1943
|
// outputPaths: {
|
|
1931
1944
|
// copilot: ".github/copilot-instructions.md",
|
|
@@ -1947,6 +1960,9 @@ export default config;`;
|
|
|
1947
1960
|
if (options.exclude) {
|
|
1948
1961
|
configLines.push(` exclude: ${JSON.stringify(options.exclude)}`);
|
|
1949
1962
|
}
|
|
1963
|
+
if (options.features) {
|
|
1964
|
+
configLines.push(` features: ${JSON.stringify(options.features)}`);
|
|
1965
|
+
}
|
|
1950
1966
|
if (options.aiRulesDir) {
|
|
1951
1967
|
configLines.push(` aiRulesDir: "${options.aiRulesDir}"`);
|
|
1952
1968
|
}
|
|
@@ -1979,7 +1995,7 @@ export default config;
|
|
|
1979
1995
|
}
|
|
1980
1996
|
|
|
1981
1997
|
// src/cli/commands/generate.ts
|
|
1982
|
-
var
|
|
1998
|
+
var import_node_path18 = require("path");
|
|
1983
1999
|
|
|
1984
2000
|
// src/core/command-generator.ts
|
|
1985
2001
|
var import_node_path5 = require("path");
|
|
@@ -2248,8 +2264,475 @@ async function generateCommands(projectRoot, baseDir, targets) {
|
|
|
2248
2264
|
return outputs;
|
|
2249
2265
|
}
|
|
2250
2266
|
|
|
2251
|
-
// 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
|
|
2252
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");
|
|
2253
2736
|
|
|
2254
2737
|
// src/generators/ignore/shared-helpers.ts
|
|
2255
2738
|
function extractIgnorePatternsFromRules(rules) {
|
|
@@ -2372,7 +2855,7 @@ function generateIgnoreFile(rules, config, ignoreConfig, baseDir) {
|
|
|
2372
2855
|
const outputs = [];
|
|
2373
2856
|
const content = generateIgnoreContent(rules, ignoreConfig);
|
|
2374
2857
|
const outputPath = baseDir || process.cwd();
|
|
2375
|
-
const filepath = (0,
|
|
2858
|
+
const filepath = (0, import_node_path7.join)(outputPath, ignoreConfig.filename);
|
|
2376
2859
|
outputs.push({
|
|
2377
2860
|
tool: ignoreConfig.tool,
|
|
2378
2861
|
filepath,
|
|
@@ -2955,7 +3438,7 @@ async function generateKiroIgnoreFiles(rules, config, baseDir) {
|
|
|
2955
3438
|
}
|
|
2956
3439
|
|
|
2957
3440
|
// src/generators/ignore/qwencode.ts
|
|
2958
|
-
var
|
|
3441
|
+
var import_node_path8 = require("path");
|
|
2959
3442
|
function extractQwenCodeFileFilteringPatterns(content) {
|
|
2960
3443
|
const filtering = {};
|
|
2961
3444
|
const configBlocks = content.match(/```(?:json|javascript)\s*\n([\s\S]*?)\n```/g);
|
|
@@ -3005,7 +3488,7 @@ async function generateQwenCodeIgnoreFiles(rules, config, baseDir) {
|
|
|
3005
3488
|
const outputs = [];
|
|
3006
3489
|
const outputPath = baseDir || process.cwd();
|
|
3007
3490
|
const qwenConfig = generateQwenCodeConfiguration(rules);
|
|
3008
|
-
const settingsPath = (0,
|
|
3491
|
+
const settingsPath = (0, import_node_path8.join)(outputPath, ".qwen", "settings.json");
|
|
3009
3492
|
outputs.push({
|
|
3010
3493
|
tool: "qwencode",
|
|
3011
3494
|
filepath: settingsPath,
|
|
@@ -3020,12 +3503,48 @@ function generateWindsurfIgnore(rules, config, baseDir) {
|
|
|
3020
3503
|
return generateIgnoreFile(rules, config, ignoreConfigs.windsurf, baseDir);
|
|
3021
3504
|
}
|
|
3022
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
|
+
|
|
3023
3542
|
// src/generators/rules/shared-helpers.ts
|
|
3024
|
-
var
|
|
3543
|
+
var import_node_path10 = require("path");
|
|
3025
3544
|
init_file();
|
|
3026
3545
|
|
|
3027
3546
|
// src/utils/ignore.ts
|
|
3028
|
-
var
|
|
3547
|
+
var import_node_path9 = require("path");
|
|
3029
3548
|
var import_micromatch = __toESM(require("micromatch"), 1);
|
|
3030
3549
|
init_file();
|
|
3031
3550
|
init_logger();
|
|
@@ -3034,7 +3553,7 @@ async function loadIgnorePatterns(baseDir = process.cwd()) {
|
|
|
3034
3553
|
if (cachedIgnorePatterns) {
|
|
3035
3554
|
return cachedIgnorePatterns;
|
|
3036
3555
|
}
|
|
3037
|
-
const ignorePath = (0,
|
|
3556
|
+
const ignorePath = (0, import_node_path9.join)(baseDir, ".rulesyncignore");
|
|
3038
3557
|
if (!await fileExists(ignorePath)) {
|
|
3039
3558
|
cachedIgnorePatterns = { patterns: [] };
|
|
3040
3559
|
return cachedIgnorePatterns;
|
|
@@ -3088,21 +3607,35 @@ function addOutput(outputs, tool, config, baseDir, relativePath, content) {
|
|
|
3088
3607
|
const outputDir = resolveOutputDir(config, tool, baseDir);
|
|
3089
3608
|
outputs.push({
|
|
3090
3609
|
tool,
|
|
3091
|
-
filepath: (0,
|
|
3610
|
+
filepath: (0, import_node_path10.join)(outputDir, relativePath),
|
|
3092
3611
|
content
|
|
3093
3612
|
});
|
|
3094
3613
|
}
|
|
3095
3614
|
async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
3096
3615
|
const outputs = [];
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
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);
|
|
3101
3623
|
outputs.push({
|
|
3102
3624
|
tool: generatorConfig.tool,
|
|
3103
3625
|
filepath,
|
|
3104
3626
|
content
|
|
3105
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
|
+
}
|
|
3106
3639
|
}
|
|
3107
3640
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
3108
3641
|
if (ignorePatterns.patterns.length > 0 && generatorConfig.ignoreFileName) {
|
|
@@ -3125,7 +3658,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
3125
3658
|
for (const rule of detailRules) {
|
|
3126
3659
|
const content = generatorConfig.generateDetailContent(rule);
|
|
3127
3660
|
const filepath = resolvePath(
|
|
3128
|
-
(0,
|
|
3661
|
+
(0, import_node_path10.join)(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
3129
3662
|
baseDir
|
|
3130
3663
|
);
|
|
3131
3664
|
outputs.push({
|
|
@@ -3233,7 +3766,7 @@ function generateRuleFile(rule) {
|
|
|
3233
3766
|
}
|
|
3234
3767
|
|
|
3235
3768
|
// src/generators/rules/augmentcode.ts
|
|
3236
|
-
var
|
|
3769
|
+
var import_node_path11 = require("path");
|
|
3237
3770
|
async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
3238
3771
|
const outputs = createOutputsArray();
|
|
3239
3772
|
rules.forEach((rule) => {
|
|
@@ -3242,7 +3775,7 @@ async function generateAugmentcodeConfig(rules, config, baseDir) {
|
|
|
3242
3775
|
"augmentcode",
|
|
3243
3776
|
config,
|
|
3244
3777
|
baseDir,
|
|
3245
|
-
(0,
|
|
3778
|
+
(0, import_node_path11.join)(".augment", "rules", `${rule.filename}.md`),
|
|
3246
3779
|
generateRuleFile2(rule)
|
|
3247
3780
|
);
|
|
3248
3781
|
});
|
|
@@ -3295,7 +3828,7 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
3295
3828
|
}
|
|
3296
3829
|
|
|
3297
3830
|
// src/generators/rules/claudecode.ts
|
|
3298
|
-
var
|
|
3831
|
+
var import_node_path12 = require("path");
|
|
3299
3832
|
init_file();
|
|
3300
3833
|
init_logger();
|
|
3301
3834
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
@@ -3309,7 +3842,7 @@ async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
|
3309
3842
|
generateDetailContent: generateMemoryFile,
|
|
3310
3843
|
detailSubDir: ".claude/memories",
|
|
3311
3844
|
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
3312
|
-
const settingsPath = resolvePath((0,
|
|
3845
|
+
const settingsPath = resolvePath((0, import_node_path12.join)(".claude", "settings.json"), baseDir2);
|
|
3313
3846
|
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
3314
3847
|
return [];
|
|
3315
3848
|
}
|
|
@@ -3373,7 +3906,7 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
3373
3906
|
}
|
|
3374
3907
|
|
|
3375
3908
|
// src/generators/rules/generator-registry.ts
|
|
3376
|
-
var
|
|
3909
|
+
var import_node_path13 = require("path");
|
|
3377
3910
|
function determineCursorRuleType(frontmatter) {
|
|
3378
3911
|
if (frontmatter.cursorRuleType) {
|
|
3379
3912
|
return frontmatter.cursorRuleType;
|
|
@@ -3397,6 +3930,15 @@ function determineCursorRuleType(frontmatter) {
|
|
|
3397
3930
|
}
|
|
3398
3931
|
var GENERATOR_REGISTRY = {
|
|
3399
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
|
+
},
|
|
3400
3942
|
amazonqcli: {
|
|
3401
3943
|
type: "complex",
|
|
3402
3944
|
tool: "amazonqcli",
|
|
@@ -3469,7 +4011,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3469
4011
|
},
|
|
3470
4012
|
pathResolver: (rule, outputDir) => {
|
|
3471
4013
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
3472
|
-
return (0,
|
|
4014
|
+
return (0, import_node_path13.join)(outputDir, `${baseFilename}.instructions.md`);
|
|
3473
4015
|
}
|
|
3474
4016
|
},
|
|
3475
4017
|
cursor: {
|
|
@@ -3509,7 +4051,7 @@ var GENERATOR_REGISTRY = {
|
|
|
3509
4051
|
return lines.join("\n");
|
|
3510
4052
|
},
|
|
3511
4053
|
pathResolver: (rule, outputDir) => {
|
|
3512
|
-
return (0,
|
|
4054
|
+
return (0, import_node_path13.join)(outputDir, `${rule.filename}.mdc`);
|
|
3513
4055
|
}
|
|
3514
4056
|
},
|
|
3515
4057
|
codexcli: {
|
|
@@ -3545,10 +4087,10 @@ var GENERATOR_REGISTRY = {
|
|
|
3545
4087
|
pathResolver: (rule, outputDir) => {
|
|
3546
4088
|
const outputFormat = rule.frontmatter.windsurfOutputFormat || "directory";
|
|
3547
4089
|
if (outputFormat === "single-file") {
|
|
3548
|
-
return (0,
|
|
4090
|
+
return (0, import_node_path13.join)(outputDir, ".windsurf-rules");
|
|
3549
4091
|
} else {
|
|
3550
|
-
const rulesDir = (0,
|
|
3551
|
-
return (0,
|
|
4092
|
+
const rulesDir = (0, import_node_path13.join)(outputDir, ".windsurf", "rules");
|
|
4093
|
+
return (0, import_node_path13.join)(rulesDir, `${rule.filename}.md`);
|
|
3552
4094
|
}
|
|
3553
4095
|
}
|
|
3554
4096
|
},
|
|
@@ -3685,8 +4227,58 @@ var generateKiroConfig = createSimpleGenerator("kiro");
|
|
|
3685
4227
|
var generateRooConfig = createSimpleGenerator("roo");
|
|
3686
4228
|
var generateQwencodeConfig = createSimpleGenerator("qwencode");
|
|
3687
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
|
+
}
|
|
4267
|
+
|
|
3688
4268
|
// src/generators/rules/codexcli.ts
|
|
3689
|
-
|
|
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
|
+
}
|
|
3690
4282
|
|
|
3691
4283
|
// src/utils/xml-document-generator.ts
|
|
3692
4284
|
var import_fast_xml_parser = require("fast-xml-parser");
|
|
@@ -3732,47 +4324,6 @@ function generateRootMarkdownWithXmlDocs(rootRule, memoryRules, config) {
|
|
|
3732
4324
|
return lines.join("\n");
|
|
3733
4325
|
}
|
|
3734
4326
|
|
|
3735
|
-
// src/generators/rules/codexcli.ts
|
|
3736
|
-
async function generateCodexConfig(rules, config, baseDir) {
|
|
3737
|
-
const outputs = [];
|
|
3738
|
-
const nonEmptyRules = rules.filter((rule) => rule.content.trim().length > 0);
|
|
3739
|
-
if (nonEmptyRules.length > 0) {
|
|
3740
|
-
const generatorConfig = {
|
|
3741
|
-
tool: "codexcli",
|
|
3742
|
-
fileExtension: ".md",
|
|
3743
|
-
ignoreFileName: ".codexignore",
|
|
3744
|
-
generateContent: generateCodexMemoryMarkdown,
|
|
3745
|
-
generateDetailContent: generateCodexMemoryMarkdown,
|
|
3746
|
-
generateRootContent: generateCodexRootMarkdown,
|
|
3747
|
-
rootFilePath: "AGENTS.md",
|
|
3748
|
-
detailSubDir: ".codex/memories"
|
|
3749
|
-
};
|
|
3750
|
-
const ruleOutputs = await generateComplexRules(nonEmptyRules, config, generatorConfig, baseDir);
|
|
3751
|
-
outputs.push(...ruleOutputs);
|
|
3752
|
-
} else {
|
|
3753
|
-
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
3754
|
-
if (ignorePatterns.patterns.length > 0) {
|
|
3755
|
-
const ignorePath = resolvePath(".codexignore", baseDir);
|
|
3756
|
-
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, "codexcli");
|
|
3757
|
-
outputs.push({
|
|
3758
|
-
tool: "codexcli",
|
|
3759
|
-
filepath: ignorePath,
|
|
3760
|
-
content: ignoreContent
|
|
3761
|
-
});
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
|
-
return outputs;
|
|
3765
|
-
}
|
|
3766
|
-
function generateCodexMemoryMarkdown(rule) {
|
|
3767
|
-
return rule.content.trim();
|
|
3768
|
-
}
|
|
3769
|
-
function generateCodexRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
3770
|
-
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
3771
|
-
memorySubDir: ".codex/memories",
|
|
3772
|
-
fallbackTitle: "OpenAI Codex CLI Configuration"
|
|
3773
|
-
});
|
|
3774
|
-
}
|
|
3775
|
-
|
|
3776
4327
|
// src/generators/rules/geminicli.ts
|
|
3777
4328
|
async function generateGeminiConfig(rules, config, baseDir) {
|
|
3778
4329
|
const generatorConfig = {
|
|
@@ -3830,23 +4381,17 @@ async function generateOpenCodeConfig(rules, config, baseDir) {
|
|
|
3830
4381
|
tool: "opencode",
|
|
3831
4382
|
fileExtension: ".md",
|
|
3832
4383
|
// ignoreFileName omitted - OpenCode doesn't use dedicated ignore files
|
|
3833
|
-
generateContent:
|
|
3834
|
-
generateDetailContent:
|
|
3835
|
-
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
|
+
}),
|
|
3836
4390
|
rootFilePath: "AGENTS.md",
|
|
3837
4391
|
detailSubDir: ".opencode/memories"
|
|
3838
4392
|
};
|
|
3839
4393
|
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
3840
4394
|
}
|
|
3841
|
-
function generateOpenCodeMarkdown(rule) {
|
|
3842
|
-
return rule.content.trim();
|
|
3843
|
-
}
|
|
3844
|
-
function generateOpenCodeRootMarkdown(rootRule, memoryRules, _baseDir) {
|
|
3845
|
-
return generateRootMarkdownWithXmlDocs(rootRule, memoryRules, {
|
|
3846
|
-
memorySubDir: ".opencode/memories",
|
|
3847
|
-
fallbackTitle: "OpenCode Configuration"
|
|
3848
|
-
});
|
|
3849
|
-
}
|
|
3850
4395
|
|
|
3851
4396
|
// src/generators/rules/qwencode.ts
|
|
3852
4397
|
async function generateQwencodeConfig2(rules, config, baseDir) {
|
|
@@ -3905,6 +4450,8 @@ function filterRulesForTool(rules, tool, config) {
|
|
|
3905
4450
|
}
|
|
3906
4451
|
async function generateForTool(tool, rules, config, baseDir) {
|
|
3907
4452
|
switch (tool) {
|
|
4453
|
+
case "agentsmd":
|
|
4454
|
+
return await generateAgentsMdConfig(rules, config, baseDir);
|
|
3908
4455
|
case "amazonqcli":
|
|
3909
4456
|
return await generateAmazonqcliConfig(rules, config, baseDir);
|
|
3910
4457
|
case "augmentcode": {
|
|
@@ -3964,7 +4511,7 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
3964
4511
|
}
|
|
3965
4512
|
|
|
3966
4513
|
// src/core/parser.ts
|
|
3967
|
-
var
|
|
4514
|
+
var import_node_path14 = require("path");
|
|
3968
4515
|
init_logger();
|
|
3969
4516
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
3970
4517
|
const ignorePatterns = await loadIgnorePatterns();
|
|
@@ -4018,7 +4565,7 @@ async function parseRuleFile(filepath) {
|
|
|
4018
4565
|
},
|
|
4019
4566
|
...validatedData.tags !== void 0 && { tags: validatedData.tags }
|
|
4020
4567
|
};
|
|
4021
|
-
const filename = (0,
|
|
4568
|
+
const filename = (0, import_node_path14.basename)(filepath, ".md");
|
|
4022
4569
|
return {
|
|
4023
4570
|
frontmatter,
|
|
4024
4571
|
content: parsed.content,
|
|
@@ -4134,10 +4681,12 @@ function parseMcpConfig(projectRoot) {
|
|
|
4134
4681
|
async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
4135
4682
|
const outputs = [];
|
|
4136
4683
|
const toolMap = {
|
|
4684
|
+
agentsmd: async () => [],
|
|
4137
4685
|
amazonqcli: async (servers, dir) => {
|
|
4138
4686
|
const config = {
|
|
4139
4687
|
aiRulesDir: ".rulesync",
|
|
4140
4688
|
outputPaths: {
|
|
4689
|
+
agentsmd: ".agents/memories",
|
|
4141
4690
|
amazonqcli: ".amazonq/rules",
|
|
4142
4691
|
augmentcode: ".",
|
|
4143
4692
|
"augmentcode-legacy": ".",
|
|
@@ -4216,231 +4765,594 @@ async function generateMcpConfigurations(mcpConfig, baseDir, targetTools) {
|
|
|
4216
4765
|
return outputs;
|
|
4217
4766
|
}
|
|
4218
4767
|
|
|
4219
|
-
// src/
|
|
4768
|
+
// src/core/subagent-generator.ts
|
|
4769
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
4770
|
+
|
|
4771
|
+
// src/generators/subagents/claudecode.ts
|
|
4220
4772
|
init_logger();
|
|
4221
|
-
async function generateCommand(options = {}) {
|
|
4222
|
-
const configLoaderOptions = {
|
|
4223
|
-
...options.config !== void 0 && { configPath: options.config },
|
|
4224
|
-
...options.noConfig !== void 0 && { noConfig: options.noConfig }
|
|
4225
|
-
};
|
|
4226
|
-
const configResult = await loadConfig(configLoaderOptions);
|
|
4227
|
-
const cliOptions = {
|
|
4228
|
-
tools: options.tools,
|
|
4229
|
-
...options.verbose !== void 0 && { verbose: options.verbose },
|
|
4230
|
-
...options.delete !== void 0 && { delete: options.delete },
|
|
4231
|
-
...options.baseDirs !== void 0 && { baseDirs: options.baseDirs }
|
|
4232
|
-
};
|
|
4233
|
-
const config = mergeWithCliOptions(configResult.config, cliOptions);
|
|
4234
|
-
if (!config.defaultTargets || config.defaultTargets.length === 0) {
|
|
4235
|
-
const errorMessage = `\u274C Error: At least one tool must be specified.
|
|
4236
4773
|
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
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
|
+
}
|
|
4260
4820
|
}
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
} else {
|
|
4268
|
-
baseDirs = [process.cwd()];
|
|
4821
|
+
};
|
|
4822
|
+
|
|
4823
|
+
// src/generators/subagents/claudecode.ts
|
|
4824
|
+
var ClaudeCodeSubagentGenerator = class extends BaseSubagentGenerator {
|
|
4825
|
+
getToolName() {
|
|
4826
|
+
return "claudecode";
|
|
4269
4827
|
}
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
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;
|
|
4275
4911
|
}
|
|
4912
|
+
}
|
|
4913
|
+
async function parseSubagentsFromDirectory(agentsDir) {
|
|
4276
4914
|
try {
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
logger.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
4281
|
-
return;
|
|
4915
|
+
if (!await fileExists(agentsDir)) {
|
|
4916
|
+
logger.debug(`Agents directory does not exist: ${agentsDir}`);
|
|
4917
|
+
return [];
|
|
4282
4918
|
}
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
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 [];
|
|
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 = [];
|
|
4944
|
+
try {
|
|
4945
|
+
parsedSubagents = await parseSubagentsFromDirectory(subagentsDir);
|
|
4946
|
+
if (parsedSubagents.length > 0) {
|
|
4947
|
+
logger.debug(`Found ${parsedSubagents.length} subagent files in ${subagentsDir}`);
|
|
4948
|
+
}
|
|
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
|
+
}
|
|
4299
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;
|
|
5234
|
+
}
|
|
5235
|
+
} else {
|
|
5236
|
+
logger.info("\nSkipping rule generation (not in --features)");
|
|
4300
5237
|
}
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
break;
|
|
4311
|
-
case "copilot":
|
|
4312
|
-
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
4313
|
-
break;
|
|
4314
|
-
case "cursor":
|
|
4315
|
-
deleteTasks.push(removeDirectory(config.outputPaths.cursor));
|
|
4316
|
-
break;
|
|
4317
|
-
case "cline":
|
|
4318
|
-
deleteTasks.push(removeDirectory(config.outputPaths.cline));
|
|
4319
|
-
break;
|
|
4320
|
-
case "claudecode":
|
|
4321
|
-
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
4322
|
-
if (hasCommandFiles) {
|
|
4323
|
-
deleteTasks.push(removeDirectory((0, import_node_path14.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;
|
|
4324
5247
|
}
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
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;
|
|
4330
5256
|
}
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
deleteTasks.push(removeDirectory((0, import_node_path14.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++;
|
|
4336
5261
|
}
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
deleteTasks.push(removeDirectory(config.outputPaths.opencode));
|
|
4343
|
-
break;
|
|
4344
|
-
case "qwencode":
|
|
4345
|
-
deleteTasks.push(removeDirectory(config.outputPaths.qwencode));
|
|
4346
|
-
break;
|
|
4347
|
-
case "windsurf":
|
|
4348
|
-
deleteTasks.push(removeDirectory(config.outputPaths.windsurf));
|
|
4349
|
-
break;
|
|
5262
|
+
} catch (error) {
|
|
5263
|
+
logger.error(
|
|
5264
|
+
`\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
5265
|
+
);
|
|
5266
|
+
}
|
|
4350
5267
|
}
|
|
5268
|
+
} else {
|
|
5269
|
+
logger.info("\nSkipping MCP configuration generation (not in --features)");
|
|
4351
5270
|
}
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
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)");
|
|
4363
5292
|
}
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
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)");
|
|
4367
5299
|
}
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
);
|
|
4388
|
-
if (mcpResults.length === 0) {
|
|
4389
|
-
logger.info(`No MCP configurations generated for ${baseDir}`);
|
|
4390
|
-
continue;
|
|
4391
|
-
}
|
|
4392
|
-
for (const result of mcpResults) {
|
|
4393
|
-
await writeFileContent(result.filepath, result.content);
|
|
4394
|
-
logger.success(`Generated ${result.tool} MCP configuration: ${result.filepath}`);
|
|
4395
|
-
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
|
+
}
|
|
4396
5319
|
}
|
|
4397
|
-
}
|
|
4398
|
-
logger.
|
|
4399
|
-
`\u274C Failed to generate MCP configurations: ${error instanceof Error ? error.message : String(error)}`
|
|
4400
|
-
);
|
|
5320
|
+
} else {
|
|
5321
|
+
logger.info("\nSkipping subagent file generation (not in --features)");
|
|
4401
5322
|
}
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
await writeFileContent(result.filepath, result.content);
|
|
4417
|
-
logger.success(`Generated ${result.tool} command: ${result.filepath}`);
|
|
4418
|
-
totalCommandOutputs++;
|
|
4419
|
-
}
|
|
4420
|
-
}
|
|
4421
|
-
const totalGenerated = totalOutputs + totalMcpOutputs + totalCommandOutputs;
|
|
4422
|
-
if (totalGenerated > 0) {
|
|
4423
|
-
const parts = [];
|
|
4424
|
-
if (totalOutputs > 0) parts.push(`${totalOutputs} configurations`);
|
|
4425
|
-
if (totalMcpOutputs > 0) parts.push(`${totalMcpOutputs} MCP configurations`);
|
|
4426
|
-
if (totalCommandOutputs > 0) parts.push(`${totalCommandOutputs} commands`);
|
|
4427
|
-
logger.success(
|
|
4428
|
-
`
|
|
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
|
+
`
|
|
4429
5337
|
\u{1F389} All done! Generated ${totalGenerated} file(s) total (${parts.join(" + ")})`
|
|
4430
|
-
|
|
5338
|
+
);
|
|
5339
|
+
}
|
|
5340
|
+
} catch (error) {
|
|
5341
|
+
logger.error("\u274C Failed to generate configurations:", error);
|
|
5342
|
+
process.exit(1);
|
|
4431
5343
|
}
|
|
4432
5344
|
} catch (error) {
|
|
4433
|
-
logger.error("\u274C Failed to
|
|
5345
|
+
logger.error("\u274C Failed to resolve configuration:", error);
|
|
4434
5346
|
process.exit(1);
|
|
4435
5347
|
}
|
|
4436
5348
|
}
|
|
4437
5349
|
|
|
4438
5350
|
// src/cli/commands/gitignore.ts
|
|
4439
5351
|
var import_node_fs2 = require("fs");
|
|
4440
|
-
var
|
|
5352
|
+
var import_node_path19 = require("path");
|
|
4441
5353
|
init_logger();
|
|
4442
5354
|
var gitignoreCommand = async () => {
|
|
4443
|
-
const gitignorePath = (0,
|
|
5355
|
+
const gitignorePath = (0, import_node_path19.join)(process.cwd(), ".gitignore");
|
|
4444
5356
|
const rulesFilesToIgnore = [
|
|
4445
5357
|
"# Generated by rulesync - AI tool configuration files",
|
|
4446
5358
|
"**/.amazonq/rules/",
|
|
@@ -4454,7 +5366,9 @@ var gitignoreCommand = async () => {
|
|
|
4454
5366
|
"**/CLAUDE.md",
|
|
4455
5367
|
"**/.claude/memories/",
|
|
4456
5368
|
"**/.claude/commands/",
|
|
5369
|
+
"**/.claude/agents/",
|
|
4457
5370
|
"**/AGENTS.md",
|
|
5371
|
+
"**/.agents/",
|
|
4458
5372
|
"**/.codexignore",
|
|
4459
5373
|
"**/.roo/rules/",
|
|
4460
5374
|
"**/.rooignore",
|
|
@@ -4514,11 +5428,155 @@ ${linesToAdd.join("\n")}
|
|
|
4514
5428
|
};
|
|
4515
5429
|
|
|
4516
5430
|
// src/core/importer.ts
|
|
4517
|
-
var
|
|
4518
|
-
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
|
+
}
|
|
4519
5577
|
|
|
4520
5578
|
// src/parsers/shared-helpers.ts
|
|
4521
|
-
var
|
|
5579
|
+
var import_node_path21 = require("path");
|
|
4522
5580
|
init_file();
|
|
4523
5581
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
4524
5582
|
const errors = [];
|
|
@@ -4572,11 +5630,11 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
4572
5630
|
const dirPath = resolvePath(dirConfig.directory, baseDir);
|
|
4573
5631
|
if (await fileExists(dirPath)) {
|
|
4574
5632
|
const result = await safeAsyncOperation(async () => {
|
|
4575
|
-
const { readdir:
|
|
4576
|
-
const files = await
|
|
5633
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5634
|
+
const files = await readdir3(dirPath);
|
|
4577
5635
|
for (const file of files) {
|
|
4578
5636
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
4579
|
-
const filePath = (0,
|
|
5637
|
+
const filePath = (0, import_node_path21.join)(dirPath, file);
|
|
4580
5638
|
const fileResult = await safeAsyncOperation(async () => {
|
|
4581
5639
|
const rawContent = await readFileContent(filePath);
|
|
4582
5640
|
let content;
|
|
@@ -4723,14 +5781,14 @@ function parseMainFile(content, filepath, config) {
|
|
|
4723
5781
|
async function parseMemoryFiles(memoryDir, config) {
|
|
4724
5782
|
const rules = [];
|
|
4725
5783
|
try {
|
|
4726
|
-
const { readdir:
|
|
4727
|
-
const files = await
|
|
5784
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5785
|
+
const files = await readdir3(memoryDir);
|
|
4728
5786
|
for (const file of files) {
|
|
4729
5787
|
if (file.endsWith(".md")) {
|
|
4730
|
-
const filePath = (0,
|
|
5788
|
+
const filePath = (0, import_node_path21.join)(memoryDir, file);
|
|
4731
5789
|
const content = await readFileContent(filePath);
|
|
4732
5790
|
if (content.trim()) {
|
|
4733
|
-
const filename = (0,
|
|
5791
|
+
const filename = (0, import_node_path21.basename)(file, ".md");
|
|
4734
5792
|
const frontmatter = {
|
|
4735
5793
|
root: false,
|
|
4736
5794
|
targets: [config.tool],
|
|
@@ -4753,14 +5811,14 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
4753
5811
|
async function parseCommandsFiles(commandsDir, config) {
|
|
4754
5812
|
const rules = [];
|
|
4755
5813
|
try {
|
|
4756
|
-
const { readdir:
|
|
4757
|
-
const files = await
|
|
5814
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5815
|
+
const files = await readdir3(commandsDir);
|
|
4758
5816
|
for (const file of files) {
|
|
4759
5817
|
if (file.endsWith(".md")) {
|
|
4760
|
-
const filePath = (0,
|
|
5818
|
+
const filePath = (0, import_node_path21.join)(commandsDir, file);
|
|
4761
5819
|
const content = await readFileContent(filePath);
|
|
4762
5820
|
if (content.trim()) {
|
|
4763
|
-
const filename = (0,
|
|
5821
|
+
const filename = (0, import_node_path21.basename)(file, ".md");
|
|
4764
5822
|
let frontmatter;
|
|
4765
5823
|
let ruleContent;
|
|
4766
5824
|
try {
|
|
@@ -4849,7 +5907,7 @@ async function parseAmazonqcliConfiguration(baseDir = process.cwd()) {
|
|
|
4849
5907
|
}
|
|
4850
5908
|
|
|
4851
5909
|
// src/parsers/augmentcode.ts
|
|
4852
|
-
var
|
|
5910
|
+
var import_node_path22 = require("path");
|
|
4853
5911
|
|
|
4854
5912
|
// src/utils/parser-helpers.ts
|
|
4855
5913
|
function createParseResult() {
|
|
@@ -4897,7 +5955,7 @@ async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
|
4897
5955
|
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
4898
5956
|
const result = createParseResult();
|
|
4899
5957
|
if (config.rulesDir) {
|
|
4900
|
-
const rulesDir = (0,
|
|
5958
|
+
const rulesDir = (0, import_node_path22.join)(baseDir, config.rulesDir);
|
|
4901
5959
|
if (await fileExists(rulesDir)) {
|
|
4902
5960
|
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
4903
5961
|
addRules(result, rulesResult.rules);
|
|
@@ -4910,7 +5968,7 @@ async function parseUnifiedAugmentcode(baseDir, config) {
|
|
|
4910
5968
|
}
|
|
4911
5969
|
}
|
|
4912
5970
|
if (config.legacyFilePath) {
|
|
4913
|
-
const legacyPath = (0,
|
|
5971
|
+
const legacyPath = (0, import_node_path22.join)(baseDir, config.legacyFilePath);
|
|
4914
5972
|
if (await fileExists(legacyPath)) {
|
|
4915
5973
|
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
4916
5974
|
if (legacyResult.rule) {
|
|
@@ -4930,11 +5988,11 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
4930
5988
|
const rules = [];
|
|
4931
5989
|
const errors = [];
|
|
4932
5990
|
try {
|
|
4933
|
-
const { readdir:
|
|
4934
|
-
const files = await
|
|
5991
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
5992
|
+
const files = await readdir3(rulesDir);
|
|
4935
5993
|
for (const file of files) {
|
|
4936
5994
|
if (file.endsWith(".md") || file.endsWith(".mdc")) {
|
|
4937
|
-
const filePath = (0,
|
|
5995
|
+
const filePath = (0, import_node_path22.join)(rulesDir, file);
|
|
4938
5996
|
try {
|
|
4939
5997
|
const rawContent = await readFileContent(filePath);
|
|
4940
5998
|
const parsed = parseFrontmatter(rawContent);
|
|
@@ -4942,7 +6000,7 @@ async function parseAugmentRules(rulesDir, config) {
|
|
|
4942
6000
|
const description = extractStringField(parsed.data, "description", "");
|
|
4943
6001
|
const tags = extractArrayField(parsed.data, "tags");
|
|
4944
6002
|
const isRoot = ruleType === "always";
|
|
4945
|
-
const filename = (0,
|
|
6003
|
+
const filename = (0, import_node_path22.basename)(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
4946
6004
|
const frontmatter = {
|
|
4947
6005
|
root: isRoot,
|
|
4948
6006
|
targets: [config.targetName],
|
|
@@ -5000,8 +6058,9 @@ async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
|
5000
6058
|
}
|
|
5001
6059
|
|
|
5002
6060
|
// src/parsers/claudecode.ts
|
|
6061
|
+
init_file();
|
|
5003
6062
|
async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
5004
|
-
|
|
6063
|
+
const memoryResult = await parseMemoryBasedConfiguration(baseDir, {
|
|
5005
6064
|
tool: "claudecode",
|
|
5006
6065
|
mainFileName: "CLAUDE.md",
|
|
5007
6066
|
memoryDirPath: ".claude/memories",
|
|
@@ -5011,6 +6070,24 @@ async function parseClaudeConfiguration(baseDir = process.cwd()) {
|
|
|
5011
6070
|
filenamePrefix: "claude",
|
|
5012
6071
|
commandsDirPath: ".claude/commands"
|
|
5013
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;
|
|
5014
6091
|
}
|
|
5015
6092
|
|
|
5016
6093
|
// src/parsers/cline.ts
|
|
@@ -5034,7 +6111,7 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
5034
6111
|
}
|
|
5035
6112
|
|
|
5036
6113
|
// src/parsers/codexcli.ts
|
|
5037
|
-
var
|
|
6114
|
+
var import_node_path23 = require("path");
|
|
5038
6115
|
|
|
5039
6116
|
// src/parsers/copilot.ts
|
|
5040
6117
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
@@ -5057,9 +6134,9 @@ async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
|
5057
6134
|
}
|
|
5058
6135
|
|
|
5059
6136
|
// src/parsers/cursor.ts
|
|
5060
|
-
var
|
|
6137
|
+
var import_node_path24 = require("path");
|
|
5061
6138
|
var import_js_yaml = require("js-yaml");
|
|
5062
|
-
var
|
|
6139
|
+
var import_mini9 = require("zod/mini");
|
|
5063
6140
|
var customMatterOptions = {
|
|
5064
6141
|
engines: {
|
|
5065
6142
|
yaml: {
|
|
@@ -5087,7 +6164,7 @@ var customMatterOptions = {
|
|
|
5087
6164
|
}
|
|
5088
6165
|
};
|
|
5089
6166
|
function convertCursorMdcFrontmatter(cursorFrontmatter, _filename) {
|
|
5090
|
-
const FrontmatterSchema =
|
|
6167
|
+
const FrontmatterSchema = import_mini9.z.record(import_mini9.z.string(), import_mini9.z.unknown());
|
|
5091
6168
|
const parseResult = FrontmatterSchema.safeParse(cursorFrontmatter);
|
|
5092
6169
|
if (!parseResult.success) {
|
|
5093
6170
|
return {
|
|
@@ -5181,7 +6258,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5181
6258
|
const rules = [];
|
|
5182
6259
|
let ignorePatterns;
|
|
5183
6260
|
let mcpServers;
|
|
5184
|
-
const cursorFilePath = (0,
|
|
6261
|
+
const cursorFilePath = (0, import_node_path24.join)(baseDir, ".cursorrules");
|
|
5185
6262
|
if (await fileExists(cursorFilePath)) {
|
|
5186
6263
|
try {
|
|
5187
6264
|
const rawContent = await readFileContent(cursorFilePath);
|
|
@@ -5202,20 +6279,20 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5202
6279
|
errors.push(`Failed to parse .cursorrules file: ${errorMessage}`);
|
|
5203
6280
|
}
|
|
5204
6281
|
}
|
|
5205
|
-
const cursorRulesDir = (0,
|
|
6282
|
+
const cursorRulesDir = (0, import_node_path24.join)(baseDir, ".cursor", "rules");
|
|
5206
6283
|
if (await fileExists(cursorRulesDir)) {
|
|
5207
6284
|
try {
|
|
5208
|
-
const { readdir:
|
|
5209
|
-
const files = await
|
|
6285
|
+
const { readdir: readdir3 } = await import("fs/promises");
|
|
6286
|
+
const files = await readdir3(cursorRulesDir);
|
|
5210
6287
|
for (const file of files) {
|
|
5211
6288
|
if (file.endsWith(".mdc")) {
|
|
5212
|
-
const filePath = (0,
|
|
6289
|
+
const filePath = (0, import_node_path24.join)(cursorRulesDir, file);
|
|
5213
6290
|
try {
|
|
5214
6291
|
const rawContent = await readFileContent(filePath);
|
|
5215
6292
|
const parsed = parseFrontmatter(rawContent, { matterOptions: customMatterOptions });
|
|
5216
6293
|
const content = parsed.content;
|
|
5217
6294
|
if (content) {
|
|
5218
|
-
const filename = (0,
|
|
6295
|
+
const filename = (0, import_node_path24.basename)(file, ".mdc");
|
|
5219
6296
|
const frontmatter = convertCursorMdcFrontmatter(parsed.data, filename);
|
|
5220
6297
|
rules.push({
|
|
5221
6298
|
frontmatter,
|
|
@@ -5238,7 +6315,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5238
6315
|
if (rules.length === 0) {
|
|
5239
6316
|
errors.push("No Cursor configuration files found (.cursorrules or .cursor/rules/*.mdc)");
|
|
5240
6317
|
}
|
|
5241
|
-
const cursorIgnorePath = (0,
|
|
6318
|
+
const cursorIgnorePath = (0, import_node_path24.join)(baseDir, ".cursorignore");
|
|
5242
6319
|
if (await fileExists(cursorIgnorePath)) {
|
|
5243
6320
|
try {
|
|
5244
6321
|
const content = await readFileContent(cursorIgnorePath);
|
|
@@ -5251,7 +6328,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5251
6328
|
errors.push(`Failed to parse .cursorignore: ${errorMessage}`);
|
|
5252
6329
|
}
|
|
5253
6330
|
}
|
|
5254
|
-
const cursorMcpPath = (0,
|
|
6331
|
+
const cursorMcpPath = (0, import_node_path24.join)(baseDir, ".cursor", "mcp.json");
|
|
5255
6332
|
if (await fileExists(cursorMcpPath)) {
|
|
5256
6333
|
try {
|
|
5257
6334
|
const content = await readFileContent(cursorMcpPath);
|
|
@@ -5274,6 +6351,7 @@ async function parseCursorConfiguration(baseDir = process.cwd()) {
|
|
|
5274
6351
|
}
|
|
5275
6352
|
|
|
5276
6353
|
// src/parsers/geminicli.ts
|
|
6354
|
+
var import_node_path25 = require("path");
|
|
5277
6355
|
async function parseAiexclude(aiexcludePath) {
|
|
5278
6356
|
try {
|
|
5279
6357
|
const content = await readFileContent(aiexcludePath);
|
|
@@ -5283,8 +6361,51 @@ async function parseAiexclude(aiexcludePath) {
|
|
|
5283
6361
|
return [];
|
|
5284
6362
|
}
|
|
5285
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
|
+
}
|
|
5286
6407
|
async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
5287
|
-
|
|
6408
|
+
const result = await parseMemoryBasedConfiguration(baseDir, {
|
|
5288
6409
|
tool: "geminicli",
|
|
5289
6410
|
mainFileName: "GEMINI.md",
|
|
5290
6411
|
memoryDirPath: ".gemini/memories",
|
|
@@ -5295,17 +6416,23 @@ async function parseGeminiConfiguration(baseDir = process.cwd()) {
|
|
|
5295
6416
|
additionalIgnoreFile: {
|
|
5296
6417
|
path: ".aiexclude",
|
|
5297
6418
|
parser: parseAiexclude
|
|
5298
|
-
}
|
|
5299
|
-
commandsDirPath
|
|
6419
|
+
}
|
|
6420
|
+
// commandsDirPath is removed - Gemini uses .toml files which need special handling
|
|
5300
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;
|
|
5301
6428
|
}
|
|
5302
6429
|
|
|
5303
6430
|
// src/parsers/junie.ts
|
|
5304
|
-
var
|
|
6431
|
+
var import_node_path26 = require("path");
|
|
5305
6432
|
async function parseJunieConfiguration(baseDir = process.cwd()) {
|
|
5306
6433
|
const errors = [];
|
|
5307
6434
|
const rules = [];
|
|
5308
|
-
const guidelinesPath = (0,
|
|
6435
|
+
const guidelinesPath = (0, import_node_path26.join)(baseDir, ".junie", "guidelines.md");
|
|
5309
6436
|
if (!await fileExists(guidelinesPath)) {
|
|
5310
6437
|
errors.push(".junie/guidelines.md file not found");
|
|
5311
6438
|
return { rules, errors };
|
|
@@ -5399,8 +6526,8 @@ async function parseRooConfiguration(baseDir = process.cwd()) {
|
|
|
5399
6526
|
}
|
|
5400
6527
|
|
|
5401
6528
|
// src/parsers/windsurf.ts
|
|
5402
|
-
var
|
|
5403
|
-
var
|
|
6529
|
+
var import_promises4 = require("fs/promises");
|
|
6530
|
+
var import_node_path27 = require("path");
|
|
5404
6531
|
init_logger();
|
|
5405
6532
|
|
|
5406
6533
|
// src/core/importer.ts
|
|
@@ -5408,6 +6535,8 @@ init_logger();
|
|
|
5408
6535
|
async function importConfiguration(options) {
|
|
5409
6536
|
const {
|
|
5410
6537
|
tool,
|
|
6538
|
+
features = ["rules", "commands", "mcp", "ignore", "subagents"],
|
|
6539
|
+
// Default to all features for backward compatibility
|
|
5411
6540
|
baseDir = process.cwd(),
|
|
5412
6541
|
rulesDir = ".rulesync",
|
|
5413
6542
|
verbose = false,
|
|
@@ -5417,11 +6546,18 @@ async function importConfiguration(options) {
|
|
|
5417
6546
|
let rules = [];
|
|
5418
6547
|
let ignorePatterns;
|
|
5419
6548
|
let mcpServers;
|
|
6549
|
+
let subagents;
|
|
5420
6550
|
if (verbose) {
|
|
5421
6551
|
logger.log(`Importing ${tool} configuration from ${baseDir}...`);
|
|
5422
6552
|
}
|
|
5423
6553
|
try {
|
|
5424
6554
|
switch (tool) {
|
|
6555
|
+
case "agentsmd": {
|
|
6556
|
+
const agentsmdResult = await parseAgentsMdConfiguration(baseDir);
|
|
6557
|
+
rules = agentsmdResult.rules;
|
|
6558
|
+
errors.push(...agentsmdResult.errors);
|
|
6559
|
+
break;
|
|
6560
|
+
}
|
|
5425
6561
|
case "amazonqcli": {
|
|
5426
6562
|
const amazonqResult = await parseAmazonqcliConfiguration(baseDir);
|
|
5427
6563
|
rules = amazonqResult.rules;
|
|
@@ -5447,6 +6583,7 @@ async function importConfiguration(options) {
|
|
|
5447
6583
|
errors.push(...claudeResult.errors);
|
|
5448
6584
|
ignorePatterns = claudeResult.ignorePatterns;
|
|
5449
6585
|
mcpServers = claudeResult.mcpServers;
|
|
6586
|
+
subagents = claudeResult.subagents;
|
|
5450
6587
|
break;
|
|
5451
6588
|
}
|
|
5452
6589
|
case "cursor": {
|
|
@@ -5513,10 +6650,20 @@ async function importConfiguration(options) {
|
|
|
5513
6650
|
errors.push(`Failed to parse ${tool} configuration: ${errorMessage}`);
|
|
5514
6651
|
return { success: false, rulesCreated: 0, errors };
|
|
5515
6652
|
}
|
|
5516
|
-
if (rules.length === 0 && !ignorePatterns && !mcpServers) {
|
|
6653
|
+
if (rules.length === 0 && !ignorePatterns && !mcpServers && !subagents) {
|
|
5517
6654
|
return { success: false, rulesCreated: 0, errors };
|
|
5518
6655
|
}
|
|
5519
|
-
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);
|
|
5520
6667
|
try {
|
|
5521
6668
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
5522
6669
|
await mkdir3(rulesDirPath, { recursive: true });
|
|
@@ -5526,37 +6673,49 @@ async function importConfiguration(options) {
|
|
|
5526
6673
|
return { success: false, rulesCreated: 0, errors };
|
|
5527
6674
|
}
|
|
5528
6675
|
let rulesCreated = 0;
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
targetDir = (0, import_node_path22.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");
|
|
5540
6686
|
const { mkdir: mkdir3 } = await import("fs/promises");
|
|
5541
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
|
+
}
|
|
5542
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}`);
|
|
5543
6708
|
}
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
if (verbose) {
|
|
5549
|
-
logger.success(`Created rule file: ${filePath}`);
|
|
5550
|
-
}
|
|
5551
|
-
} catch (error) {
|
|
5552
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5553
|
-
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)`);
|
|
5554
6713
|
}
|
|
5555
6714
|
}
|
|
5556
6715
|
let ignoreFileCreated = false;
|
|
5557
|
-
if (ignorePatterns && ignorePatterns.length > 0) {
|
|
6716
|
+
if (ignoreEnabled && ignorePatterns && ignorePatterns.length > 0) {
|
|
5558
6717
|
try {
|
|
5559
|
-
const rulesyncignorePath = (0,
|
|
6718
|
+
const rulesyncignorePath = (0, import_node_path28.join)(baseDir, ".rulesyncignore");
|
|
5560
6719
|
const ignoreContent = `${ignorePatterns.join("\n")}
|
|
5561
6720
|
`;
|
|
5562
6721
|
await writeFileContent(rulesyncignorePath, ignoreContent);
|
|
@@ -5568,11 +6727,13 @@ async function importConfiguration(options) {
|
|
|
5568
6727
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5569
6728
|
errors.push(`Failed to create .rulesyncignore: ${errorMessage}`);
|
|
5570
6729
|
}
|
|
6730
|
+
} else if (verbose && ignorePatterns && ignorePatterns.length > 0 && !ignoreEnabled) {
|
|
6731
|
+
logger.log(`Skipping ignore patterns (ignore feature not enabled)`);
|
|
5571
6732
|
}
|
|
5572
6733
|
let mcpFileCreated = false;
|
|
5573
|
-
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
6734
|
+
if (mcpEnabled && mcpServers && Object.keys(mcpServers).length > 0) {
|
|
5574
6735
|
try {
|
|
5575
|
-
const mcpPath = (0,
|
|
6736
|
+
const mcpPath = (0, import_node_path28.join)(baseDir, rulesDir, ".mcp.json");
|
|
5576
6737
|
const mcpContent = `${JSON.stringify({ mcpServers }, null, 2)}
|
|
5577
6738
|
`;
|
|
5578
6739
|
await writeFileContent(mcpPath, mcpContent);
|
|
@@ -5584,14 +6745,51 @@ async function importConfiguration(options) {
|
|
|
5584
6745
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5585
6746
|
errors.push(`Failed to create .mcp.json: ${errorMessage}`);
|
|
5586
6747
|
}
|
|
6748
|
+
} else if (verbose && mcpServers && Object.keys(mcpServers).length > 0 && !mcpEnabled) {
|
|
6749
|
+
logger.log(`Skipping MCP configuration (mcp feature not enabled)`);
|
|
5587
6750
|
}
|
|
5588
|
-
|
|
5589
|
-
|
|
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),
|
|
5590
6784
|
rulesCreated,
|
|
5591
6785
|
errors,
|
|
5592
6786
|
ignoreFileCreated,
|
|
5593
6787
|
mcpFileCreated
|
|
5594
6788
|
};
|
|
6789
|
+
if (subagentsCreated > 0) {
|
|
6790
|
+
result.subagentsCreated = subagentsCreated;
|
|
6791
|
+
}
|
|
6792
|
+
return result;
|
|
5595
6793
|
}
|
|
5596
6794
|
function generateRuleFileContent(rule) {
|
|
5597
6795
|
if (rule.type === "command") {
|
|
@@ -5599,70 +6797,109 @@ function generateRuleFileContent(rule) {
|
|
|
5599
6797
|
description: rule.frontmatter.description,
|
|
5600
6798
|
targets: rule.frontmatter.targets
|
|
5601
6799
|
};
|
|
5602
|
-
const frontmatter2 =
|
|
6800
|
+
const frontmatter2 = import_gray_matter3.default.stringify("", simplifiedFrontmatter);
|
|
5603
6801
|
return frontmatter2 + rule.content;
|
|
5604
6802
|
}
|
|
5605
|
-
const frontmatter =
|
|
6803
|
+
const frontmatter = import_gray_matter3.default.stringify("", rule.frontmatter);
|
|
5606
6804
|
return frontmatter + rule.content;
|
|
5607
6805
|
}
|
|
6806
|
+
function generateSubagentFileContent(subagent) {
|
|
6807
|
+
const frontmatter = import_gray_matter3.default.stringify("", subagent.frontmatter);
|
|
6808
|
+
return frontmatter + subagent.content;
|
|
6809
|
+
}
|
|
5608
6810
|
|
|
5609
6811
|
// src/cli/commands/import.ts
|
|
5610
6812
|
init_logger();
|
|
5611
6813
|
async function importCommand(options = {}) {
|
|
5612
6814
|
logger.setVerbose(options.verbose || false);
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
if (options.
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
if (
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
if (tools.length === 0) {
|
|
5626
|
-
logger.error(
|
|
5627
|
-
"\u274C Please specify one tool to import from (--amazonqcli, --augmentcode, --augmentcode-legacy, --claudecode, --cursor, --copilot, --cline, --roo, --geminicli, --qwencode, --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"
|
|
5628
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");
|
|
5629
6851
|
process.exit(1);
|
|
5630
6852
|
}
|
|
5631
6853
|
if (tools.length > 1) {
|
|
5632
6854
|
logger.error(
|
|
5633
|
-
|
|
6855
|
+
`\u274C Import command only supports a single target.
|
|
6856
|
+
You specified: ${tools.join(", ")}
|
|
6857
|
+
|
|
6858
|
+
Please run the command separately for each tool:`
|
|
5634
6859
|
);
|
|
6860
|
+
for (const tool2 of tools) {
|
|
6861
|
+
logger.info(` rulesync import --targets ${tool2}`);
|
|
6862
|
+
}
|
|
5635
6863
|
process.exit(1);
|
|
5636
6864
|
}
|
|
5637
6865
|
const tool = tools[0];
|
|
5638
6866
|
if (!tool) {
|
|
5639
|
-
logger.error("
|
|
6867
|
+
logger.error("\u274C Unexpected error: No tool selected");
|
|
5640
6868
|
process.exit(1);
|
|
5641
6869
|
}
|
|
5642
6870
|
logger.log(`Importing configuration files from ${tool}...`);
|
|
5643
6871
|
try {
|
|
5644
6872
|
const result = await importConfiguration({
|
|
5645
6873
|
tool,
|
|
6874
|
+
features: normalizedFeatures,
|
|
5646
6875
|
verbose: options.verbose ?? false,
|
|
5647
6876
|
useLegacyLocation: options.legacy ?? false
|
|
5648
6877
|
});
|
|
5649
6878
|
if (result.success) {
|
|
5650
|
-
logger.success(
|
|
6879
|
+
logger.success(`\u2705 Imported ${result.rulesCreated} rule(s) from ${tool}`);
|
|
5651
6880
|
if (result.ignoreFileCreated) {
|
|
5652
|
-
logger.success("Created .rulesyncignore file from ignore patterns");
|
|
6881
|
+
logger.success(" Created .rulesyncignore file from ignore patterns");
|
|
5653
6882
|
}
|
|
5654
6883
|
if (result.mcpFileCreated) {
|
|
5655
|
-
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`);
|
|
5656
6888
|
}
|
|
6889
|
+
logger.success(`
|
|
6890
|
+
\u{1F389} Successfully imported from ${tool}`);
|
|
5657
6891
|
logger.log("You can now run 'rulesync generate' to create tool-specific configurations.");
|
|
5658
6892
|
} else if (result.errors.length > 0) {
|
|
5659
6893
|
logger.warn(`\u26A0\uFE0F Failed to import from ${tool}: ${result.errors[0]}`);
|
|
5660
6894
|
if (result.errors.length > 1) {
|
|
5661
|
-
logger.info("
|
|
6895
|
+
logger.info(" Detailed errors:");
|
|
5662
6896
|
for (const error of result.errors) {
|
|
5663
|
-
logger.info(`
|
|
6897
|
+
logger.info(` - ${error}`);
|
|
5664
6898
|
}
|
|
5665
6899
|
}
|
|
6900
|
+
logger.error(`
|
|
6901
|
+
\u274C Failed to import from ${tool}.`);
|
|
6902
|
+
process.exit(1);
|
|
5666
6903
|
}
|
|
5667
6904
|
} catch (error) {
|
|
5668
6905
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -5672,7 +6909,7 @@ async function importCommand(options = {}) {
|
|
|
5672
6909
|
}
|
|
5673
6910
|
|
|
5674
6911
|
// src/cli/commands/init.ts
|
|
5675
|
-
var
|
|
6912
|
+
var import_node_path29 = require("path");
|
|
5676
6913
|
init_logger();
|
|
5677
6914
|
async function initCommand(options = {}) {
|
|
5678
6915
|
const configResult = await loadConfig();
|
|
@@ -5681,7 +6918,7 @@ async function initCommand(options = {}) {
|
|
|
5681
6918
|
logger.log("Initializing rulesync...");
|
|
5682
6919
|
await ensureDir(aiRulesDir);
|
|
5683
6920
|
const useLegacy = options.legacy ?? config.legacy ?? false;
|
|
5684
|
-
const rulesDir = useLegacy ? aiRulesDir : (0,
|
|
6921
|
+
const rulesDir = useLegacy ? aiRulesDir : (0, import_node_path29.join)(aiRulesDir, "rules");
|
|
5685
6922
|
if (!useLegacy) {
|
|
5686
6923
|
await ensureDir(rulesDir);
|
|
5687
6924
|
}
|
|
@@ -5727,7 +6964,7 @@ globs: ["**/*"]
|
|
|
5727
6964
|
- Follow single responsibility principle
|
|
5728
6965
|
`
|
|
5729
6966
|
};
|
|
5730
|
-
const filepath = (0,
|
|
6967
|
+
const filepath = (0, import_node_path29.join)(rulesDir, sampleFile.filename);
|
|
5731
6968
|
if (!await fileExists(filepath)) {
|
|
5732
6969
|
await writeFileContent(filepath, sampleFile.content);
|
|
5733
6970
|
logger.success(`Created ${filepath}`);
|
|
@@ -5844,11 +7081,11 @@ async function watchCommand() {
|
|
|
5844
7081
|
persistent: true
|
|
5845
7082
|
});
|
|
5846
7083
|
let isGenerating = false;
|
|
5847
|
-
const handleChange = async (
|
|
7084
|
+
const handleChange = async (path8) => {
|
|
5848
7085
|
if (isGenerating) return;
|
|
5849
7086
|
isGenerating = true;
|
|
5850
7087
|
logger.log(`
|
|
5851
|
-
\u{1F4DD} Detected change in ${
|
|
7088
|
+
\u{1F4DD} Detected change in ${path8}`);
|
|
5852
7089
|
try {
|
|
5853
7090
|
await generateCommand({ verbose: false });
|
|
5854
7091
|
logger.success("Regenerated configuration files");
|
|
@@ -5858,10 +7095,10 @@ async function watchCommand() {
|
|
|
5858
7095
|
isGenerating = false;
|
|
5859
7096
|
}
|
|
5860
7097
|
};
|
|
5861
|
-
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (
|
|
7098
|
+
watcher.on("change", handleChange).on("add", handleChange).on("unlink", (path8) => {
|
|
5862
7099
|
logger.log(`
|
|
5863
|
-
\u{1F5D1}\uFE0F Removed ${
|
|
5864
|
-
handleChange(
|
|
7100
|
+
\u{1F5D1}\uFE0F Removed ${path8}`);
|
|
7101
|
+
handleChange(path8);
|
|
5865
7102
|
}).on("error", (error) => {
|
|
5866
7103
|
logger.error("Watcher error:", error);
|
|
5867
7104
|
});
|
|
@@ -5872,47 +7109,180 @@ async function watchCommand() {
|
|
|
5872
7109
|
});
|
|
5873
7110
|
}
|
|
5874
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
|
+
|
|
5875
7205
|
// src/cli/index.ts
|
|
5876
7206
|
var program = new import_commander.Command();
|
|
5877
|
-
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");
|
|
5878
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);
|
|
5879
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);
|
|
5880
7210
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
5881
|
-
program.command("import").description("Import configurations from AI tools to rulesync format").option("
|
|
5882
|
-
|
|
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(
|
|
5883
7259
|
"-b, --base-dir <paths>",
|
|
5884
7260
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
5885
7261
|
).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
if (
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
if (options.
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
config: options.config,
|
|
5910
|
-
noConfig: options.noConfig
|
|
5911
|
-
};
|
|
5912
|
-
if (options.baseDir) {
|
|
5913
|
-
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);
|
|
5914
7285
|
}
|
|
5915
|
-
await generateCommand(generateOptions);
|
|
5916
7286
|
});
|
|
5917
7287
|
program.command("validate").description("Validate rulesync configuration").action(validateCommand);
|
|
5918
7288
|
program.command("status").description("Show current status of rulesync").action(statusCommand);
|