rulesync 0.53.0 → 0.55.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.ja.md +186 -23
- package/README.md +101 -25
- package/dist/{augmentcode-ICLQ2NEZ.js → augmentcode-MJYD2Y4S.js} +2 -2
- package/dist/{chunk-TTHBLXOB.js → chunk-3PHMFVXP.js} +1 -1
- package/dist/{chunk-FFW6TGCM.js → chunk-BEPSWIZC.js} +1 -1
- package/dist/chunk-D7XQ4OHK.js +145 -0
- package/dist/{chunk-OPZOVKIL.js → chunk-ORNO5MOO.js} +1 -1
- package/dist/{chunk-Y2XH4E5R.js → chunk-OXKDEZJK.js} +1 -1
- package/dist/{chunk-FNL2KPM3.js → chunk-OY6BYYIX.js} +1 -1
- package/dist/{chunk-YPIFCGAP.js → chunk-PPAQWVXX.js} +1 -1
- package/dist/{chunk-QUJMXHNR.js → chunk-QVPD6ENS.js} +1 -1
- package/dist/{chunk-Y26DXTAT.js → chunk-TJKD6LEW.js} +1 -1
- package/dist/{chunk-HMMTSS5E.js → chunk-UHANRG2O.js} +1 -1
- package/dist/{chunk-IXCMY24P.js → chunk-UZCJNUXO.js} +1 -1
- package/dist/{chunk-USKQYIZ2.js → chunk-VI6SBYFB.js} +1 -0
- package/dist/{claudecode-4XWK2WAY.js → claudecode-CKGUHLRR.js} +3 -3
- package/dist/{cline-MNXOHP77.js → cline-Z5C656VR.js} +3 -3
- package/dist/codexcli-VFUJKSIJ.js +10 -0
- package/dist/{copilot-ARYIWVJ7.js → copilot-4WQS5TA7.js} +2 -2
- package/dist/{cursor-FCS74IAH.js → cursor-HOB2F2V2.js} +2 -2
- package/dist/{geminicli-VOPV6DXZ.js → geminicli-XTMQTIU2.js} +2 -2
- package/dist/index.cjs +608 -171
- package/dist/index.js +554 -183
- package/dist/{junie-A2Y2WZI4.js → junie-AN6CR7DD.js} +2 -2
- package/dist/{kiro-MHIK4UBV.js → kiro-PTUZOHQ2.js} +2 -2
- package/dist/{roo-VG4IUNTE.js → roo-WOMS36KU.js} +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,39 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
generateJunieMcp
|
|
4
|
+
} from "./chunk-TJKD6LEW.js";
|
|
2
5
|
import {
|
|
3
6
|
generateKiroMcp
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QVPD6ENS.js";
|
|
5
8
|
import {
|
|
6
9
|
generateRooMcp
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-BEPSWIZC.js";
|
|
8
11
|
import {
|
|
9
12
|
generateAugmentcodeMcp
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ORNO5MOO.js";
|
|
11
14
|
import {
|
|
12
15
|
generateClaudeMcp
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-OY6BYYIX.js";
|
|
14
17
|
import {
|
|
15
18
|
generateClineMcp
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import
|
|
19
|
+
} from "./chunk-UHANRG2O.js";
|
|
20
|
+
import {
|
|
21
|
+
generateCodexMcp
|
|
22
|
+
} from "./chunk-D7XQ4OHK.js";
|
|
23
|
+
import "./chunk-PPAQWVXX.js";
|
|
18
24
|
import {
|
|
19
25
|
generateCopilotMcp
|
|
20
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-OXKDEZJK.js";
|
|
21
27
|
import {
|
|
22
28
|
generateCursorMcp
|
|
23
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3PHMFVXP.js";
|
|
24
30
|
import {
|
|
25
31
|
generateGeminiCliMcp
|
|
26
|
-
} from "./chunk-
|
|
27
|
-
import {
|
|
28
|
-
generateJunieMcp
|
|
29
|
-
} from "./chunk-Y26DXTAT.js";
|
|
32
|
+
} from "./chunk-UZCJNUXO.js";
|
|
30
33
|
import {
|
|
31
34
|
ALL_TOOL_TARGETS,
|
|
32
35
|
RulesyncTargetsSchema,
|
|
33
36
|
ToolTargetSchema,
|
|
34
37
|
ToolTargetsSchema,
|
|
35
38
|
isToolTarget
|
|
36
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-VI6SBYFB.js";
|
|
37
40
|
|
|
38
41
|
// src/cli/index.ts
|
|
39
42
|
import { Command } from "commander";
|
|
@@ -53,6 +56,7 @@ function getDefaultConfig() {
|
|
|
53
56
|
cursor: ".cursor/rules",
|
|
54
57
|
cline: ".clinerules",
|
|
55
58
|
claudecode: ".",
|
|
59
|
+
codexcli: ".",
|
|
56
60
|
roo: ".roo/rules",
|
|
57
61
|
geminicli: ".gemini/memories",
|
|
58
62
|
kiro: ".kiro/steering",
|
|
@@ -139,6 +143,7 @@ var OutputPathsSchema = z3.object({
|
|
|
139
143
|
cursor: z3.optional(z3.string()),
|
|
140
144
|
cline: z3.optional(z3.string()),
|
|
141
145
|
claudecode: z3.optional(z3.string()),
|
|
146
|
+
codexcli: z3.optional(z3.string()),
|
|
142
147
|
roo: z3.optional(z3.string()),
|
|
143
148
|
geminicli: z3.optional(z3.string()),
|
|
144
149
|
kiro: z3.optional(z3.string()),
|
|
@@ -201,7 +206,8 @@ var McpServerBaseSchema = z4.object({
|
|
|
201
206
|
alwaysAllow: z4.optional(z4.array(z4.string())),
|
|
202
207
|
tools: z4.optional(z4.array(z4.string())),
|
|
203
208
|
kiroAutoApprove: z4.optional(z4.array(z4.string())),
|
|
204
|
-
kiroAutoBlock: z4.optional(z4.array(z4.string()))
|
|
209
|
+
kiroAutoBlock: z4.optional(z4.array(z4.string())),
|
|
210
|
+
headers: z4.optional(z4.record(z4.string(), z4.string()))
|
|
205
211
|
});
|
|
206
212
|
var RulesyncMcpServerSchema = z4.extend(McpServerBaseSchema, {
|
|
207
213
|
targets: z4.optional(RulesyncTargetsSchema)
|
|
@@ -429,6 +435,36 @@ function mergeWithCliOptions(config, cliOptions) {
|
|
|
429
435
|
return merged;
|
|
430
436
|
}
|
|
431
437
|
|
|
438
|
+
// src/utils/error.ts
|
|
439
|
+
function getErrorMessage(error) {
|
|
440
|
+
return error instanceof Error ? error.message : String(error);
|
|
441
|
+
}
|
|
442
|
+
function formatErrorWithContext(error, context) {
|
|
443
|
+
const errorMessage = getErrorMessage(error);
|
|
444
|
+
return `${context}: ${errorMessage}`;
|
|
445
|
+
}
|
|
446
|
+
function createErrorResult(error, context) {
|
|
447
|
+
const errorMessage = context ? formatErrorWithContext(error, context) : getErrorMessage(error);
|
|
448
|
+
return {
|
|
449
|
+
success: false,
|
|
450
|
+
error: errorMessage
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function createSuccessResult(result) {
|
|
454
|
+
return {
|
|
455
|
+
success: true,
|
|
456
|
+
result
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
async function safeAsyncOperation(operation, errorContext) {
|
|
460
|
+
try {
|
|
461
|
+
const result = await operation();
|
|
462
|
+
return createSuccessResult(result);
|
|
463
|
+
} catch (error) {
|
|
464
|
+
return createErrorResult(error, errorContext);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
432
468
|
// src/utils/file.ts
|
|
433
469
|
import { mkdir as mkdir2, readdir, readFile, rm, stat, writeFile as writeFile2 } from "fs/promises";
|
|
434
470
|
import { dirname, join as join2 } from "path";
|
|
@@ -439,6 +475,9 @@ async function ensureDir(dirPath) {
|
|
|
439
475
|
await mkdir2(dirPath, { recursive: true });
|
|
440
476
|
}
|
|
441
477
|
}
|
|
478
|
+
function resolvePath(relativePath, baseDir) {
|
|
479
|
+
return baseDir ? join2(baseDir, relativePath) : relativePath;
|
|
480
|
+
}
|
|
442
481
|
async function readFileContent(filepath) {
|
|
443
482
|
return readFile(filepath, "utf-8");
|
|
444
483
|
}
|
|
@@ -1160,6 +1199,135 @@ var ignoreConfigs = {
|
|
|
1160
1199
|
}
|
|
1161
1200
|
return augmentPatterns;
|
|
1162
1201
|
}
|
|
1202
|
+
},
|
|
1203
|
+
codexcli: {
|
|
1204
|
+
tool: "codexcli",
|
|
1205
|
+
filename: ".codexignore",
|
|
1206
|
+
header: [
|
|
1207
|
+
"# Generated by rulesync - OpenAI Codex CLI ignore file",
|
|
1208
|
+
"# This file controls which files are excluded from Codex CLI's AI context",
|
|
1209
|
+
"# Note: .codexignore is a community-requested feature (GitHub Issue #205)",
|
|
1210
|
+
"# Currently using proposed syntax based on .gitignore patterns"
|
|
1211
|
+
],
|
|
1212
|
+
corePatterns: [
|
|
1213
|
+
"# \u2500\u2500\u2500\u2500\u2500 Security & Credentials (Critical) \u2500\u2500\u2500\u2500\u2500",
|
|
1214
|
+
"# Environment files",
|
|
1215
|
+
".env",
|
|
1216
|
+
".env.*",
|
|
1217
|
+
"!.env.example",
|
|
1218
|
+
"",
|
|
1219
|
+
"# Private keys and certificates",
|
|
1220
|
+
"*.key",
|
|
1221
|
+
"*.pem",
|
|
1222
|
+
"*.p12",
|
|
1223
|
+
"*.pfx",
|
|
1224
|
+
"*.der",
|
|
1225
|
+
"*.crt",
|
|
1226
|
+
"",
|
|
1227
|
+
"# SSH keys",
|
|
1228
|
+
"id_rsa*",
|
|
1229
|
+
"id_dsa*",
|
|
1230
|
+
"*.ppk",
|
|
1231
|
+
"",
|
|
1232
|
+
"# API keys and secrets",
|
|
1233
|
+
"api-keys.json",
|
|
1234
|
+
"credentials.json",
|
|
1235
|
+
"secrets.json",
|
|
1236
|
+
"**/apikeys/",
|
|
1237
|
+
"**/*_token*",
|
|
1238
|
+
"**/*_secret*",
|
|
1239
|
+
"**/*api_key*",
|
|
1240
|
+
"",
|
|
1241
|
+
"# Cloud provider credentials",
|
|
1242
|
+
"aws-credentials.json",
|
|
1243
|
+
"gcp-service-account*.json",
|
|
1244
|
+
"azure-credentials.json",
|
|
1245
|
+
".aws/",
|
|
1246
|
+
"",
|
|
1247
|
+
"# \u2500\u2500\u2500\u2500\u2500 Database & Infrastructure Secrets \u2500\u2500\u2500\u2500\u2500",
|
|
1248
|
+
"# Database configuration",
|
|
1249
|
+
"*.db",
|
|
1250
|
+
"*.sqlite",
|
|
1251
|
+
"*.sqlite3",
|
|
1252
|
+
"database.yml",
|
|
1253
|
+
"**/database/config.*",
|
|
1254
|
+
"",
|
|
1255
|
+
"# Infrastructure as Code secrets",
|
|
1256
|
+
"*.tfstate",
|
|
1257
|
+
"*.tfstate.*",
|
|
1258
|
+
"terraform.tfvars",
|
|
1259
|
+
"secrets.auto.tfvars",
|
|
1260
|
+
".terraform/",
|
|
1261
|
+
"",
|
|
1262
|
+
"# Kubernetes secrets",
|
|
1263
|
+
"**/k8s/**/secret*.yaml",
|
|
1264
|
+
"**/kubernetes/**/secret*.yaml",
|
|
1265
|
+
"",
|
|
1266
|
+
"# \u2500\u2500\u2500\u2500\u2500 Business Sensitive Data \u2500\u2500\u2500\u2500\u2500",
|
|
1267
|
+
"# Sensitive directories",
|
|
1268
|
+
"secrets/",
|
|
1269
|
+
"private/",
|
|
1270
|
+
"confidential/",
|
|
1271
|
+
"internal-docs/",
|
|
1272
|
+
"company-secrets/",
|
|
1273
|
+
"",
|
|
1274
|
+
"# Customer and personal data",
|
|
1275
|
+
"customer-data/",
|
|
1276
|
+
"pii/",
|
|
1277
|
+
"personal-data/",
|
|
1278
|
+
"**/*customer*.csv",
|
|
1279
|
+
"**/*personal*.json",
|
|
1280
|
+
"",
|
|
1281
|
+
"# \u2500\u2500\u2500\u2500\u2500 Build Artifacts & Large Files \u2500\u2500\u2500\u2500\u2500",
|
|
1282
|
+
"# Build outputs (may contain embedded secrets)",
|
|
1283
|
+
"dist/",
|
|
1284
|
+
"build/",
|
|
1285
|
+
"out/",
|
|
1286
|
+
".next/",
|
|
1287
|
+
".nuxt/",
|
|
1288
|
+
"",
|
|
1289
|
+
"# Large files that slow down AI processing",
|
|
1290
|
+
"*.zip",
|
|
1291
|
+
"*.tar.gz",
|
|
1292
|
+
"*.rar",
|
|
1293
|
+
"**/*.{mp4,avi,mov,mkv}",
|
|
1294
|
+
"**/*.{pdf,doc,docx}",
|
|
1295
|
+
"",
|
|
1296
|
+
"# Data files",
|
|
1297
|
+
"*.csv",
|
|
1298
|
+
"*.tsv",
|
|
1299
|
+
"*.xlsx",
|
|
1300
|
+
"data/",
|
|
1301
|
+
"datasets/",
|
|
1302
|
+
"",
|
|
1303
|
+
"# \u2500\u2500\u2500\u2500\u2500 Development Environment \u2500\u2500\u2500\u2500\u2500",
|
|
1304
|
+
"# Personal IDE settings",
|
|
1305
|
+
".vscode/settings.json",
|
|
1306
|
+
".idea/workspace.xml",
|
|
1307
|
+
"",
|
|
1308
|
+
"# Temporary files",
|
|
1309
|
+
"*.swp",
|
|
1310
|
+
"*.swo",
|
|
1311
|
+
"*~",
|
|
1312
|
+
"*.tmp",
|
|
1313
|
+
"",
|
|
1314
|
+
"# Test data with sensitive content",
|
|
1315
|
+
"test-data/sensitive/",
|
|
1316
|
+
"tests/fixtures/real-data/**",
|
|
1317
|
+
"",
|
|
1318
|
+
"# \u2500\u2500\u2500\u2500\u2500 Logs & Runtime Data \u2500\u2500\u2500\u2500\u2500",
|
|
1319
|
+
"*.log",
|
|
1320
|
+
"logs/",
|
|
1321
|
+
".cache/",
|
|
1322
|
+
"",
|
|
1323
|
+
"# \u2500\u2500\u2500\u2500\u2500 Re-include Important Files \u2500\u2500\u2500\u2500\u2500",
|
|
1324
|
+
"# Allow configuration examples and documentation",
|
|
1325
|
+
"!secrets/README.md",
|
|
1326
|
+
"!config/*.example.*",
|
|
1327
|
+
"!docs/**/*.md"
|
|
1328
|
+
],
|
|
1329
|
+
includeCommonPatterns: false,
|
|
1330
|
+
projectPatternsHeader: "# \u2500\u2500\u2500\u2500\u2500 Project-specific patterns from rulesync rules \u2500\u2500\u2500\u2500\u2500"
|
|
1163
1331
|
}
|
|
1164
1332
|
};
|
|
1165
1333
|
|
|
@@ -1237,7 +1405,7 @@ function filterIgnoredFiles(files, ignorePatterns) {
|
|
|
1237
1405
|
|
|
1238
1406
|
// src/generators/rules/shared-helpers.ts
|
|
1239
1407
|
function resolveOutputDir(config, tool, baseDir) {
|
|
1240
|
-
return
|
|
1408
|
+
return resolvePath(config.outputPaths[tool], baseDir);
|
|
1241
1409
|
}
|
|
1242
1410
|
function createOutputsArray() {
|
|
1243
1411
|
return [];
|
|
@@ -1264,7 +1432,7 @@ async function generateRulesConfig(rules, config, generatorConfig, baseDir) {
|
|
|
1264
1432
|
}
|
|
1265
1433
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1266
1434
|
if (ignorePatterns.patterns.length > 0) {
|
|
1267
|
-
const ignorePath =
|
|
1435
|
+
const ignorePath = resolvePath(generatorConfig.ignoreFileName, baseDir);
|
|
1268
1436
|
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, generatorConfig.tool);
|
|
1269
1437
|
outputs.push({
|
|
1270
1438
|
tool: generatorConfig.tool,
|
|
@@ -1282,7 +1450,10 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
1282
1450
|
if (generatorConfig.generateDetailContent && generatorConfig.detailSubDir) {
|
|
1283
1451
|
for (const rule of detailRules) {
|
|
1284
1452
|
const content = generatorConfig.generateDetailContent(rule);
|
|
1285
|
-
const filepath =
|
|
1453
|
+
const filepath = resolvePath(
|
|
1454
|
+
join5(generatorConfig.detailSubDir, `${rule.filename}.md`),
|
|
1455
|
+
baseDir
|
|
1456
|
+
);
|
|
1286
1457
|
outputs.push({
|
|
1287
1458
|
tool: generatorConfig.tool,
|
|
1288
1459
|
filepath,
|
|
@@ -1292,7 +1463,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
1292
1463
|
}
|
|
1293
1464
|
if (generatorConfig.generateRootContent && generatorConfig.rootFilePath) {
|
|
1294
1465
|
const rootContent = generatorConfig.generateRootContent(rootRule, detailRules, baseDir);
|
|
1295
|
-
const rootFilepath =
|
|
1466
|
+
const rootFilepath = resolvePath(generatorConfig.rootFilePath, baseDir);
|
|
1296
1467
|
outputs.push({
|
|
1297
1468
|
tool: generatorConfig.tool,
|
|
1298
1469
|
filepath: rootFilepath,
|
|
@@ -1301,7 +1472,7 @@ async function generateComplexRules(rules, config, generatorConfig, baseDir) {
|
|
|
1301
1472
|
}
|
|
1302
1473
|
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1303
1474
|
if (ignorePatterns.patterns.length > 0) {
|
|
1304
|
-
const ignorePath =
|
|
1475
|
+
const ignorePath = resolvePath(generatorConfig.ignoreFileName, baseDir);
|
|
1305
1476
|
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, generatorConfig.tool);
|
|
1306
1477
|
outputs.push({
|
|
1307
1478
|
tool: generatorConfig.tool,
|
|
@@ -1406,30 +1577,22 @@ function generateLegacyGuidelinesFile(allRules) {
|
|
|
1406
1577
|
// src/generators/rules/claudecode.ts
|
|
1407
1578
|
import { join as join7 } from "path";
|
|
1408
1579
|
async function generateClaudecodeConfig(rules, config, baseDir) {
|
|
1409
|
-
const
|
|
1410
|
-
const rootRules = rules.filter((r) => r.frontmatter.root === true);
|
|
1411
|
-
const detailRules = rules.filter((r) => r.frontmatter.root === false);
|
|
1412
|
-
const claudeMdContent = generateClaudeMarkdown(rootRules, detailRules);
|
|
1413
|
-
const claudeOutputDir = baseDir ? join7(baseDir, config.outputPaths.claudecode) : config.outputPaths.claudecode;
|
|
1414
|
-
outputs.push({
|
|
1580
|
+
const generatorConfig = {
|
|
1415
1581
|
tool: "claudecode",
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
await updateClaudeSettings(settingsPath, ignorePatterns.patterns);
|
|
1431
|
-
}
|
|
1432
|
-
return outputs;
|
|
1582
|
+
fileExtension: ".md",
|
|
1583
|
+
ignoreFileName: ".aiignore",
|
|
1584
|
+
generateContent: generateMemoryFile,
|
|
1585
|
+
generateRootContent: (rootRule, detailRules) => generateClaudeMarkdown(rootRule ? [rootRule] : [], detailRules),
|
|
1586
|
+
rootFilePath: "CLAUDE.md",
|
|
1587
|
+
generateDetailContent: generateMemoryFile,
|
|
1588
|
+
detailSubDir: ".claude/memories",
|
|
1589
|
+
updateAdditionalConfig: async (ignorePatterns, baseDir2) => {
|
|
1590
|
+
const settingsPath = resolvePath(join7(".claude", "settings.json"), baseDir2);
|
|
1591
|
+
await updateClaudeSettings(settingsPath, ignorePatterns);
|
|
1592
|
+
return [];
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
return generateComplexRules(rules, config, generatorConfig, baseDir);
|
|
1433
1596
|
}
|
|
1434
1597
|
function generateClaudeMarkdown(rootRules, detailRules) {
|
|
1435
1598
|
const lines = [];
|
|
@@ -1489,23 +1652,222 @@ async function updateClaudeSettings(settingsPath, ignorePatterns) {
|
|
|
1489
1652
|
console.log(`\u2705 Updated Claude Code settings: ${settingsPath}`);
|
|
1490
1653
|
}
|
|
1491
1654
|
|
|
1655
|
+
// src/generators/rules/generator-registry.ts
|
|
1656
|
+
import { join as join8 } from "path";
|
|
1657
|
+
var GENERATOR_REGISTRY = {
|
|
1658
|
+
// Simple generators - generate one file per rule
|
|
1659
|
+
cline: {
|
|
1660
|
+
type: "simple",
|
|
1661
|
+
tool: "cline",
|
|
1662
|
+
fileExtension: ".md",
|
|
1663
|
+
ignoreFileName: ".clineignore",
|
|
1664
|
+
generateContent: (rule) => rule.content.trim()
|
|
1665
|
+
},
|
|
1666
|
+
roo: {
|
|
1667
|
+
type: "simple",
|
|
1668
|
+
tool: "roo",
|
|
1669
|
+
fileExtension: ".md",
|
|
1670
|
+
ignoreFileName: ".rooignore",
|
|
1671
|
+
generateContent: (rule) => rule.content.trim()
|
|
1672
|
+
},
|
|
1673
|
+
kiro: {
|
|
1674
|
+
type: "simple",
|
|
1675
|
+
tool: "kiro",
|
|
1676
|
+
fileExtension: ".md",
|
|
1677
|
+
ignoreFileName: ".kiroignore",
|
|
1678
|
+
generateContent: (rule) => rule.content.trim()
|
|
1679
|
+
},
|
|
1680
|
+
augmentcode: {
|
|
1681
|
+
type: "simple",
|
|
1682
|
+
tool: "augmentcode",
|
|
1683
|
+
fileExtension: ".md",
|
|
1684
|
+
ignoreFileName: ".aiignore",
|
|
1685
|
+
generateContent: (rule) => rule.content.trim()
|
|
1686
|
+
},
|
|
1687
|
+
"augmentcode-legacy": {
|
|
1688
|
+
type: "simple",
|
|
1689
|
+
tool: "augmentcode-legacy",
|
|
1690
|
+
fileExtension: ".md",
|
|
1691
|
+
ignoreFileName: ".aiignore",
|
|
1692
|
+
generateContent: (rule) => rule.content.trim()
|
|
1693
|
+
},
|
|
1694
|
+
// Complex generators with custom content formatting
|
|
1695
|
+
copilot: {
|
|
1696
|
+
type: "simple",
|
|
1697
|
+
tool: "copilot",
|
|
1698
|
+
fileExtension: ".instructions.md",
|
|
1699
|
+
ignoreFileName: ".copilotignore",
|
|
1700
|
+
generateContent: (rule) => {
|
|
1701
|
+
const lines = [];
|
|
1702
|
+
lines.push("---");
|
|
1703
|
+
lines.push(`description: "${rule.frontmatter.description}"`);
|
|
1704
|
+
if (rule.frontmatter.globs.length > 0) {
|
|
1705
|
+
lines.push(`applyTo: "${rule.frontmatter.globs.join(", ")}"`);
|
|
1706
|
+
} else {
|
|
1707
|
+
lines.push('applyTo: "**"');
|
|
1708
|
+
}
|
|
1709
|
+
lines.push("---");
|
|
1710
|
+
lines.push(rule.content);
|
|
1711
|
+
return lines.join("\n");
|
|
1712
|
+
},
|
|
1713
|
+
pathResolver: (rule, outputDir) => {
|
|
1714
|
+
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
1715
|
+
return join8(outputDir, `${baseFilename}.instructions.md`);
|
|
1716
|
+
}
|
|
1717
|
+
},
|
|
1718
|
+
cursor: {
|
|
1719
|
+
type: "simple",
|
|
1720
|
+
tool: "cursor",
|
|
1721
|
+
fileExtension: ".md",
|
|
1722
|
+
ignoreFileName: ".cursorignore",
|
|
1723
|
+
generateContent: (rule) => rule.content.trim()
|
|
1724
|
+
},
|
|
1725
|
+
codexcli: {
|
|
1726
|
+
type: "simple",
|
|
1727
|
+
tool: "codexcli",
|
|
1728
|
+
fileExtension: ".md",
|
|
1729
|
+
ignoreFileName: ".codexignore",
|
|
1730
|
+
generateContent: (rule) => rule.content.trim()
|
|
1731
|
+
},
|
|
1732
|
+
// Complex generators with root + detail pattern
|
|
1733
|
+
claudecode: {
|
|
1734
|
+
type: "complex",
|
|
1735
|
+
tool: "claudecode",
|
|
1736
|
+
fileExtension: ".md",
|
|
1737
|
+
ignoreFileName: ".aiignore",
|
|
1738
|
+
generateContent: (rule) => {
|
|
1739
|
+
const lines = [];
|
|
1740
|
+
if (rule.frontmatter.description) {
|
|
1741
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
1742
|
+
`);
|
|
1743
|
+
}
|
|
1744
|
+
lines.push(rule.content.trim());
|
|
1745
|
+
return lines.join("\n");
|
|
1746
|
+
}
|
|
1747
|
+
// NOTE: Claude Code specific logic is handled in the actual generator file
|
|
1748
|
+
// due to complex settings.json manipulation requirements
|
|
1749
|
+
},
|
|
1750
|
+
geminicli: {
|
|
1751
|
+
type: "complex",
|
|
1752
|
+
tool: "geminicli",
|
|
1753
|
+
fileExtension: ".md",
|
|
1754
|
+
ignoreFileName: ".aiexclude",
|
|
1755
|
+
generateContent: (rule) => {
|
|
1756
|
+
const lines = [];
|
|
1757
|
+
if (rule.frontmatter.description) {
|
|
1758
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
1759
|
+
`);
|
|
1760
|
+
}
|
|
1761
|
+
lines.push(rule.content.trim());
|
|
1762
|
+
return lines.join("\n");
|
|
1763
|
+
}
|
|
1764
|
+
// Complex generation handled by existing generator
|
|
1765
|
+
},
|
|
1766
|
+
junie: {
|
|
1767
|
+
type: "complex",
|
|
1768
|
+
tool: "junie",
|
|
1769
|
+
fileExtension: ".md",
|
|
1770
|
+
ignoreFileName: ".aiignore",
|
|
1771
|
+
generateContent: (rule) => {
|
|
1772
|
+
const lines = [];
|
|
1773
|
+
if (rule.frontmatter.description) {
|
|
1774
|
+
lines.push(`# ${rule.frontmatter.description}
|
|
1775
|
+
`);
|
|
1776
|
+
}
|
|
1777
|
+
lines.push(rule.content.trim());
|
|
1778
|
+
return lines.join("\n");
|
|
1779
|
+
}
|
|
1780
|
+
// Complex generation handled by existing generator
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
async function generateFromRegistry(tool, rules, config, baseDir) {
|
|
1784
|
+
const generatorConfig = GENERATOR_REGISTRY[tool];
|
|
1785
|
+
if (!generatorConfig) {
|
|
1786
|
+
throw new Error(`No generator configuration found for tool: ${tool}`);
|
|
1787
|
+
}
|
|
1788
|
+
if (generatorConfig.type === "simple") {
|
|
1789
|
+
const ruleConfig = {
|
|
1790
|
+
tool: generatorConfig.tool,
|
|
1791
|
+
fileExtension: generatorConfig.fileExtension,
|
|
1792
|
+
ignoreFileName: generatorConfig.ignoreFileName,
|
|
1793
|
+
generateContent: generatorConfig.generateContent,
|
|
1794
|
+
...generatorConfig.pathResolver && { pathResolver: generatorConfig.pathResolver }
|
|
1795
|
+
};
|
|
1796
|
+
return generateRulesConfig(rules, config, ruleConfig, baseDir);
|
|
1797
|
+
} else {
|
|
1798
|
+
const enhancedConfig = {
|
|
1799
|
+
tool: generatorConfig.tool,
|
|
1800
|
+
fileExtension: generatorConfig.fileExtension,
|
|
1801
|
+
ignoreFileName: generatorConfig.ignoreFileName,
|
|
1802
|
+
generateContent: generatorConfig.generateContent,
|
|
1803
|
+
...generatorConfig.generateRootContent && {
|
|
1804
|
+
generateRootContent: generatorConfig.generateRootContent
|
|
1805
|
+
},
|
|
1806
|
+
...generatorConfig.rootFilePath && { rootFilePath: generatorConfig.rootFilePath },
|
|
1807
|
+
...generatorConfig.generateDetailContent && {
|
|
1808
|
+
generateDetailContent: generatorConfig.generateDetailContent
|
|
1809
|
+
},
|
|
1810
|
+
...generatorConfig.detailSubDir && { detailSubDir: generatorConfig.detailSubDir },
|
|
1811
|
+
...generatorConfig.updateAdditionalConfig && {
|
|
1812
|
+
updateAdditionalConfig: generatorConfig.updateAdditionalConfig
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
return generateComplexRules(rules, config, enhancedConfig, baseDir);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1492
1819
|
// src/generators/rules/cline.ts
|
|
1493
1820
|
async function generateClineConfig(rules, config, baseDir) {
|
|
1494
|
-
return
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1821
|
+
return generateFromRegistry("cline", rules, config, baseDir);
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
// src/generators/rules/codexcli.ts
|
|
1825
|
+
async function generateCodexConfig(rules, config, baseDir) {
|
|
1826
|
+
const outputs = [];
|
|
1827
|
+
if (rules.length === 0) {
|
|
1828
|
+
return outputs;
|
|
1829
|
+
}
|
|
1830
|
+
const sortedRules = [...rules].sort((a, b) => {
|
|
1831
|
+
if (a.frontmatter.root === true && b.frontmatter.root !== true) return -1;
|
|
1832
|
+
if (a.frontmatter.root !== true && b.frontmatter.root === true) return 1;
|
|
1833
|
+
return 0;
|
|
1834
|
+
});
|
|
1835
|
+
const concatenatedContent = generateConcatenatedCodexContent(sortedRules);
|
|
1836
|
+
if (concatenatedContent.trim()) {
|
|
1837
|
+
const outputDir = resolveOutputDir(config, "codexcli", baseDir);
|
|
1838
|
+
const filepath = `${outputDir}/codex.md`;
|
|
1839
|
+
outputs.push({
|
|
1840
|
+
tool: "codexcli",
|
|
1841
|
+
filepath,
|
|
1842
|
+
content: concatenatedContent
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
const ignorePatterns = await loadIgnorePatterns(baseDir);
|
|
1846
|
+
if (ignorePatterns.patterns.length > 0) {
|
|
1847
|
+
const ignorePath = resolvePath(".codexignore", baseDir);
|
|
1848
|
+
const ignoreContent = generateIgnoreFile2(ignorePatterns.patterns, "codexcli");
|
|
1849
|
+
outputs.push({
|
|
1850
|
+
tool: "codexcli",
|
|
1851
|
+
filepath: ignorePath,
|
|
1852
|
+
content: ignoreContent
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
return outputs;
|
|
1856
|
+
}
|
|
1857
|
+
function generateConcatenatedCodexContent(rules) {
|
|
1858
|
+
const sections = [];
|
|
1859
|
+
for (const rule of rules) {
|
|
1860
|
+
const content = rule.content.trim();
|
|
1861
|
+
if (!content) {
|
|
1862
|
+
continue;
|
|
1863
|
+
}
|
|
1864
|
+
sections.push(content);
|
|
1865
|
+
}
|
|
1866
|
+
return sections.join("\n\n---\n\n");
|
|
1505
1867
|
}
|
|
1506
1868
|
|
|
1507
1869
|
// src/generators/rules/copilot.ts
|
|
1508
|
-
import { join as
|
|
1870
|
+
import { join as join9 } from "path";
|
|
1509
1871
|
async function generateCopilotConfig(rules, config, baseDir) {
|
|
1510
1872
|
return generateComplexRulesConfig(
|
|
1511
1873
|
rules,
|
|
@@ -1517,7 +1879,7 @@ async function generateCopilotConfig(rules, config, baseDir) {
|
|
|
1517
1879
|
generateContent: generateCopilotMarkdown,
|
|
1518
1880
|
getOutputPath: (rule, outputDir) => {
|
|
1519
1881
|
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
1520
|
-
return
|
|
1882
|
+
return join9(outputDir, `${baseFilename}.instructions.md`);
|
|
1521
1883
|
}
|
|
1522
1884
|
},
|
|
1523
1885
|
baseDir
|
|
@@ -1538,7 +1900,7 @@ function generateCopilotMarkdown(rule) {
|
|
|
1538
1900
|
}
|
|
1539
1901
|
|
|
1540
1902
|
// src/generators/rules/cursor.ts
|
|
1541
|
-
import { join as
|
|
1903
|
+
import { join as join10 } from "path";
|
|
1542
1904
|
async function generateCursorConfig(rules, config, baseDir) {
|
|
1543
1905
|
return generateComplexRulesConfig(
|
|
1544
1906
|
rules,
|
|
@@ -1549,7 +1911,7 @@ async function generateCursorConfig(rules, config, baseDir) {
|
|
|
1549
1911
|
ignoreFileName: ".cursorignore",
|
|
1550
1912
|
generateContent: generateCursorMarkdown,
|
|
1551
1913
|
getOutputPath: (rule, outputDir) => {
|
|
1552
|
-
return
|
|
1914
|
+
return join10(outputDir, `${rule.filename}.mdc`);
|
|
1553
1915
|
}
|
|
1554
1916
|
},
|
|
1555
1917
|
baseDir
|
|
@@ -1678,38 +2040,13 @@ function generateGuidelinesMarkdown(rootRule, detailRules) {
|
|
|
1678
2040
|
}
|
|
1679
2041
|
|
|
1680
2042
|
// src/generators/rules/kiro.ts
|
|
1681
|
-
import { join as join10 } from "path";
|
|
1682
2043
|
async function generateKiroConfig(rules, config, baseDir) {
|
|
1683
|
-
|
|
1684
|
-
for (const rule of rules) {
|
|
1685
|
-
const content = generateKiroMarkdown(rule);
|
|
1686
|
-
const outputDir = baseDir ? join10(baseDir, config.outputPaths.kiro) : config.outputPaths.kiro;
|
|
1687
|
-
const filepath = join10(outputDir, `${rule.filename}.md`);
|
|
1688
|
-
outputs.push({
|
|
1689
|
-
tool: "kiro",
|
|
1690
|
-
filepath,
|
|
1691
|
-
content
|
|
1692
|
-
});
|
|
1693
|
-
}
|
|
1694
|
-
return outputs;
|
|
1695
|
-
}
|
|
1696
|
-
function generateKiroMarkdown(rule) {
|
|
1697
|
-
return rule.content.trim();
|
|
2044
|
+
return generateFromRegistry("kiro", rules, config, baseDir);
|
|
1698
2045
|
}
|
|
1699
2046
|
|
|
1700
2047
|
// src/generators/rules/roo.ts
|
|
1701
2048
|
async function generateRooConfig(rules, config, baseDir) {
|
|
1702
|
-
return
|
|
1703
|
-
rules,
|
|
1704
|
-
config,
|
|
1705
|
-
{
|
|
1706
|
-
tool: "roo",
|
|
1707
|
-
fileExtension: ".md",
|
|
1708
|
-
ignoreFileName: ".rooignore",
|
|
1709
|
-
generateContent: (rule) => rule.content.trim()
|
|
1710
|
-
},
|
|
1711
|
-
baseDir
|
|
1712
|
-
);
|
|
2049
|
+
return generateFromRegistry("roo", rules, config, baseDir);
|
|
1713
2050
|
}
|
|
1714
2051
|
|
|
1715
2052
|
// src/core/generator.ts
|
|
@@ -1768,6 +2105,8 @@ async function generateForTool(tool, rules, config, baseDir) {
|
|
|
1768
2105
|
return generateClineConfig(rules, config, baseDir);
|
|
1769
2106
|
case "claudecode":
|
|
1770
2107
|
return await generateClaudecodeConfig(rules, config, baseDir);
|
|
2108
|
+
case "codexcli":
|
|
2109
|
+
return generateCodexConfig(rules, config, baseDir);
|
|
1771
2110
|
case "roo":
|
|
1772
2111
|
return generateRooConfig(rules, config, baseDir);
|
|
1773
2112
|
case "geminicli":
|
|
@@ -1960,6 +2299,11 @@ async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
|
|
|
1960
2299
|
path: path4.join(targetRoot, ".cline", "mcp.json"),
|
|
1961
2300
|
generate: () => generateClineMcp(config)
|
|
1962
2301
|
},
|
|
2302
|
+
{
|
|
2303
|
+
tool: "codexcli-project",
|
|
2304
|
+
path: path4.join(targetRoot, ".codex", "mcp-config.json"),
|
|
2305
|
+
generate: () => generateCodexMcp(config)
|
|
2306
|
+
},
|
|
1963
2307
|
{
|
|
1964
2308
|
tool: "gemini-project",
|
|
1965
2309
|
path: path4.join(targetRoot, ".gemini", "settings.json"),
|
|
@@ -1995,7 +2339,7 @@ async function generateMcpConfigs(projectRoot, baseDir, targetTools) {
|
|
|
1995
2339
|
try {
|
|
1996
2340
|
const content = generator.generate();
|
|
1997
2341
|
const parsed = JSON.parse(content);
|
|
1998
|
-
if (generator.tool.includes("augmentcode") || generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("junie") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
|
|
2342
|
+
if (generator.tool.includes("augmentcode") || generator.tool.includes("claude") || generator.tool.includes("cline") || generator.tool.includes("codexcli") || generator.tool.includes("cursor") || generator.tool.includes("gemini") || generator.tool.includes("junie") || generator.tool.includes("kiro") || generator.tool.includes("roo")) {
|
|
1999
2343
|
if (!parsed.mcpServers || Object.keys(parsed.mcpServers).length === 0) {
|
|
2000
2344
|
results.push({
|
|
2001
2345
|
tool: generator.tool,
|
|
@@ -2220,6 +2564,8 @@ var gitignoreCommand = async () => {
|
|
|
2220
2564
|
"**/.clineignore",
|
|
2221
2565
|
"**/CLAUDE.md",
|
|
2222
2566
|
"**/.claude/memories/",
|
|
2567
|
+
"**/codex.md",
|
|
2568
|
+
"**/.codexignore",
|
|
2223
2569
|
"**/.roo/rules/",
|
|
2224
2570
|
"**/.rooignore",
|
|
2225
2571
|
"**/.copilotignore",
|
|
@@ -2238,6 +2584,7 @@ var gitignoreCommand = async () => {
|
|
|
2238
2584
|
"**/.cursor/mcp.json",
|
|
2239
2585
|
"**/.cline/mcp.json",
|
|
2240
2586
|
"**/.vscode/mcp.json",
|
|
2587
|
+
"**/.codex/mcp-config.json",
|
|
2241
2588
|
"**/.gemini/settings.json",
|
|
2242
2589
|
"**/.roo/mcp.json"
|
|
2243
2590
|
];
|
|
@@ -2296,36 +2643,63 @@ function addRules(result, rules) {
|
|
|
2296
2643
|
}
|
|
2297
2644
|
result.rules.push(...rules);
|
|
2298
2645
|
}
|
|
2299
|
-
function handleParseError(error, context) {
|
|
2300
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2301
|
-
return `${context}: ${errorMessage}`;
|
|
2302
|
-
}
|
|
2303
2646
|
async function safeReadFile(operation, errorContext) {
|
|
2304
2647
|
try {
|
|
2305
2648
|
const result = await operation();
|
|
2306
|
-
return
|
|
2649
|
+
return createSuccessResult(result);
|
|
2307
2650
|
} catch (error) {
|
|
2308
|
-
return
|
|
2309
|
-
success: false,
|
|
2310
|
-
error: handleParseError(error, errorContext)
|
|
2311
|
-
};
|
|
2651
|
+
return createErrorResult(error, errorContext);
|
|
2312
2652
|
}
|
|
2313
2653
|
}
|
|
2314
2654
|
|
|
2315
2655
|
// src/parsers/augmentcode.ts
|
|
2316
2656
|
async function parseAugmentcodeConfiguration(baseDir = process.cwd()) {
|
|
2657
|
+
return parseUnifiedAugmentcode(baseDir, {
|
|
2658
|
+
rulesDir: ".augment/rules",
|
|
2659
|
+
targetName: "augmentcode",
|
|
2660
|
+
filenamePrefix: "augmentcode"
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
async function parseAugmentcodeLegacyConfiguration(baseDir = process.cwd()) {
|
|
2664
|
+
return parseUnifiedAugmentcode(baseDir, {
|
|
2665
|
+
legacyFilePath: ".augment-guidelines",
|
|
2666
|
+
targetName: "augmentcode-legacy",
|
|
2667
|
+
filenamePrefix: "augmentcode-legacy"
|
|
2668
|
+
});
|
|
2669
|
+
}
|
|
2670
|
+
async function parseUnifiedAugmentcode(baseDir, config) {
|
|
2317
2671
|
const result = createParseResult();
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2672
|
+
if (config.rulesDir) {
|
|
2673
|
+
const rulesDir = join15(baseDir, config.rulesDir);
|
|
2674
|
+
if (await fileExists(rulesDir)) {
|
|
2675
|
+
const rulesResult = await parseAugmentRules(rulesDir, config);
|
|
2676
|
+
addRules(result, rulesResult.rules);
|
|
2677
|
+
result.errors.push(...rulesResult.errors);
|
|
2678
|
+
} else {
|
|
2679
|
+
addError(
|
|
2680
|
+
result,
|
|
2681
|
+
`No AugmentCode configuration found. Expected ${config.rulesDir} directory.`
|
|
2682
|
+
);
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
if (config.legacyFilePath) {
|
|
2686
|
+
const legacyPath = join15(baseDir, config.legacyFilePath);
|
|
2687
|
+
if (await fileExists(legacyPath)) {
|
|
2688
|
+
const legacyResult = await parseAugmentGuidelines(legacyPath, config);
|
|
2689
|
+
if (legacyResult.rule) {
|
|
2690
|
+
addRule(result, legacyResult.rule);
|
|
2691
|
+
}
|
|
2692
|
+
result.errors.push(...legacyResult.errors);
|
|
2693
|
+
} else {
|
|
2694
|
+
addError(
|
|
2695
|
+
result,
|
|
2696
|
+
`No AugmentCode legacy configuration found. Expected ${config.legacyFilePath} file.`
|
|
2697
|
+
);
|
|
2698
|
+
}
|
|
2325
2699
|
}
|
|
2326
2700
|
return { rules: result.rules || [], errors: result.errors };
|
|
2327
2701
|
}
|
|
2328
|
-
async function parseAugmentRules(rulesDir) {
|
|
2702
|
+
async function parseAugmentRules(rulesDir, config) {
|
|
2329
2703
|
const rules = [];
|
|
2330
2704
|
const errors = [];
|
|
2331
2705
|
try {
|
|
@@ -2345,7 +2719,7 @@ async function parseAugmentRules(rulesDir) {
|
|
|
2345
2719
|
const filename = basename2(file, file.endsWith(".mdc") ? ".mdc" : ".md");
|
|
2346
2720
|
const frontmatter = {
|
|
2347
2721
|
root: isRoot,
|
|
2348
|
-
targets: [
|
|
2722
|
+
targets: [config.targetName],
|
|
2349
2723
|
description,
|
|
2350
2724
|
globs: ["**/*"],
|
|
2351
2725
|
// AugmentCode doesn't use specific globs in the same way
|
|
@@ -2354,7 +2728,7 @@ async function parseAugmentRules(rulesDir) {
|
|
|
2354
2728
|
rules.push({
|
|
2355
2729
|
frontmatter,
|
|
2356
2730
|
content: parsed.content.trim(),
|
|
2357
|
-
filename:
|
|
2731
|
+
filename: `${config.filenamePrefix}-${ruleType}-${filename}`,
|
|
2358
2732
|
filepath: filePath
|
|
2359
2733
|
});
|
|
2360
2734
|
} catch (error) {
|
|
@@ -2365,50 +2739,33 @@ async function parseAugmentRules(rulesDir) {
|
|
|
2365
2739
|
}
|
|
2366
2740
|
} catch (error) {
|
|
2367
2741
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2368
|
-
errors.push(`Failed to read .
|
|
2742
|
+
errors.push(`Failed to read ${config.rulesDir || rulesDir} directory: ${errorMessage}`);
|
|
2369
2743
|
}
|
|
2370
2744
|
return { rules, errors };
|
|
2371
2745
|
}
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
if (content.trim()) {
|
|
2396
|
-
const frontmatter = {
|
|
2397
|
-
root: true,
|
|
2398
|
-
// Legacy guidelines become root rules
|
|
2399
|
-
targets: ["augmentcode-legacy"],
|
|
2400
|
-
description: "Legacy AugmentCode guidelines",
|
|
2401
|
-
globs: ["**/*"]
|
|
2402
|
-
};
|
|
2403
|
-
return {
|
|
2404
|
-
frontmatter,
|
|
2405
|
-
content: content.trim(),
|
|
2406
|
-
filename: "augmentcode-legacy-guidelines",
|
|
2407
|
-
filepath: guidelinesPath
|
|
2408
|
-
};
|
|
2409
|
-
}
|
|
2410
|
-
return null;
|
|
2411
|
-
}, "Failed to parse .augment-guidelines");
|
|
2746
|
+
async function parseAugmentGuidelines(guidelinesPath, config) {
|
|
2747
|
+
const parseResult = await safeReadFile(
|
|
2748
|
+
async () => {
|
|
2749
|
+
const content = await readFileContent(guidelinesPath);
|
|
2750
|
+
if (content.trim()) {
|
|
2751
|
+
const frontmatter = {
|
|
2752
|
+
root: true,
|
|
2753
|
+
// Legacy guidelines become root rules
|
|
2754
|
+
targets: [config.targetName],
|
|
2755
|
+
description: "Legacy AugmentCode guidelines",
|
|
2756
|
+
globs: ["**/*"]
|
|
2757
|
+
};
|
|
2758
|
+
return {
|
|
2759
|
+
frontmatter,
|
|
2760
|
+
content: content.trim(),
|
|
2761
|
+
filename: `${config.filenamePrefix}-guidelines`,
|
|
2762
|
+
filepath: guidelinesPath
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
return null;
|
|
2766
|
+
},
|
|
2767
|
+
`Failed to parse ${config.legacyFilePath || guidelinesPath}`
|
|
2768
|
+
);
|
|
2412
2769
|
if (parseResult.success) {
|
|
2413
2770
|
return { rule: parseResult.result || null, errors: [] };
|
|
2414
2771
|
} else {
|
|
@@ -2417,33 +2774,36 @@ async function parseAugmentGuidelines(guidelinesPath) {
|
|
|
2417
2774
|
}
|
|
2418
2775
|
|
|
2419
2776
|
// src/parsers/shared-helpers.ts
|
|
2420
|
-
import { basename as basename3, join as
|
|
2777
|
+
import { basename as basename3, join as join16 } from "path";
|
|
2421
2778
|
import matter3 from "gray-matter";
|
|
2422
2779
|
async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
2423
2780
|
const errors = [];
|
|
2424
2781
|
const rules = [];
|
|
2425
2782
|
if (config.mainFile) {
|
|
2426
|
-
const
|
|
2783
|
+
const mainFile = config.mainFile;
|
|
2784
|
+
const mainFilePath = resolvePath(mainFile.path, baseDir);
|
|
2427
2785
|
if (await fileExists(mainFilePath)) {
|
|
2428
|
-
|
|
2786
|
+
const result = await safeAsyncOperation(async () => {
|
|
2429
2787
|
const rawContent = await readFileContent(mainFilePath);
|
|
2430
2788
|
let content;
|
|
2431
2789
|
let frontmatter;
|
|
2432
|
-
if (
|
|
2790
|
+
if (mainFile.useFrontmatter) {
|
|
2433
2791
|
const parsed = matter3(rawContent);
|
|
2434
2792
|
content = parsed.content.trim();
|
|
2793
|
+
const parsedFrontmatter = parsed.data;
|
|
2435
2794
|
frontmatter = {
|
|
2436
|
-
root: false,
|
|
2795
|
+
root: mainFile.isRoot ?? false,
|
|
2437
2796
|
targets: [config.tool],
|
|
2438
|
-
description:
|
|
2439
|
-
globs: ["**/*"]
|
|
2797
|
+
description: parsedFrontmatter.description || mainFile.description,
|
|
2798
|
+
globs: Array.isArray(parsedFrontmatter.globs) ? parsedFrontmatter.globs : ["**/*"],
|
|
2799
|
+
...parsedFrontmatter.tags && { tags: parsedFrontmatter.tags }
|
|
2440
2800
|
};
|
|
2441
2801
|
} else {
|
|
2442
2802
|
content = rawContent.trim();
|
|
2443
2803
|
frontmatter = {
|
|
2444
|
-
root: false,
|
|
2804
|
+
root: mainFile.isRoot ?? false,
|
|
2445
2805
|
targets: [config.tool],
|
|
2446
|
-
description:
|
|
2806
|
+
description: mainFile.description,
|
|
2447
2807
|
globs: ["**/*"]
|
|
2448
2808
|
};
|
|
2449
2809
|
}
|
|
@@ -2451,43 +2811,52 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
2451
2811
|
rules.push({
|
|
2452
2812
|
frontmatter,
|
|
2453
2813
|
content,
|
|
2454
|
-
filename: "instructions",
|
|
2814
|
+
filename: mainFile.filenameOverride || "instructions",
|
|
2455
2815
|
filepath: mainFilePath
|
|
2456
2816
|
});
|
|
2457
2817
|
}
|
|
2458
|
-
}
|
|
2459
|
-
|
|
2460
|
-
errors.push(
|
|
2818
|
+
}, `Failed to parse ${mainFile.path}`);
|
|
2819
|
+
if (!result.success) {
|
|
2820
|
+
errors.push(result.error);
|
|
2461
2821
|
}
|
|
2462
2822
|
}
|
|
2463
2823
|
}
|
|
2464
2824
|
if (config.directories) {
|
|
2465
2825
|
for (const dirConfig of config.directories) {
|
|
2466
|
-
const dirPath =
|
|
2826
|
+
const dirPath = resolvePath(dirConfig.directory, baseDir);
|
|
2467
2827
|
if (await fileExists(dirPath)) {
|
|
2468
|
-
|
|
2828
|
+
const result = await safeAsyncOperation(async () => {
|
|
2469
2829
|
const { readdir: readdir2 } = await import("fs/promises");
|
|
2470
2830
|
const files = await readdir2(dirPath);
|
|
2471
2831
|
for (const file of files) {
|
|
2472
2832
|
if (file.endsWith(dirConfig.filePattern)) {
|
|
2473
|
-
const filePath =
|
|
2474
|
-
|
|
2833
|
+
const filePath = join16(dirPath, file);
|
|
2834
|
+
const fileResult = await safeAsyncOperation(async () => {
|
|
2475
2835
|
const rawContent = await readFileContent(filePath);
|
|
2476
2836
|
let content;
|
|
2837
|
+
let frontmatter;
|
|
2838
|
+
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
2477
2839
|
if (dirConfig.filePattern === ".instructions.md") {
|
|
2478
2840
|
const parsed = matter3(rawContent);
|
|
2479
2841
|
content = parsed.content.trim();
|
|
2842
|
+
const parsedFrontmatter = parsed.data;
|
|
2843
|
+
frontmatter = {
|
|
2844
|
+
root: false,
|
|
2845
|
+
targets: [config.tool],
|
|
2846
|
+
description: parsedFrontmatter.description || `${dirConfig.description}: ${filename}`,
|
|
2847
|
+
globs: Array.isArray(parsedFrontmatter.globs) ? parsedFrontmatter.globs : ["**/*"],
|
|
2848
|
+
...parsedFrontmatter.tags && { tags: parsedFrontmatter.tags }
|
|
2849
|
+
};
|
|
2480
2850
|
} else {
|
|
2481
2851
|
content = rawContent.trim();
|
|
2482
|
-
|
|
2483
|
-
if (content) {
|
|
2484
|
-
const filename = file.replace(new RegExp(`\\${dirConfig.filePattern}$`), "");
|
|
2485
|
-
const frontmatter = {
|
|
2852
|
+
frontmatter = {
|
|
2486
2853
|
root: false,
|
|
2487
2854
|
targets: [config.tool],
|
|
2488
2855
|
description: `${dirConfig.description}: ${filename}`,
|
|
2489
2856
|
globs: ["**/*"]
|
|
2490
2857
|
};
|
|
2858
|
+
}
|
|
2859
|
+
if (content) {
|
|
2491
2860
|
rules.push({
|
|
2492
2861
|
frontmatter,
|
|
2493
2862
|
content,
|
|
@@ -2495,15 +2864,15 @@ async function parseConfigurationFiles(baseDir = process.cwd(), config) {
|
|
|
2495
2864
|
filepath: filePath
|
|
2496
2865
|
});
|
|
2497
2866
|
}
|
|
2498
|
-
}
|
|
2499
|
-
|
|
2500
|
-
errors.push(
|
|
2867
|
+
}, `Failed to parse ${filePath}`);
|
|
2868
|
+
if (!fileResult.success) {
|
|
2869
|
+
errors.push(fileResult.error);
|
|
2501
2870
|
}
|
|
2502
2871
|
}
|
|
2503
2872
|
}
|
|
2504
|
-
}
|
|
2505
|
-
|
|
2506
|
-
errors.push(
|
|
2873
|
+
}, `Failed to parse ${dirConfig.directory} files`);
|
|
2874
|
+
if (!result.success) {
|
|
2875
|
+
errors.push(result.error);
|
|
2507
2876
|
}
|
|
2508
2877
|
}
|
|
2509
2878
|
}
|
|
@@ -2518,7 +2887,7 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2518
2887
|
const rules = [];
|
|
2519
2888
|
let ignorePatterns;
|
|
2520
2889
|
let mcpServers;
|
|
2521
|
-
const mainFilePath =
|
|
2890
|
+
const mainFilePath = resolvePath(config.mainFileName, baseDir);
|
|
2522
2891
|
if (!await fileExists(mainFilePath)) {
|
|
2523
2892
|
errors.push(`${config.mainFileName} file not found`);
|
|
2524
2893
|
return { rules, errors };
|
|
@@ -2529,12 +2898,12 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2529
2898
|
if (mainRule) {
|
|
2530
2899
|
rules.push(mainRule);
|
|
2531
2900
|
}
|
|
2532
|
-
const memoryDir =
|
|
2901
|
+
const memoryDir = resolvePath(config.memoryDirPath, baseDir);
|
|
2533
2902
|
if (await fileExists(memoryDir)) {
|
|
2534
2903
|
const memoryRules = await parseMemoryFiles(memoryDir, config);
|
|
2535
2904
|
rules.push(...memoryRules);
|
|
2536
2905
|
}
|
|
2537
|
-
const settingsPath =
|
|
2906
|
+
const settingsPath = resolvePath(config.settingsPath, baseDir);
|
|
2538
2907
|
if (await fileExists(settingsPath)) {
|
|
2539
2908
|
const settingsResult = await parseSettingsFile(settingsPath, config.tool);
|
|
2540
2909
|
if (settingsResult.ignorePatterns) {
|
|
@@ -2546,7 +2915,7 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2546
2915
|
errors.push(...settingsResult.errors);
|
|
2547
2916
|
}
|
|
2548
2917
|
if (config.additionalIgnoreFile) {
|
|
2549
|
-
const additionalIgnorePath =
|
|
2918
|
+
const additionalIgnorePath = resolvePath(config.additionalIgnoreFile.path, baseDir);
|
|
2550
2919
|
if (await fileExists(additionalIgnorePath)) {
|
|
2551
2920
|
const additionalPatterns = await config.additionalIgnoreFile.parser(additionalIgnorePath);
|
|
2552
2921
|
if (additionalPatterns.length > 0) {
|
|
@@ -2555,8 +2924,7 @@ async function parseMemoryBasedConfiguration(baseDir = process.cwd(), config) {
|
|
|
2555
2924
|
}
|
|
2556
2925
|
}
|
|
2557
2926
|
} catch (error) {
|
|
2558
|
-
|
|
2559
|
-
errors.push(`Failed to parse ${config.tool} configuration: ${errorMessage}`);
|
|
2927
|
+
errors.push(`Failed to parse ${config.tool} configuration: ${getErrorMessage(error)}`);
|
|
2560
2928
|
}
|
|
2561
2929
|
return {
|
|
2562
2930
|
rules,
|
|
@@ -2600,7 +2968,7 @@ async function parseMemoryFiles(memoryDir, config) {
|
|
|
2600
2968
|
const files = await readdir2(memoryDir);
|
|
2601
2969
|
for (const file of files) {
|
|
2602
2970
|
if (file.endsWith(".md")) {
|
|
2603
|
-
const filePath =
|
|
2971
|
+
const filePath = join16(memoryDir, file);
|
|
2604
2972
|
const content = await readFileContent(filePath);
|
|
2605
2973
|
if (content.trim()) {
|
|
2606
2974
|
const filename = basename3(file, ".md");
|
|
@@ -2652,8 +3020,7 @@ async function parseSettingsFile(settingsPath, tool) {
|
|
|
2652
3020
|
mcpServers = parseResult.data.mcpServers;
|
|
2653
3021
|
}
|
|
2654
3022
|
} catch (error) {
|
|
2655
|
-
|
|
2656
|
-
errors.push(`Failed to parse settings.json: ${errorMessage}`);
|
|
3023
|
+
errors.push(`Failed to parse settings.json: ${getErrorMessage(error)}`);
|
|
2657
3024
|
}
|
|
2658
3025
|
return {
|
|
2659
3026
|
errors,
|
|
@@ -2695,6 +3062,9 @@ async function parseClineConfiguration(baseDir = process.cwd()) {
|
|
|
2695
3062
|
});
|
|
2696
3063
|
}
|
|
2697
3064
|
|
|
3065
|
+
// src/parsers/codexcli.ts
|
|
3066
|
+
import { join as join17 } from "path";
|
|
3067
|
+
|
|
2698
3068
|
// src/parsers/copilot.ts
|
|
2699
3069
|
async function parseCopilotConfiguration(baseDir = process.cwd()) {
|
|
2700
3070
|
return parseConfigurationFiles(baseDir, {
|
|
@@ -3430,12 +3800,12 @@ async function watchCommand() {
|
|
|
3430
3800
|
|
|
3431
3801
|
// src/cli/index.ts
|
|
3432
3802
|
var program = new Command();
|
|
3433
|
-
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.
|
|
3803
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.55.0");
|
|
3434
3804
|
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
3435
3805
|
program.command("add <filename>").description("Add a new rule file").action(addCommand);
|
|
3436
3806
|
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
3437
3807
|
program.command("import").description("Import configurations from AI tools to rulesync format").option("--augmentcode", "Import from AugmentCode (.augment/rules/)").option("--augmentcode-legacy", "Import from AugmentCode legacy format (.augment-guidelines)").option("--claudecode", "Import from Claude Code (CLAUDE.md)").option("--cursor", "Import from Cursor (.cursorrules)").option("--copilot", "Import from GitHub Copilot (.github/copilot-instructions.md)").option("--cline", "Import from Cline (.cline/instructions.md)").option("--roo", "Import from Roo Code (.roo/instructions.md)").option("--geminicli", "Import from Gemini CLI (GEMINI.md)").option("--junie", "Import from JetBrains Junie (.junie/guidelines.md)").option("-v, --verbose", "Verbose output").action(importCommand);
|
|
3438
|
-
program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
3808
|
+
program.command("generate").description("Generate configuration files for AI tools").option("--augmentcode", "Generate only for AugmentCode").option("--augmentcode-legacy", "Generate only for AugmentCode legacy format").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--codexcli", "Generate only for OpenAI Codex CLI").option("--claudecode", "Generate only for Claude Code").option("--roo", "Generate only for Roo Code").option("--geminicli", "Generate only for Gemini CLI").option("--junie", "Generate only for JetBrains Junie").option("--kiro", "Generate only for Kiro IDE").option("--delete", "Delete all existing files in output directories before generating").option(
|
|
3439
3809
|
"-b, --base-dir <paths>",
|
|
3440
3810
|
"Base directories to generate files (comma-separated for multiple paths)"
|
|
3441
3811
|
).option("-v, --verbose", "Verbose output").option("-c, --config <path>", "Path to configuration file").option("--no-config", "Disable configuration file loading").action(async (options) => {
|
|
@@ -3445,6 +3815,7 @@ program.command("generate").description("Generate configuration files for AI too
|
|
|
3445
3815
|
if (options.copilot) tools.push("copilot");
|
|
3446
3816
|
if (options.cursor) tools.push("cursor");
|
|
3447
3817
|
if (options.cline) tools.push("cline");
|
|
3818
|
+
if (options.codexcli) tools.push("codexcli");
|
|
3448
3819
|
if (options.claudecode) tools.push("claudecode");
|
|
3449
3820
|
if (options.roo) tools.push("roo");
|
|
3450
3821
|
if (options.geminicli) tools.push("geminicli");
|