rulesync 0.5.0 → 0.9.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 +7 -3
- package/dist/index.js +71 -19
- package/dist/index.mjs +68 -16
- package/package.json +71 -70
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ A Node.js CLI tool that automatically generates configuration files for various
|
|
|
11
11
|
- **Cursor Project Rules** (`.cursor/rules/*.mdc`)
|
|
12
12
|
- **Cline Rules** (`.clinerules/*.md`)
|
|
13
13
|
- **Claude Code Memory** (`./CLAUDE.md` + `.claude/memories/*.md`)
|
|
14
|
+
- **Roo Code Rules** (`.roo/rules/*.md`)
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -165,7 +166,7 @@ Define metadata in front matter for each Markdown file:
|
|
|
165
166
|
```markdown
|
|
166
167
|
---
|
|
167
168
|
root: true # or false
|
|
168
|
-
targets: ["*"] # or [copilot, cursor, cline,
|
|
169
|
+
targets: ["*"] # or [copilot, cursor, cline, claude, roo]
|
|
169
170
|
description: "TypeScript coding rules"
|
|
170
171
|
globs: ["**/*.ts", "**/*.tsx"]
|
|
171
172
|
---
|
|
@@ -197,6 +198,7 @@ Each AI tool handles rule levels differently:
|
|
|
197
198
|
| **Cursor** | `ruletype: always` | `ruletype: autoattached` | Detail rules without globs use `ruletype: agentrequested` |
|
|
198
199
|
| **GitHub Copilot** | Standard format | Standard format | All rules use same format with frontmatter |
|
|
199
200
|
| **Cline** | Standard format | Standard format | All rules use plain Markdown format |
|
|
201
|
+
| **Roo Code** | Standard format | Standard format | All rules use plain Markdown format with description header |
|
|
200
202
|
|
|
201
203
|
### 3. Generate Configuration Files
|
|
202
204
|
|
|
@@ -209,6 +211,7 @@ rulesync generate --copilot
|
|
|
209
211
|
rulesync generate --cursor
|
|
210
212
|
rulesync generate --cline
|
|
211
213
|
rulesync generate --claude
|
|
214
|
+
rulesync generate --roo
|
|
212
215
|
|
|
213
216
|
# Clean build (delete existing files first)
|
|
214
217
|
rulesync generate --delete
|
|
@@ -225,7 +228,7 @@ rulesync generate --delete --verbose
|
|
|
225
228
|
|
|
226
229
|
- `--delete`: Remove all existing generated files before creating new ones
|
|
227
230
|
- `--verbose`: Show detailed output during generation process
|
|
228
|
-
- `--copilot`, `--cursor`, `--cline`, `--claude`: Generate only for specified tools
|
|
231
|
+
- `--copilot`, `--cursor`, `--cline`, `--claude`, `--roo`: Generate only for specified tools
|
|
229
232
|
|
|
230
233
|
### 4. Other Commands
|
|
231
234
|
|
|
@@ -291,7 +294,7 @@ This project follows TypeScript-first development with clean architecture princi
|
|
|
291
294
|
```markdown
|
|
292
295
|
---
|
|
293
296
|
root: false
|
|
294
|
-
targets: ["copilot", "cursor"]
|
|
297
|
+
targets: ["copilot", "cursor", "roo"]
|
|
295
298
|
description: "TypeScript coding standards"
|
|
296
299
|
globs: ["**/*.ts", "**/*.tsx"]
|
|
297
300
|
---
|
|
@@ -311,6 +314,7 @@ globs: ["**/*.ts", "**/*.tsx"]
|
|
|
311
314
|
| **Cursor** | `.cursor/rules/*.mdc` | MDC (YAML header + Markdown) | Root: `ruletype: always`<br>Non-root: `ruletype: autoattached`<br>Non-root without globs: `ruletype: agentrequested` |
|
|
312
315
|
| **Cline** | `.clinerules/*.md` | Plain Markdown | Both levels use same format |
|
|
313
316
|
| **Claude Code** | `./CLAUDE.md` (root)<br>`.claude/memories/*.md` (non-root) | Plain Markdown | Root goes to CLAUDE.md<br>Non-root go to separate memory files<br>CLAUDE.md includes `@filename` references |
|
|
317
|
+
| **Roo Code** | `.roo/rules/*.md` | Plain Markdown | Both levels use same format with description header |
|
|
314
318
|
|
|
315
319
|
## Validation
|
|
316
320
|
|
package/dist/index.js
CHANGED
|
@@ -51,8 +51,10 @@ async function generateClaudeConfig(rules, config) {
|
|
|
51
51
|
function generateClaudeMarkdown(rootRules, detailRules) {
|
|
52
52
|
const lines = [];
|
|
53
53
|
if (detailRules.length > 0) {
|
|
54
|
+
lines.push("Please also reference the following documents as needed:");
|
|
55
|
+
lines.push("");
|
|
54
56
|
for (const rule of detailRules) {
|
|
55
|
-
lines.push(
|
|
57
|
+
lines.push(`@.claude/memories/${rule.filename}.md`);
|
|
56
58
|
}
|
|
57
59
|
lines.push("");
|
|
58
60
|
}
|
|
@@ -87,10 +89,6 @@ function formatRuleForClaude(rule) {
|
|
|
87
89
|
}
|
|
88
90
|
function generateMemoryFile(rule) {
|
|
89
91
|
const lines = [];
|
|
90
|
-
lines.push("Please also refer to the following files as needed:");
|
|
91
|
-
lines.push("");
|
|
92
|
-
lines.push("---");
|
|
93
|
-
lines.push("");
|
|
94
92
|
lines.push(`# ${rule.filename}`);
|
|
95
93
|
lines.push("");
|
|
96
94
|
if (rule.frontmatter.description) {
|
|
@@ -158,7 +156,6 @@ function generateCopilotMarkdown(rule) {
|
|
|
158
156
|
lines.push('applyTo: "**"');
|
|
159
157
|
}
|
|
160
158
|
lines.push("---");
|
|
161
|
-
lines.push("");
|
|
162
159
|
lines.push(rule.content);
|
|
163
160
|
return lines.join("\n");
|
|
164
161
|
}
|
|
@@ -195,6 +192,28 @@ function generateCursorMarkdown(rule) {
|
|
|
195
192
|
}
|
|
196
193
|
lines.push(`ruletype: ${ruletype}`);
|
|
197
194
|
lines.push("---");
|
|
195
|
+
lines.push(rule.content);
|
|
196
|
+
return lines.join("\n");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/generators/roo.ts
|
|
200
|
+
var import_node_path5 = require("path");
|
|
201
|
+
async function generateRooConfig(rules, config) {
|
|
202
|
+
const outputs = [];
|
|
203
|
+
for (const rule of rules) {
|
|
204
|
+
const content = generateRooMarkdown(rule);
|
|
205
|
+
const filepath = (0, import_node_path5.join)(config.outputPaths.roo, `${rule.filename}.md`);
|
|
206
|
+
outputs.push({
|
|
207
|
+
tool: "roo",
|
|
208
|
+
filepath,
|
|
209
|
+
content
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return outputs;
|
|
213
|
+
}
|
|
214
|
+
function generateRooMarkdown(rule) {
|
|
215
|
+
const lines = [];
|
|
216
|
+
lines.push(`# ${rule.frontmatter.description}`);
|
|
198
217
|
lines.push("");
|
|
199
218
|
lines.push(rule.content);
|
|
200
219
|
return lines.join("\n");
|
|
@@ -208,10 +227,11 @@ function getDefaultConfig() {
|
|
|
208
227
|
copilot: ".github/instructions",
|
|
209
228
|
cursor: ".cursor/rules",
|
|
210
229
|
cline: ".clinerules",
|
|
211
|
-
claude: "."
|
|
230
|
+
claude: ".",
|
|
231
|
+
roo: ".roo/rules"
|
|
212
232
|
},
|
|
213
233
|
watchEnabled: false,
|
|
214
|
-
defaultTargets: ["copilot", "cursor", "cline", "claude"]
|
|
234
|
+
defaultTargets: ["copilot", "cursor", "cline", "claude", "roo"]
|
|
215
235
|
};
|
|
216
236
|
}
|
|
217
237
|
function resolveTargets(targets, config) {
|
|
@@ -223,7 +243,7 @@ function resolveTargets(targets, config) {
|
|
|
223
243
|
|
|
224
244
|
// src/utils/file.ts
|
|
225
245
|
var import_promises = require("fs/promises");
|
|
226
|
-
var
|
|
246
|
+
var import_node_path6 = require("path");
|
|
227
247
|
async function ensureDir(dirPath) {
|
|
228
248
|
try {
|
|
229
249
|
await (0, import_promises.stat)(dirPath);
|
|
@@ -235,13 +255,13 @@ async function readFileContent(filepath) {
|
|
|
235
255
|
return (0, import_promises.readFile)(filepath, "utf-8");
|
|
236
256
|
}
|
|
237
257
|
async function writeFileContent(filepath, content) {
|
|
238
|
-
await ensureDir((0,
|
|
258
|
+
await ensureDir((0, import_node_path6.dirname)(filepath));
|
|
239
259
|
await (0, import_promises.writeFile)(filepath, content, "utf-8");
|
|
240
260
|
}
|
|
241
261
|
async function findFiles(dir, extension = ".md") {
|
|
242
262
|
try {
|
|
243
263
|
const files = await (0, import_promises.readdir)(dir);
|
|
244
|
-
return files.filter((file) => file.endsWith(extension)).map((file) => (0,
|
|
264
|
+
return files.filter((file) => file.endsWith(extension)).map((file) => (0, import_node_path6.join)(dir, file));
|
|
245
265
|
} catch {
|
|
246
266
|
return [];
|
|
247
267
|
}
|
|
@@ -255,6 +275,11 @@ async function fileExists(filepath) {
|
|
|
255
275
|
}
|
|
256
276
|
}
|
|
257
277
|
async function removeDirectory(dirPath) {
|
|
278
|
+
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
279
|
+
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
280
|
+
console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
258
283
|
try {
|
|
259
284
|
if (await fileExists(dirPath)) {
|
|
260
285
|
await (0, import_promises.rm)(dirPath, { recursive: true, force: true });
|
|
@@ -263,6 +288,25 @@ async function removeDirectory(dirPath) {
|
|
|
263
288
|
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
264
289
|
}
|
|
265
290
|
}
|
|
291
|
+
async function removeFile(filepath) {
|
|
292
|
+
try {
|
|
293
|
+
if (await fileExists(filepath)) {
|
|
294
|
+
await (0, import_promises.rm)(filepath);
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function removeClaudeGeneratedFiles() {
|
|
301
|
+
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
302
|
+
for (const fileOrDir of filesToRemove) {
|
|
303
|
+
if (fileOrDir.endsWith("/memories")) {
|
|
304
|
+
await removeDirectory(fileOrDir);
|
|
305
|
+
} else {
|
|
306
|
+
await removeFile(fileOrDir);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
266
310
|
|
|
267
311
|
// src/core/generator.ts
|
|
268
312
|
async function generateConfigurations(rules, config, targetTools) {
|
|
@@ -297,6 +341,8 @@ async function generateForTool(tool, rules, config) {
|
|
|
297
341
|
return generateClineConfig(rules, config);
|
|
298
342
|
case "claude":
|
|
299
343
|
return await generateClaudeConfig(rules, config);
|
|
344
|
+
case "roo":
|
|
345
|
+
return generateRooConfig(rules, config);
|
|
300
346
|
default:
|
|
301
347
|
console.warn(`Unknown tool: ${tool}`);
|
|
302
348
|
return null;
|
|
@@ -304,7 +350,7 @@ async function generateForTool(tool, rules, config) {
|
|
|
304
350
|
}
|
|
305
351
|
|
|
306
352
|
// src/core/parser.ts
|
|
307
|
-
var
|
|
353
|
+
var import_node_path7 = require("path");
|
|
308
354
|
var import_gray_matter = __toESM(require("gray-matter"));
|
|
309
355
|
async function parseRulesFromDirectory(aiRulesDir) {
|
|
310
356
|
const ruleFiles = await findFiles(aiRulesDir);
|
|
@@ -324,7 +370,7 @@ async function parseRuleFile(filepath) {
|
|
|
324
370
|
const parsed = (0, import_gray_matter.default)(content);
|
|
325
371
|
validateFrontmatter(parsed.data, filepath);
|
|
326
372
|
const frontmatter = parsed.data;
|
|
327
|
-
const filename = (0,
|
|
373
|
+
const filename = (0, import_node_path7.basename)(filepath, ".md");
|
|
328
374
|
return {
|
|
329
375
|
frontmatter,
|
|
330
376
|
content: parsed.content,
|
|
@@ -452,7 +498,10 @@ async function generateCommand(options = {}) {
|
|
|
452
498
|
deleteTasks.push(removeDirectory(config.outputPaths.cline));
|
|
453
499
|
break;
|
|
454
500
|
case "claude":
|
|
455
|
-
deleteTasks.push(
|
|
501
|
+
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
502
|
+
break;
|
|
503
|
+
case "roo":
|
|
504
|
+
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
456
505
|
break;
|
|
457
506
|
}
|
|
458
507
|
}
|
|
@@ -480,15 +529,18 @@ async function generateCommand(options = {}) {
|
|
|
480
529
|
|
|
481
530
|
// src/cli/commands/gitignore.ts
|
|
482
531
|
var import_node_fs = require("fs");
|
|
483
|
-
var
|
|
532
|
+
var import_node_path8 = require("path");
|
|
484
533
|
var gitignoreCommand = async () => {
|
|
485
|
-
const gitignorePath = (0,
|
|
534
|
+
const gitignorePath = (0, import_node_path8.join)(process.cwd(), ".gitignore");
|
|
486
535
|
const rulesFilesToIgnore = [
|
|
487
536
|
"# Generated by rulesync - AI tool configuration files",
|
|
537
|
+
".github/copilot-instructions.md",
|
|
488
538
|
".github/instructions/",
|
|
489
539
|
".cursor/rules/",
|
|
490
540
|
".clinerules/",
|
|
491
|
-
"CLAUDE.md"
|
|
541
|
+
"CLAUDE.md",
|
|
542
|
+
".claude/memories/",
|
|
543
|
+
".roo/rules/"
|
|
492
544
|
];
|
|
493
545
|
let gitignoreContent = "";
|
|
494
546
|
if ((0, import_node_fs.existsSync)(gitignorePath)) {
|
|
@@ -519,7 +571,7 @@ ${linesToAdd.join("\n")}
|
|
|
519
571
|
};
|
|
520
572
|
|
|
521
573
|
// src/cli/commands/init.ts
|
|
522
|
-
var
|
|
574
|
+
var import_node_path9 = require("path");
|
|
523
575
|
async function initCommand() {
|
|
524
576
|
const aiRulesDir = ".rulesync";
|
|
525
577
|
console.log("Initializing rulesync...");
|
|
@@ -609,7 +661,7 @@ globs: ["src/**/*.ts"]
|
|
|
609
661
|
}
|
|
610
662
|
];
|
|
611
663
|
for (const file of sampleFiles) {
|
|
612
|
-
const filepath = (0,
|
|
664
|
+
const filepath = (0, import_node_path9.join)(aiRulesDir, file.filename);
|
|
613
665
|
if (!await fileExists(filepath)) {
|
|
614
666
|
await writeFileContent(filepath, file.content);
|
|
615
667
|
console.log(`Created ${filepath}`);
|
package/dist/index.mjs
CHANGED
|
@@ -28,8 +28,10 @@ async function generateClaudeConfig(rules, config) {
|
|
|
28
28
|
function generateClaudeMarkdown(rootRules, detailRules) {
|
|
29
29
|
const lines = [];
|
|
30
30
|
if (detailRules.length > 0) {
|
|
31
|
+
lines.push("Please also reference the following documents as needed:");
|
|
32
|
+
lines.push("");
|
|
31
33
|
for (const rule of detailRules) {
|
|
32
|
-
lines.push(
|
|
34
|
+
lines.push(`@.claude/memories/${rule.filename}.md`);
|
|
33
35
|
}
|
|
34
36
|
lines.push("");
|
|
35
37
|
}
|
|
@@ -64,10 +66,6 @@ function formatRuleForClaude(rule) {
|
|
|
64
66
|
}
|
|
65
67
|
function generateMemoryFile(rule) {
|
|
66
68
|
const lines = [];
|
|
67
|
-
lines.push("Please also refer to the following files as needed:");
|
|
68
|
-
lines.push("");
|
|
69
|
-
lines.push("---");
|
|
70
|
-
lines.push("");
|
|
71
69
|
lines.push(`# ${rule.filename}`);
|
|
72
70
|
lines.push("");
|
|
73
71
|
if (rule.frontmatter.description) {
|
|
@@ -135,7 +133,6 @@ function generateCopilotMarkdown(rule) {
|
|
|
135
133
|
lines.push('applyTo: "**"');
|
|
136
134
|
}
|
|
137
135
|
lines.push("---");
|
|
138
|
-
lines.push("");
|
|
139
136
|
lines.push(rule.content);
|
|
140
137
|
return lines.join("\n");
|
|
141
138
|
}
|
|
@@ -172,6 +169,28 @@ function generateCursorMarkdown(rule) {
|
|
|
172
169
|
}
|
|
173
170
|
lines.push(`ruletype: ${ruletype}`);
|
|
174
171
|
lines.push("---");
|
|
172
|
+
lines.push(rule.content);
|
|
173
|
+
return lines.join("\n");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/generators/roo.ts
|
|
177
|
+
import { join as join5 } from "path";
|
|
178
|
+
async function generateRooConfig(rules, config) {
|
|
179
|
+
const outputs = [];
|
|
180
|
+
for (const rule of rules) {
|
|
181
|
+
const content = generateRooMarkdown(rule);
|
|
182
|
+
const filepath = join5(config.outputPaths.roo, `${rule.filename}.md`);
|
|
183
|
+
outputs.push({
|
|
184
|
+
tool: "roo",
|
|
185
|
+
filepath,
|
|
186
|
+
content
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return outputs;
|
|
190
|
+
}
|
|
191
|
+
function generateRooMarkdown(rule) {
|
|
192
|
+
const lines = [];
|
|
193
|
+
lines.push(`# ${rule.frontmatter.description}`);
|
|
175
194
|
lines.push("");
|
|
176
195
|
lines.push(rule.content);
|
|
177
196
|
return lines.join("\n");
|
|
@@ -185,10 +204,11 @@ function getDefaultConfig() {
|
|
|
185
204
|
copilot: ".github/instructions",
|
|
186
205
|
cursor: ".cursor/rules",
|
|
187
206
|
cline: ".clinerules",
|
|
188
|
-
claude: "."
|
|
207
|
+
claude: ".",
|
|
208
|
+
roo: ".roo/rules"
|
|
189
209
|
},
|
|
190
210
|
watchEnabled: false,
|
|
191
|
-
defaultTargets: ["copilot", "cursor", "cline", "claude"]
|
|
211
|
+
defaultTargets: ["copilot", "cursor", "cline", "claude", "roo"]
|
|
192
212
|
};
|
|
193
213
|
}
|
|
194
214
|
function resolveTargets(targets, config) {
|
|
@@ -200,7 +220,7 @@ function resolveTargets(targets, config) {
|
|
|
200
220
|
|
|
201
221
|
// src/utils/file.ts
|
|
202
222
|
import { mkdir, readdir, readFile, rm, stat, writeFile } from "fs/promises";
|
|
203
|
-
import { dirname, join as
|
|
223
|
+
import { dirname, join as join6 } from "path";
|
|
204
224
|
async function ensureDir(dirPath) {
|
|
205
225
|
try {
|
|
206
226
|
await stat(dirPath);
|
|
@@ -218,7 +238,7 @@ async function writeFileContent(filepath, content) {
|
|
|
218
238
|
async function findFiles(dir, extension = ".md") {
|
|
219
239
|
try {
|
|
220
240
|
const files = await readdir(dir);
|
|
221
|
-
return files.filter((file) => file.endsWith(extension)).map((file) =>
|
|
241
|
+
return files.filter((file) => file.endsWith(extension)).map((file) => join6(dir, file));
|
|
222
242
|
} catch {
|
|
223
243
|
return [];
|
|
224
244
|
}
|
|
@@ -232,6 +252,11 @@ async function fileExists(filepath) {
|
|
|
232
252
|
}
|
|
233
253
|
}
|
|
234
254
|
async function removeDirectory(dirPath) {
|
|
255
|
+
const dangerousPaths = [".", "/", "~", "src", "node_modules"];
|
|
256
|
+
if (dangerousPaths.includes(dirPath) || dirPath === "") {
|
|
257
|
+
console.warn(`Skipping deletion of dangerous path: ${dirPath}`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
235
260
|
try {
|
|
236
261
|
if (await fileExists(dirPath)) {
|
|
237
262
|
await rm(dirPath, { recursive: true, force: true });
|
|
@@ -240,6 +265,25 @@ async function removeDirectory(dirPath) {
|
|
|
240
265
|
console.warn(`Failed to remove directory ${dirPath}:`, error);
|
|
241
266
|
}
|
|
242
267
|
}
|
|
268
|
+
async function removeFile(filepath) {
|
|
269
|
+
try {
|
|
270
|
+
if (await fileExists(filepath)) {
|
|
271
|
+
await rm(filepath);
|
|
272
|
+
}
|
|
273
|
+
} catch (error) {
|
|
274
|
+
console.warn(`Failed to remove file ${filepath}:`, error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
async function removeClaudeGeneratedFiles() {
|
|
278
|
+
const filesToRemove = ["CLAUDE.md", ".claude/memories"];
|
|
279
|
+
for (const fileOrDir of filesToRemove) {
|
|
280
|
+
if (fileOrDir.endsWith("/memories")) {
|
|
281
|
+
await removeDirectory(fileOrDir);
|
|
282
|
+
} else {
|
|
283
|
+
await removeFile(fileOrDir);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
243
287
|
|
|
244
288
|
// src/core/generator.ts
|
|
245
289
|
async function generateConfigurations(rules, config, targetTools) {
|
|
@@ -274,6 +318,8 @@ async function generateForTool(tool, rules, config) {
|
|
|
274
318
|
return generateClineConfig(rules, config);
|
|
275
319
|
case "claude":
|
|
276
320
|
return await generateClaudeConfig(rules, config);
|
|
321
|
+
case "roo":
|
|
322
|
+
return generateRooConfig(rules, config);
|
|
277
323
|
default:
|
|
278
324
|
console.warn(`Unknown tool: ${tool}`);
|
|
279
325
|
return null;
|
|
@@ -429,7 +475,10 @@ async function generateCommand(options = {}) {
|
|
|
429
475
|
deleteTasks.push(removeDirectory(config.outputPaths.cline));
|
|
430
476
|
break;
|
|
431
477
|
case "claude":
|
|
432
|
-
deleteTasks.push(
|
|
478
|
+
deleteTasks.push(removeClaudeGeneratedFiles());
|
|
479
|
+
break;
|
|
480
|
+
case "roo":
|
|
481
|
+
deleteTasks.push(removeDirectory(config.outputPaths.roo));
|
|
433
482
|
break;
|
|
434
483
|
}
|
|
435
484
|
}
|
|
@@ -457,15 +506,18 @@ async function generateCommand(options = {}) {
|
|
|
457
506
|
|
|
458
507
|
// src/cli/commands/gitignore.ts
|
|
459
508
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
460
|
-
import { join as
|
|
509
|
+
import { join as join7 } from "path";
|
|
461
510
|
var gitignoreCommand = async () => {
|
|
462
|
-
const gitignorePath =
|
|
511
|
+
const gitignorePath = join7(process.cwd(), ".gitignore");
|
|
463
512
|
const rulesFilesToIgnore = [
|
|
464
513
|
"# Generated by rulesync - AI tool configuration files",
|
|
514
|
+
".github/copilot-instructions.md",
|
|
465
515
|
".github/instructions/",
|
|
466
516
|
".cursor/rules/",
|
|
467
517
|
".clinerules/",
|
|
468
|
-
"CLAUDE.md"
|
|
518
|
+
"CLAUDE.md",
|
|
519
|
+
".claude/memories/",
|
|
520
|
+
".roo/rules/"
|
|
469
521
|
];
|
|
470
522
|
let gitignoreContent = "";
|
|
471
523
|
if (existsSync(gitignorePath)) {
|
|
@@ -496,7 +548,7 @@ ${linesToAdd.join("\n")}
|
|
|
496
548
|
};
|
|
497
549
|
|
|
498
550
|
// src/cli/commands/init.ts
|
|
499
|
-
import { join as
|
|
551
|
+
import { join as join8 } from "path";
|
|
500
552
|
async function initCommand() {
|
|
501
553
|
const aiRulesDir = ".rulesync";
|
|
502
554
|
console.log("Initializing rulesync...");
|
|
@@ -586,7 +638,7 @@ globs: ["src/**/*.ts"]
|
|
|
586
638
|
}
|
|
587
639
|
];
|
|
588
640
|
for (const file of sampleFiles) {
|
|
589
|
-
const filepath =
|
|
641
|
+
const filepath = join8(aiRulesDir, file.filename);
|
|
590
642
|
if (!await fileExists(filepath)) {
|
|
591
643
|
await writeFileContent(filepath, file.content);
|
|
592
644
|
console.log(`Created ${filepath}`);
|
package/package.json
CHANGED
|
@@ -1,71 +1,72 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
2
|
+
"name": "rulesync",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"rulesync": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "tsx src/cli/index.ts",
|
|
16
|
+
"build": "tsup src/cli/index.ts --format cjs,esm --dts --clean",
|
|
17
|
+
"lint": "biome lint src/",
|
|
18
|
+
"format": "biome format --write src/",
|
|
19
|
+
"format:check": "biome format src/",
|
|
20
|
+
"check": "biome check src/",
|
|
21
|
+
"secretlint": "secretlint \"**/*\"",
|
|
22
|
+
"test": "vitest",
|
|
23
|
+
"test:watch": "vitest --watch",
|
|
24
|
+
"test:coverage": "vitest --coverage",
|
|
25
|
+
"prepublishOnly": "pnpm build"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.0.0"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"ai",
|
|
32
|
+
"rules",
|
|
33
|
+
"cli",
|
|
34
|
+
"copilot",
|
|
35
|
+
"cursor",
|
|
36
|
+
"cline",
|
|
37
|
+
"configuration",
|
|
38
|
+
"development"
|
|
39
|
+
],
|
|
40
|
+
"author": "dyoshikawa",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/dyoshikawa/rulesync.git"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/dyoshikawa/rulesync/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/dyoshikawa/rulesync#readme",
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"packageManager": "pnpm@7.33.7",
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@biomejs/biome": "2.0.0",
|
|
56
|
+
"@secretlint/secretlint-rule-preset-recommend": "10.1.0",
|
|
57
|
+
"@tsconfig/node24": "24.0.1",
|
|
58
|
+
"@types/node": "24.0.3",
|
|
59
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
60
|
+
"secretlint": "10.1.0",
|
|
61
|
+
"tsup": "8.5.0",
|
|
62
|
+
"tsx": "4.20.3",
|
|
63
|
+
"typescript": "5.8.3",
|
|
64
|
+
"vitest": "3.2.4"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"chokidar": "4.0.3",
|
|
68
|
+
"commander": "14.0.0",
|
|
69
|
+
"gray-matter": "4.0.3",
|
|
70
|
+
"marked": "15.0.12"
|
|
71
|
+
}
|
|
72
|
+
}
|