rulesync 0.2.0 → 0.4.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/LICENSE +21 -0
- package/README.md +55 -43
- package/dist/index.js +231 -163
- package/dist/index.mjs +229 -161
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,196 +26,178 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// src/cli/index.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
|
|
29
|
-
// src/generators/
|
|
29
|
+
// src/generators/claude.ts
|
|
30
30
|
var import_node_path = require("path");
|
|
31
|
-
async function
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
async function generateClaudeConfig(rules, config) {
|
|
32
|
+
const outputs = [];
|
|
33
|
+
const overviewRules = rules.filter((r) => r.frontmatter.ruleLevel === "overview");
|
|
34
|
+
const detailRules = rules.filter((r) => r.frontmatter.ruleLevel === "detail");
|
|
35
|
+
const claudeMdContent = generateClaudeMarkdown(overviewRules, detailRules);
|
|
36
|
+
outputs.push({
|
|
37
|
+
tool: "claude",
|
|
38
|
+
filepath: (0, import_node_path.join)(config.outputPaths.claude, "CLAUDE.md"),
|
|
39
|
+
content: claudeMdContent
|
|
37
40
|
});
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
for (const rule of detailRules) {
|
|
42
|
+
const memoryContent = generateMemoryFile(rule);
|
|
43
|
+
outputs.push({
|
|
44
|
+
tool: "claude",
|
|
45
|
+
filepath: (0, import_node_path.join)(config.outputPaths.claude, ".claude", "memories", `${rule.filename}.md`),
|
|
46
|
+
content: memoryContent
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return outputs;
|
|
45
50
|
}
|
|
46
|
-
function
|
|
51
|
+
function generateClaudeMarkdown(overviewRules, detailRules) {
|
|
47
52
|
const lines = [];
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
lines.push("");
|
|
52
|
-
lines.push("These rules provide project-specific guidance for AI-assisted development.");
|
|
53
|
-
lines.push("");
|
|
54
|
-
const highPriorityRules = rules.filter((r) => r.frontmatter.priority === "high");
|
|
55
|
-
const lowPriorityRules = rules.filter((r) => r.frontmatter.priority === "low");
|
|
56
|
-
if (highPriorityRules.length > 0) {
|
|
57
|
-
lines.push("## High Priority Guidelines");
|
|
58
|
-
lines.push("");
|
|
59
|
-
lines.push("These are critical rules that should always be followed:");
|
|
60
|
-
lines.push("");
|
|
61
|
-
for (const rule of highPriorityRules) {
|
|
62
|
-
lines.push(...formatRuleForCline(rule));
|
|
53
|
+
if (detailRules.length > 0) {
|
|
54
|
+
for (const rule of detailRules) {
|
|
55
|
+
lines.push(`@${rule.filename}`);
|
|
63
56
|
}
|
|
64
|
-
}
|
|
65
|
-
if (lowPriorityRules.length > 0) {
|
|
66
|
-
lines.push("## Standard Guidelines");
|
|
67
57
|
lines.push("");
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
}
|
|
59
|
+
lines.push("# Claude Code Memory - Project Instructions");
|
|
60
|
+
lines.push("");
|
|
61
|
+
lines.push(
|
|
62
|
+
"Generated from rulesync configuration. These instructions guide Claude Code's behavior for this project."
|
|
63
|
+
);
|
|
64
|
+
lines.push("");
|
|
65
|
+
if (overviewRules.length > 0) {
|
|
66
|
+
for (const rule of overviewRules) {
|
|
67
|
+
lines.push(...formatRuleForClaude(rule));
|
|
72
68
|
}
|
|
73
69
|
}
|
|
74
70
|
return lines.join("\n");
|
|
75
71
|
}
|
|
76
|
-
function
|
|
72
|
+
function formatRuleForClaude(rule) {
|
|
77
73
|
const lines = [];
|
|
78
74
|
lines.push(`### ${rule.filename}`);
|
|
79
75
|
lines.push("");
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
if (rule.frontmatter.description) {
|
|
77
|
+
lines.push(`**Description:** ${rule.frontmatter.description}`);
|
|
78
|
+
lines.push("");
|
|
79
|
+
}
|
|
80
|
+
if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
|
|
81
|
+
lines.push(`**File patterns:** ${rule.frontmatter.globs.join(", ")}`);
|
|
84
82
|
lines.push("");
|
|
85
83
|
}
|
|
86
|
-
lines.push("**Guidelines:**");
|
|
87
|
-
lines.push("");
|
|
88
84
|
lines.push(rule.content);
|
|
89
85
|
lines.push("");
|
|
90
|
-
lines.push("---");
|
|
91
|
-
lines.push("");
|
|
92
86
|
return lines;
|
|
93
87
|
}
|
|
94
|
-
|
|
95
|
-
// src/generators/copilot.ts
|
|
96
|
-
var import_node_path2 = require("path");
|
|
97
|
-
async function generateCopilotConfig(rules, config) {
|
|
98
|
-
const sortedRules = rules.sort((a, b) => {
|
|
99
|
-
if (a.frontmatter.priority !== b.frontmatter.priority) {
|
|
100
|
-
return a.frontmatter.priority === "high" ? -1 : 1;
|
|
101
|
-
}
|
|
102
|
-
return a.filename.localeCompare(b.filename);
|
|
103
|
-
});
|
|
104
|
-
const content = generateCopilotMarkdown(sortedRules);
|
|
105
|
-
const filepath = (0, import_node_path2.join)(config.outputPaths.copilot, "ai-rules.instructions.md");
|
|
106
|
-
return {
|
|
107
|
-
tool: "copilot",
|
|
108
|
-
filepath,
|
|
109
|
-
content
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
function generateCopilotMarkdown(rules) {
|
|
88
|
+
function generateMemoryFile(rule) {
|
|
113
89
|
const lines = [];
|
|
114
|
-
lines.push("
|
|
115
|
-
lines.push('description: "AI rules configuration for GitHub Copilot"');
|
|
116
|
-
lines.push('applyTo: "**"');
|
|
117
|
-
lines.push("---");
|
|
90
|
+
lines.push("Please also refer to the following files as needed:");
|
|
118
91
|
lines.push("");
|
|
119
|
-
lines.push("
|
|
92
|
+
lines.push("---");
|
|
120
93
|
lines.push("");
|
|
121
|
-
lines.push(
|
|
122
|
-
"Generated from ai-rules configuration. These instructions guide GitHub Copilot's code suggestions."
|
|
123
|
-
);
|
|
94
|
+
lines.push(`# ${rule.filename}`);
|
|
124
95
|
lines.push("");
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (highPriorityRules.length > 0) {
|
|
128
|
-
lines.push("## High Priority Rules");
|
|
96
|
+
if (rule.frontmatter.description) {
|
|
97
|
+
lines.push(`**Description:** ${rule.frontmatter.description}`);
|
|
129
98
|
lines.push("");
|
|
130
|
-
for (const rule of highPriorityRules) {
|
|
131
|
-
lines.push(...formatRuleForCopilot(rule));
|
|
132
|
-
}
|
|
133
99
|
}
|
|
134
|
-
if (
|
|
135
|
-
lines.push(
|
|
100
|
+
if (rule.frontmatter.globs && rule.frontmatter.globs.length > 0) {
|
|
101
|
+
lines.push(`**File patterns:** ${rule.frontmatter.globs.join(", ")}`);
|
|
136
102
|
lines.push("");
|
|
137
|
-
for (const rule of lowPriorityRules) {
|
|
138
|
-
lines.push(...formatRuleForCopilot(rule));
|
|
139
|
-
}
|
|
140
103
|
}
|
|
104
|
+
lines.push(rule.content);
|
|
141
105
|
return lines.join("\n");
|
|
142
106
|
}
|
|
143
|
-
|
|
107
|
+
|
|
108
|
+
// src/generators/cline.ts
|
|
109
|
+
var import_node_path2 = require("path");
|
|
110
|
+
async function generateClineConfig(rules, config) {
|
|
111
|
+
const outputs = [];
|
|
112
|
+
for (const rule of rules) {
|
|
113
|
+
const content = generateClineMarkdown(rule);
|
|
114
|
+
const filepath = (0, import_node_path2.join)(config.outputPaths.cline, `${rule.filename}.md`);
|
|
115
|
+
outputs.push({
|
|
116
|
+
tool: "cline",
|
|
117
|
+
filepath,
|
|
118
|
+
content
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return outputs;
|
|
122
|
+
}
|
|
123
|
+
function generateClineMarkdown(rule) {
|
|
144
124
|
const lines = [];
|
|
145
|
-
lines.push(
|
|
146
|
-
lines.push("");
|
|
147
|
-
lines.push(`**Description:** ${rule.frontmatter.description}`);
|
|
125
|
+
lines.push(`# ${rule.frontmatter.description}`);
|
|
148
126
|
lines.push("");
|
|
149
127
|
if (rule.frontmatter.globs.length > 0) {
|
|
150
|
-
lines.push(`**Applies to:** ${rule.frontmatter.globs.join(", ")}`);
|
|
128
|
+
lines.push(`**Applies to files:** ${rule.frontmatter.globs.join(", ")}`);
|
|
151
129
|
lines.push("");
|
|
152
130
|
}
|
|
153
131
|
lines.push(rule.content);
|
|
154
|
-
lines.
|
|
155
|
-
return lines;
|
|
132
|
+
return lines.join("\n");
|
|
156
133
|
}
|
|
157
134
|
|
|
158
|
-
// src/generators/
|
|
135
|
+
// src/generators/copilot.ts
|
|
159
136
|
var import_node_path3 = require("path");
|
|
160
|
-
async function
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
};
|
|
137
|
+
async function generateCopilotConfig(rules, config) {
|
|
138
|
+
const outputs = [];
|
|
139
|
+
for (const rule of rules) {
|
|
140
|
+
const content = generateCopilotMarkdown(rule);
|
|
141
|
+
const baseFilename = rule.filename.replace(/\.md$/, "");
|
|
142
|
+
const filepath = (0, import_node_path3.join)(config.outputPaths.copilot, `${baseFilename}.instructions.md`);
|
|
143
|
+
outputs.push({
|
|
144
|
+
tool: "copilot",
|
|
145
|
+
filepath,
|
|
146
|
+
content
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return outputs;
|
|
174
150
|
}
|
|
175
|
-
function
|
|
151
|
+
function generateCopilotMarkdown(rule) {
|
|
176
152
|
const lines = [];
|
|
177
153
|
lines.push("---");
|
|
178
|
-
lines.push(
|
|
179
|
-
|
|
154
|
+
lines.push(`description: "${rule.frontmatter.description}"`);
|
|
155
|
+
if (rule.frontmatter.globs.length > 0) {
|
|
156
|
+
lines.push(`applyTo: "${rule.frontmatter.globs.join(", ")}"`);
|
|
157
|
+
} else {
|
|
158
|
+
lines.push('applyTo: "**"');
|
|
159
|
+
}
|
|
180
160
|
lines.push("---");
|
|
181
161
|
lines.push("");
|
|
182
|
-
lines.push(
|
|
183
|
-
lines.
|
|
184
|
-
|
|
185
|
-
|
|
162
|
+
lines.push(rule.content);
|
|
163
|
+
return lines.join("\n");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/generators/cursor.ts
|
|
167
|
+
var import_node_path4 = require("path");
|
|
168
|
+
async function generateCursorConfig(rules, config) {
|
|
169
|
+
const outputs = [];
|
|
186
170
|
for (const rule of rules) {
|
|
187
|
-
|
|
171
|
+
const content = generateCursorMarkdown(rule);
|
|
172
|
+
const filepath = (0, import_node_path4.join)(config.outputPaths.cursor, `${rule.filename}.md`);
|
|
173
|
+
outputs.push({
|
|
174
|
+
tool: "cursor",
|
|
175
|
+
filepath,
|
|
176
|
+
content
|
|
177
|
+
});
|
|
188
178
|
}
|
|
189
|
-
return
|
|
179
|
+
return outputs;
|
|
190
180
|
}
|
|
191
|
-
function
|
|
181
|
+
function generateCursorMarkdown(rule) {
|
|
192
182
|
const lines = [];
|
|
193
|
-
const priorityBadge = rule.frontmatter.priority === "high" ? "\u{1F534} HIGH" : "\u{1F7E1} STANDARD";
|
|
194
183
|
lines.push("---");
|
|
195
184
|
lines.push(`description: ${rule.frontmatter.description}`);
|
|
196
185
|
if (rule.frontmatter.globs.length > 0) {
|
|
197
186
|
lines.push(`globs: [${rule.frontmatter.globs.map((g) => `"${g}"`).join(", ")}]`);
|
|
198
187
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (rule.frontmatter.globs.length > 0) {
|
|
207
|
-
lines.push("**File Patterns:**");
|
|
208
|
-
for (const glob of rule.frontmatter.globs) {
|
|
209
|
-
lines.push(`- \`${glob}\``);
|
|
210
|
-
}
|
|
211
|
-
lines.push("");
|
|
188
|
+
let ruletype;
|
|
189
|
+
if (rule.frontmatter.ruleLevel === "overview") {
|
|
190
|
+
ruletype = "always";
|
|
191
|
+
} else if (rule.frontmatter.ruleLevel === "detail" && rule.frontmatter.globs.length === 0) {
|
|
192
|
+
ruletype = "agentrequested";
|
|
193
|
+
} else {
|
|
194
|
+
ruletype = "autoattached";
|
|
212
195
|
}
|
|
213
|
-
lines.push(
|
|
214
|
-
lines.push(rule.content);
|
|
215
|
-
lines.push("");
|
|
196
|
+
lines.push(`ruletype: ${ruletype}`);
|
|
216
197
|
lines.push("---");
|
|
217
198
|
lines.push("");
|
|
218
|
-
|
|
199
|
+
lines.push(rule.content);
|
|
200
|
+
return lines.join("\n");
|
|
219
201
|
}
|
|
220
202
|
|
|
221
203
|
// src/utils/config.ts
|
|
@@ -225,10 +207,11 @@ function getDefaultConfig() {
|
|
|
225
207
|
outputPaths: {
|
|
226
208
|
copilot: ".github/instructions",
|
|
227
209
|
cursor: ".cursor/rules",
|
|
228
|
-
cline: ".clinerules"
|
|
210
|
+
cline: ".clinerules",
|
|
211
|
+
claude: "."
|
|
229
212
|
},
|
|
230
213
|
watchEnabled: false,
|
|
231
|
-
defaultTargets: ["copilot", "cursor", "cline"]
|
|
214
|
+
defaultTargets: ["copilot", "cursor", "cline", "claude"]
|
|
232
215
|
};
|
|
233
216
|
}
|
|
234
217
|
function resolveTargets(targets, config) {
|
|
@@ -240,7 +223,7 @@ function resolveTargets(targets, config) {
|
|
|
240
223
|
|
|
241
224
|
// src/utils/file.ts
|
|
242
225
|
var import_promises = require("fs/promises");
|
|
243
|
-
var
|
|
226
|
+
var import_node_path5 = require("path");
|
|
244
227
|
async function ensureDir(dirPath) {
|
|
245
228
|
try {
|
|
246
229
|
await (0, import_promises.stat)(dirPath);
|
|
@@ -252,13 +235,13 @@ async function readFileContent(filepath) {
|
|
|
252
235
|
return (0, import_promises.readFile)(filepath, "utf-8");
|
|
253
236
|
}
|
|
254
237
|
async function writeFileContent(filepath, content) {
|
|
255
|
-
await ensureDir((0,
|
|
238
|
+
await ensureDir((0, import_node_path5.dirname)(filepath));
|
|
256
239
|
await (0, import_promises.writeFile)(filepath, content, "utf-8");
|
|
257
240
|
}
|
|
258
241
|
async function findFiles(dir, extension = ".md") {
|
|
259
242
|
try {
|
|
260
243
|
const files = await (0, import_promises.readdir)(dir);
|
|
261
|
-
return files.filter((file) => file.endsWith(extension)).map((file) => (0,
|
|
244
|
+
return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path5.join)(dir, file));
|
|
262
245
|
} catch {
|
|
263
246
|
return [];
|
|
264
247
|
}
|
|
@@ -271,6 +254,15 @@ async function fileExists(filepath) {
|
|
|
271
254
|
return false;
|
|
272
255
|
}
|
|
273
256
|
}
|
|
257
|
+
async function removeDirectory(dirPath) {
|
|
258
|
+
try {
|
|
259
|
+
if (await fileExists(dirPath)) {
|
|
260
|
+
await (0, import_promises.rm)(dirPath, { recursive: true, force: true });
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
274
266
|
|
|
275
267
|
// src/core/generator.ts
|
|
276
268
|
async function generateConfigurations(rules, config, targetTools) {
|
|
@@ -282,9 +274,9 @@ async function generateConfigurations(rules, config, targetTools) {
|
|
|
282
274
|
console.warn(`No rules found for tool: ${tool}`);
|
|
283
275
|
continue;
|
|
284
276
|
}
|
|
285
|
-
const
|
|
286
|
-
if (
|
|
287
|
-
outputs.push(
|
|
277
|
+
const toolOutputs = await generateForTool(tool, relevantRules, config);
|
|
278
|
+
if (toolOutputs) {
|
|
279
|
+
outputs.push(...toolOutputs);
|
|
288
280
|
}
|
|
289
281
|
}
|
|
290
282
|
return outputs;
|
|
@@ -303,6 +295,8 @@ async function generateForTool(tool, rules, config) {
|
|
|
303
295
|
return generateCursorConfig(rules, config);
|
|
304
296
|
case "cline":
|
|
305
297
|
return generateClineConfig(rules, config);
|
|
298
|
+
case "claude":
|
|
299
|
+
return await generateClaudeConfig(rules, config);
|
|
306
300
|
default:
|
|
307
301
|
console.warn(`Unknown tool: ${tool}`);
|
|
308
302
|
return null;
|
|
@@ -310,7 +304,7 @@ async function generateForTool(tool, rules, config) {
|
|
|
310
304
|
}
|
|
311
305
|
|
|
312
306
|
// src/core/parser.ts
|
|
313
|
-
var
|
|
307
|
+
var import_node_path6 = require("path");
|
|
314
308
|
var import_gray_matter = __toESM(require("gray-matter"));
|
|
315
309
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
316
310
|
const ruleFiles = await findFiles(aiRulesDir);
|
|
@@ -330,7 +324,7 @@ async function parseRuleFile(filepath) {
|
|
|
330
324
|
const parsed = (0, import_gray_matter.default)(content);
|
|
331
325
|
validateFrontmatter(parsed.data, filepath);
|
|
332
326
|
const frontmatter = parsed.data;
|
|
333
|
-
const filename = (0,
|
|
327
|
+
const filename = (0, import_node_path6.basename)(filepath, ".md");
|
|
334
328
|
return {
|
|
335
329
|
frontmatter,
|
|
336
330
|
content: parsed.content,
|
|
@@ -343,8 +337,8 @@ function validateFrontmatter(data, filepath) {
|
|
|
343
337
|
throw new Error(`Invalid frontmatter in ${filepath}: must be an object`);
|
|
344
338
|
}
|
|
345
339
|
const obj = data;
|
|
346
|
-
if (!obj.
|
|
347
|
-
throw new Error(`Invalid
|
|
340
|
+
if (!obj.ruleLevel || !["overview", "detail"].includes(obj.ruleLevel)) {
|
|
341
|
+
throw new Error(`Invalid ruleLevel in ${filepath}: must be "overview" or "detail"`);
|
|
348
342
|
}
|
|
349
343
|
if (!Array.isArray(obj.targets)) {
|
|
350
344
|
throw new Error(`Invalid targets in ${filepath}: must be an array`);
|
|
@@ -381,6 +375,10 @@ async function validateRules(rules) {
|
|
|
381
375
|
}
|
|
382
376
|
filenames.add(rule.filename);
|
|
383
377
|
}
|
|
378
|
+
const overviewRules = rules.filter((rule) => rule.frontmatter.ruleLevel === "overview");
|
|
379
|
+
if (overviewRules.length > 1) {
|
|
380
|
+
errors.push(`Multiple overview rules found: ${overviewRules.map((r) => r.filename).join(", ")}. Only one overview rule is allowed.`);
|
|
381
|
+
}
|
|
384
382
|
for (const rule of rules) {
|
|
385
383
|
const ruleValidation = await validateRule(rule);
|
|
386
384
|
errors.push(...ruleValidation.errors);
|
|
@@ -434,6 +432,33 @@ async function generateCommand(options = {}) {
|
|
|
434
432
|
if (options.verbose) {
|
|
435
433
|
console.log(`Found ${rules.length} rule(s)`);
|
|
436
434
|
}
|
|
435
|
+
if (options.delete) {
|
|
436
|
+
if (options.verbose) {
|
|
437
|
+
console.log("Deleting existing output directories...");
|
|
438
|
+
}
|
|
439
|
+
const targetTools = options.tools || config.defaultTargets;
|
|
440
|
+
const deleteTasks = [];
|
|
441
|
+
for (const tool of targetTools) {
|
|
442
|
+
switch (tool) {
|
|
443
|
+
case "copilot":
|
|
444
|
+
deleteTasks.push(removeDirectory(config.outputPaths.copilot));
|
|
445
|
+
break;
|
|
446
|
+
case "cursor":
|
|
447
|
+
deleteTasks.push(removeDirectory(config.outputPaths.cursor));
|
|
448
|
+
break;
|
|
449
|
+
case "cline":
|
|
450
|
+
deleteTasks.push(removeDirectory(config.outputPaths.cline));
|
|
451
|
+
break;
|
|
452
|
+
case "claude":
|
|
453
|
+
deleteTasks.push(removeDirectory(config.outputPaths.claude));
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
await Promise.all(deleteTasks);
|
|
458
|
+
if (options.verbose) {
|
|
459
|
+
console.log("Deleted existing output directories");
|
|
460
|
+
}
|
|
461
|
+
}
|
|
437
462
|
const outputs = await generateConfigurations(rules, config, options.tools);
|
|
438
463
|
if (outputs.length === 0) {
|
|
439
464
|
console.warn("\u26A0\uFE0F No configurations generated");
|
|
@@ -451,17 +476,57 @@ async function generateCommand(options = {}) {
|
|
|
451
476
|
}
|
|
452
477
|
}
|
|
453
478
|
|
|
479
|
+
// src/cli/commands/gitignore.ts
|
|
480
|
+
var import_node_fs = require("fs");
|
|
481
|
+
var import_node_path7 = require("path");
|
|
482
|
+
var gitignoreCommand = async () => {
|
|
483
|
+
const gitignorePath = (0, import_node_path7.join)(process.cwd(), ".gitignore");
|
|
484
|
+
const rulesFilesToIgnore = [
|
|
485
|
+
"# Generated by rulesync - AI tool configuration files",
|
|
486
|
+
".github/instructions/",
|
|
487
|
+
".cursor/rules/",
|
|
488
|
+
".clinerules/",
|
|
489
|
+
"CLAUDE.md"
|
|
490
|
+
];
|
|
491
|
+
let gitignoreContent = "";
|
|
492
|
+
if ((0, import_node_fs.existsSync)(gitignorePath)) {
|
|
493
|
+
gitignoreContent = (0, import_node_fs.readFileSync)(gitignorePath, "utf-8");
|
|
494
|
+
}
|
|
495
|
+
const linesToAdd = [];
|
|
496
|
+
for (const rule of rulesFilesToIgnore) {
|
|
497
|
+
if (!gitignoreContent.includes(rule)) {
|
|
498
|
+
linesToAdd.push(rule);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (linesToAdd.length === 0) {
|
|
502
|
+
console.log("\u2705 .gitignore\u306F\u65E2\u306B\u6700\u65B0\u3067\u3059");
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
const newContent = gitignoreContent ? `${gitignoreContent.trimEnd()}
|
|
506
|
+
|
|
507
|
+
${linesToAdd.join("\n")}
|
|
508
|
+
` : `${linesToAdd.join("\n")}
|
|
509
|
+
`;
|
|
510
|
+
(0, import_node_fs.writeFileSync)(gitignorePath, newContent);
|
|
511
|
+
console.log(`\u2705 .gitignore\u306B${linesToAdd.length}\u500B\u306E\u30EB\u30FC\u30EB\u3092\u8FFD\u52A0\u3057\u307E\u3057\u305F:`);
|
|
512
|
+
for (const line of linesToAdd) {
|
|
513
|
+
if (!line.startsWith("#")) {
|
|
514
|
+
console.log(` ${line}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
454
519
|
// src/cli/commands/init.ts
|
|
455
|
-
var
|
|
520
|
+
var import_node_path8 = require("path");
|
|
456
521
|
async function initCommand() {
|
|
457
522
|
const aiRulesDir = ".rulesync";
|
|
458
|
-
console.log("Initializing
|
|
523
|
+
console.log("Initializing rulesync...");
|
|
459
524
|
await ensureDir(aiRulesDir);
|
|
460
525
|
await createSampleFiles(aiRulesDir);
|
|
461
|
-
console.log("\u2705
|
|
526
|
+
console.log("\u2705 rulesync initialized successfully!");
|
|
462
527
|
console.log("\nNext steps:");
|
|
463
528
|
console.log("1. Edit rule files in .rulesync/");
|
|
464
|
-
console.log("2. Run '
|
|
529
|
+
console.log("2. Run 'rulesync generate' to create configuration files");
|
|
465
530
|
}
|
|
466
531
|
async function createSampleFiles(aiRulesDir) {
|
|
467
532
|
const sampleFiles = [
|
|
@@ -542,7 +607,7 @@ globs: ["src/**/*.ts"]
|
|
|
542
607
|
}
|
|
543
608
|
];
|
|
544
609
|
for (const file of sampleFiles) {
|
|
545
|
-
const filepath = (0,
|
|
610
|
+
const filepath = (0, import_node_path8.join)(aiRulesDir, file.filename);
|
|
546
611
|
if (!await fileExists(filepath)) {
|
|
547
612
|
await writeFileContent(filepath, file.content);
|
|
548
613
|
console.log(`Created ${filepath}`);
|
|
@@ -557,10 +622,10 @@ async function statusCommand() {
|
|
|
557
622
|
const config = getDefaultConfig();
|
|
558
623
|
console.log("rulesync Status");
|
|
559
624
|
console.log("===============");
|
|
560
|
-
const
|
|
625
|
+
const rulesyncExists = await fileExists(config.aiRulesDir);
|
|
561
626
|
console.log(`
|
|
562
|
-
\u{1F4C1} .rulesync directory: ${
|
|
563
|
-
if (!
|
|
627
|
+
\u{1F4C1} .rulesync directory: ${rulesyncExists ? "\u2705 Found" : "\u274C Not found"}`);
|
|
628
|
+
if (!rulesyncExists) {
|
|
564
629
|
console.log("\n\u{1F4A1} Run 'rulesync init' to get started");
|
|
565
630
|
return;
|
|
566
631
|
}
|
|
@@ -603,7 +668,7 @@ async function statusCommand() {
|
|
|
603
668
|
// src/cli/commands/validate.ts
|
|
604
669
|
async function validateCommand() {
|
|
605
670
|
const config = getDefaultConfig();
|
|
606
|
-
console.log("Validating
|
|
671
|
+
console.log("Validating rulesync configuration...");
|
|
607
672
|
if (!await fileExists(config.aiRulesDir)) {
|
|
608
673
|
console.error("\u274C .rulesync directory not found. Run 'rulesync init' first.");
|
|
609
674
|
process.exit(1);
|
|
@@ -611,7 +676,7 @@ async function validateCommand() {
|
|
|
611
676
|
try {
|
|
612
677
|
const rules = await parseRulesFromDirectory(config.aiRulesDir);
|
|
613
678
|
if (rules.length === 0) {
|
|
614
|
-
console.warn("\u26A0\uFE0F No rules found in .
|
|
679
|
+
console.warn("\u26A0\uFE0F No rules found in .rulesync directory");
|
|
615
680
|
return;
|
|
616
681
|
}
|
|
617
682
|
console.log(`Found ${rules.length} rule(s), validating...`);
|
|
@@ -683,22 +748,25 @@ async function watchCommand() {
|
|
|
683
748
|
|
|
684
749
|
// src/cli/index.ts
|
|
685
750
|
var program = new import_commander.Command();
|
|
686
|
-
program.name("
|
|
687
|
-
program.command("init").description("Initialize
|
|
688
|
-
program.command("
|
|
751
|
+
program.name("rulesync").description("Unified AI rules management CLI tool").version("0.1.0");
|
|
752
|
+
program.command("init").description("Initialize rulesync in current directory").action(initCommand);
|
|
753
|
+
program.command("gitignore").description("Add generated files to .gitignore").action(gitignoreCommand);
|
|
754
|
+
program.command("generate").description("Generate configuration files for AI tools").option("--copilot", "Generate only for GitHub Copilot").option("--cursor", "Generate only for Cursor").option("--cline", "Generate only for Cline").option("--claude", "Generate only for Claude Code").option("--delete", "Delete all existing files in output directories before generating").option("-v, --verbose", "Verbose output").action(async (options) => {
|
|
689
755
|
const tools = [];
|
|
690
756
|
if (options.copilot) tools.push("copilot");
|
|
691
757
|
if (options.cursor) tools.push("cursor");
|
|
692
758
|
if (options.cline) tools.push("cline");
|
|
759
|
+
if (options.claude) tools.push("claude");
|
|
693
760
|
const generateOptions = {
|
|
694
|
-
verbose: options.verbose
|
|
761
|
+
verbose: options.verbose,
|
|
762
|
+
delete: options.delete
|
|
695
763
|
};
|
|
696
764
|
if (tools.length > 0) {
|
|
697
765
|
generateOptions.tools = tools;
|
|
698
766
|
}
|
|
699
767
|
await generateCommand(generateOptions);
|
|
700
768
|
});
|
|
701
|
-
program.command("validate").description("Validate
|
|
702
|
-
program.command("status").description("Show current status of
|
|
769
|
+
program.command("validate").description("Validate rulesync configuration").action(validateCommand);
|
|
770
|
+
program.command("status").description("Show current status of rulesync").action(statusCommand);
|
|
703
771
|
program.command("watch").description("Watch for changes and auto-generate configurations").action(watchCommand);
|
|
704
772
|
program.parse();
|