heymark 1.1.2 → 1.1.3

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/scripts/sync.js CHANGED
@@ -1,239 +1,312 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
-
4
- const fs = require("fs");
5
- const path = require("path");
6
- const { loadRules } = require("./lib/parser");
7
- const { CONFIG_RELATIVE, loadConfig, writeConfig } = require("./lib/config");
8
- const { getRulesDirFromRepo } = require("./lib/repo");
9
-
10
- const SCRIPT_DIR = __dirname;
11
- const PROJECT_ROOT = process.cwd();
12
-
13
- function discoverTools() {
14
- const toolsDir = path.join(SCRIPT_DIR, "tools");
15
- const registry = {};
16
-
17
- fs.readdirSync(toolsDir)
18
- .filter((f) => f.endsWith(".js"))
19
- .sort()
20
- .forEach((file) => {
21
- const key = path.basename(file, ".js");
22
- registry[key] = require(path.join(toolsDir, file));
23
- });
24
-
25
- return registry;
26
- }
27
-
28
- function parseArgs(availableTools) {
29
- const args = process.argv.slice(2);
30
- const config = {
31
- tools: Object.keys(availableTools),
32
- clean: false,
33
- preview: false,
34
- help: false,
35
- source: null,
36
- };
37
-
38
- for (let i = 0; i < args.length; i++) {
39
- const arg = args[i];
40
-
41
- if (arg === "--tools" || arg === "-t") {
42
- const val = args[++i];
43
- if (!val) {
44
- console.error("[Error] --tools requires a comma-separated list.");
45
- process.exit(1);
46
- }
47
- config.tools = val.split(",").map((t) => t.trim().toLowerCase());
48
- } else if (arg === "--clean" || arg === "-c") {
49
- config.clean = true;
50
- } else if (arg === "--preview" || arg === "-p") {
51
- config.preview = true;
52
- } else if (arg === "--source" || arg === "-s") {
53
- const val = args[++i];
54
- if (!val) {
55
- console.error("[Error] --source requires a GitHub repository URL.");
56
- process.exit(1);
57
- }
58
- config.source = val.trim();
59
- } else if (arg === "--help" || arg === "-h") {
60
- config.help = true;
61
- } else {
62
- console.error(`[Error] Unknown option: ${arg}`);
63
- console.error(" Use --help for usage information.");
64
- process.exit(1);
65
- }
66
- }
67
-
68
- const invalid = config.tools.filter((t) => !availableTools[t]);
69
- if (invalid.length > 0) {
70
- console.error(`[Error] Unknown tool(s): ${invalid.join(", ")}`);
71
- console.error(` Available: ${Object.keys(availableTools).join(", ")}`);
72
- process.exit(1);
73
- }
74
-
75
- return config;
76
- }
77
-
78
- function showHelp(tools) {
79
- const toolLines = Object.entries(tools)
80
- .map(([key, t]) => ` ${key.padEnd(10)} ${t.name.padEnd(16)} -> ${t.output}`)
81
- .join("\n");
82
-
83
- console.log(`
84
- AI Coding Tool Convention Sync
85
-
86
- Reads *.md from a GitHub repository (public or private) and generates
87
- tool-specific configuration files for various AI coding assistants.
88
- Same rules everywhere: A computer, B computer, same remote repo.
89
-
90
- Usage:
91
- heymark init <repo-url> Set rules source (creates ${CONFIG_RELATIVE})
92
- heymark [options] Sync from configured or --source repo
93
-
94
- Options:
95
- --source, -s <url> GitHub repo URL for this run (overrides ${CONFIG_RELATIVE})
96
- --tools, -t <list> Comma-separated tool names (default: all)
97
- --clean, -c Remove all generated files
98
- --preview, -p Preview what will be generated without writing
99
- --help, -h Show this help message
100
-
101
- Rules source (in order):
102
- 1. --source <repo-url>
103
- 2. ${CONFIG_RELATIVE} (set via 'heymark init <repo-url>')
104
- Private repos: use SSH (git@github.com:org/repo.git) or HTTPS with token.
105
-
106
- Available tools:
107
- ${toolLines}
108
-
109
- Examples:
110
- heymark init https://github.com/org/my-rules.git
111
- heymark init https://github.com/org/my-rules.git --dir rules --branch main
112
- heymark
113
- heymark -s https://github.com/org/other-rules.git
114
- heymark -t cursor,claude
115
- heymark -c
116
- heymark -p
117
- `);
118
- }
119
-
120
- function runInit(initArgs) {
121
- const args = initArgs.slice(0);
122
- const repoUrl = args[0];
123
- if (!repoUrl || repoUrl.startsWith("--")) {
124
- console.error("[Error] init requires a GitHub repository URL.");
125
- console.error(" Example: heymark init https://github.com/org/my-rules.git");
126
- console.error(" Example: heymark init git@github.com:org/my-rules.git");
127
- console.error(" Optional: --branch <branch> --dir <subdir> (e.g. --dir rules)");
128
- process.exit(1);
129
- }
130
- let branch = "main";
131
- let rulesSourceDir = "";
132
- for (let i = 1; i < args.length; i++) {
133
- if ((args[i] === "--branch" || args[i] === "-b") && args[i + 1]) {
134
- branch = args[++i].trim();
135
- } else if ((args[i] === "--dir" || args[i] === "-d") && args[i + 1]) {
136
- rulesSourceDir = args[++i].trim();
137
- }
138
- }
139
- const config = { rulesSource: repoUrl.trim(), branch, rulesSourceDir };
140
- const configPath = writeConfig(PROJECT_ROOT, config);
141
- console.log(
142
- `[Init] Rules source saved to ${path.relative(PROJECT_ROOT, configPath) || configPath}`
143
- );
144
- console.log(` rulesSource: ${config.rulesSource}`);
145
- if (branch !== "main") console.log(` branch: ${branch}`);
146
- if (rulesSourceDir) console.log(` rulesSourceDir: ${rulesSourceDir}`);
147
- console.log("");
148
- console.log("Run 'heymark' to fetch rules from the repo and generate tool configs.");
149
- }
150
-
151
- function resolveRulesDir(config) {
152
- const repoConfig = config.source
153
- ? { rulesSource: config.source, branch: "main", rulesSourceDir: "" }
154
- : loadConfig(PROJECT_ROOT);
155
- if (!repoConfig) return null;
156
- return getRulesDirFromRepo(PROJECT_ROOT, repoConfig);
157
- }
158
-
159
- function main() {
160
- const args = process.argv.slice(2);
161
- const subcommand = args[0];
162
- if (subcommand === "init") {
163
- runInit(args.slice(1));
164
- return;
165
- }
166
-
167
- const tools = discoverTools();
168
- const config = parseArgs(tools);
169
-
170
- if (config.help) {
171
- showHelp(tools);
172
- return;
173
- }
174
-
175
- const RULES_SRC_DIR = resolveRulesDir(config);
176
- if (!RULES_SRC_DIR) {
177
- console.error("[Error] Rules source not set.");
178
- console.error(" Run: heymark init <github-repo-url>");
179
- console.error(" Example: heymark init https://github.com/org/my-rules.git");
180
- console.error(" Or use: heymark --source <repo-url>");
181
- process.exit(1);
182
- }
183
-
184
- const rulesRelPath = path.relative(PROJECT_ROOT, RULES_SRC_DIR) || ".";
185
-
186
- console.log("[Sync] Starting convention sync...");
187
- console.log(` Source: ${rulesRelPath} (from remote repo)`);
188
- console.log(` Target: ${PROJECT_ROOT}`);
189
- console.log(` Tools: ${config.tools.join(", ")}`);
190
- console.log("");
191
-
192
- const rules = loadRules(RULES_SRC_DIR);
193
- console.log(`[Load] ${rules.length} rule(s): ${rules.map((r) => r.name).join(", ")}`);
194
- console.log("");
195
-
196
- if (config.clean) {
197
- console.log("[Clean] Removing generated files...");
198
- const ruleNames = rules.map((r) => r.name);
199
- for (const key of config.tools) {
200
- const cleaned = tools[key].clean(ruleNames, PROJECT_ROOT);
201
- cleaned.forEach((p) => console.log(` Deleted: ${p}`));
202
- }
203
- console.log("");
204
- console.log(`[Done] Cleaned ${config.tools.length} tool(s) successfully.`);
205
- return;
206
- }
207
-
208
- if (config.preview) {
209
- console.log("[Preview] Would generate:");
210
- for (const key of config.tools) {
211
- const t = tools[key];
212
- console.log(` ${t.name.padEnd(16)} -> ${t.output} (${rules.length} rules)`);
213
- }
214
- return;
215
- }
216
-
217
- // Clean existing files before generating (for fresh sync)
218
- console.log("[Clean] Removing existing generated files...");
219
- const ruleNames = rules.map((r) => r.name);
220
- for (const key of config.tools) {
221
- const cleaned = tools[key].clean(ruleNames, PROJECT_ROOT);
222
- if (cleaned.length > 0) {
223
- cleaned.forEach((p) => console.log(` Deleted: ${p}`));
224
- }
225
- }
226
- console.log("");
227
-
228
- console.log("[Generate]");
229
- for (const key of config.tools) {
230
- const t = tools[key];
231
- const count = t.generate(rules, PROJECT_ROOT);
232
- console.log(` ${t.name.padEnd(16)} -> ${t.output} (${count} rules)`);
233
- }
234
-
235
- console.log("");
236
- console.log(`[Done] ${config.tools.length} tool(s) synced successfully.`);
237
- }
238
-
239
- main();
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ const { CONFIG_RELATIVE, DEFAULT_BRANCH, loadConfig, writeConfig } = require("./lib/config");
7
+ const { loadRules } = require("./lib/parser");
8
+ const { getRulesDirFromRepo } = require("./lib/repo");
9
+
10
+ const SCRIPT_DIR = __dirname;
11
+ const PROJECT_ROOT = process.cwd();
12
+
13
+ const INIT_SUBCOMMAND = "init";
14
+ const OPTION_TOOLS = "--tools";
15
+ const OPTION_SOURCE = "--source";
16
+ const OPTION_CLEAN = "--clean";
17
+ const OPTION_PREVIEW = "--preview";
18
+ const OPTION_HELP = "--help";
19
+ const SHORT_TOOLS = "-t";
20
+ const SHORT_SOURCE = "-s";
21
+ const SHORT_CLEAN = "-c";
22
+ const SHORT_PREVIEW = "-p";
23
+ const SHORT_HELP = "-h";
24
+ const OPTION_BRANCH = "--branch";
25
+ const OPTION_DIR = "--dir";
26
+ const SHORT_BRANCH = "-b";
27
+ const SHORT_DIR = "-d";
28
+
29
+ function exitWithError(message, details = []) {
30
+ console.error(`[Error] ${message}`);
31
+ details.forEach((detail) => console.error(` ${detail}`));
32
+ process.exit(1);
33
+ }
34
+
35
+ function discoverTools() {
36
+ const toolsDir = path.join(SCRIPT_DIR, "tools");
37
+ const registry = {};
38
+
39
+ fs.readdirSync(toolsDir)
40
+ .filter((fileName) => fileName.endsWith(".js"))
41
+ .sort()
42
+ .forEach((file) => {
43
+ const key = path.basename(file, ".js");
44
+ registry[key] = require(path.join(toolsDir, file));
45
+ });
46
+
47
+ return registry;
48
+ }
49
+
50
+ function parseToolList(rawValue) {
51
+ const parsed = rawValue
52
+ .split(",")
53
+ .map((tool) => tool.trim().toLowerCase())
54
+ .filter(Boolean);
55
+
56
+ if (parsed.length === 0) {
57
+ exitWithError("--tools requires a comma-separated list.");
58
+ }
59
+
60
+ return parsed;
61
+ }
62
+
63
+ function parseArgs(availableTools) {
64
+ const args = process.argv.slice(2);
65
+ const config = {
66
+ tools: Object.keys(availableTools),
67
+ clean: false,
68
+ preview: false,
69
+ help: false,
70
+ source: null,
71
+ };
72
+
73
+ for (let i = 0; i < args.length; i++) {
74
+ const arg = args[i];
75
+
76
+ if (arg === OPTION_TOOLS || arg === SHORT_TOOLS) {
77
+ const value = args[++i];
78
+ if (!value) {
79
+ exitWithError("--tools requires a comma-separated list.");
80
+ }
81
+ config.tools = parseToolList(value);
82
+ } else if (arg === OPTION_CLEAN || arg === SHORT_CLEAN) {
83
+ config.clean = true;
84
+ } else if (arg === OPTION_PREVIEW || arg === SHORT_PREVIEW) {
85
+ config.preview = true;
86
+ } else if (arg === OPTION_SOURCE || arg === SHORT_SOURCE) {
87
+ const value = args[++i];
88
+ if (!value) {
89
+ exitWithError("--source requires a GitHub repository URL.");
90
+ }
91
+ config.source = value.trim();
92
+ } else if (arg === OPTION_HELP || arg === SHORT_HELP) {
93
+ config.help = true;
94
+ } else {
95
+ exitWithError(`Unknown option: ${arg}`, ["Use --help for usage information."]);
96
+ }
97
+ }
98
+
99
+ const invalidTools = config.tools.filter((tool) => !availableTools[tool]);
100
+ if (invalidTools.length > 0) {
101
+ exitWithError(`Unknown tool(s): ${invalidTools.join(", ")}`, [
102
+ `Available: ${Object.keys(availableTools).join(", ")}`,
103
+ ]);
104
+ }
105
+
106
+ return config;
107
+ }
108
+
109
+ function showHelp(tools) {
110
+ const toolLines = Object.entries(tools)
111
+ .map(([toolKey, toolDefinition]) => {
112
+ const paddedKey = toolKey.padEnd(10);
113
+ const paddedName = toolDefinition.name.padEnd(16);
114
+ return ` ${paddedKey} ${paddedName} -> ${toolDefinition.output}`;
115
+ })
116
+ .join("\n");
117
+
118
+ console.log(`
119
+ AI Coding Tool Convention Sync
120
+
121
+ Reads *.md from a GitHub repository (public or private) and generates
122
+ tool-specific configuration files for various AI coding assistants.
123
+ Same rules everywhere: A computer, B computer, same remote repo.
124
+
125
+ Usage:
126
+ heymark init <repo-url> Set rules source (creates ${CONFIG_RELATIVE})
127
+ heymark [options] Sync from configured or --source repo
128
+
129
+ Options:
130
+ --source, -s <url> GitHub repo URL for this run (overrides ${CONFIG_RELATIVE})
131
+ --tools, -t <list> Comma-separated tool names (default: all)
132
+ --clean, -c Remove all generated files
133
+ --preview, -p Preview what will be generated without writing
134
+ --help, -h Show this help message
135
+
136
+ Rules source (in order):
137
+ 1. --source <repo-url>
138
+ 2. ${CONFIG_RELATIVE} (set via 'heymark init <repo-url>')
139
+ Private repos: use SSH (git@github.com:org/repo.git) or HTTPS with token.
140
+
141
+ Available tools:
142
+ ${toolLines}
143
+
144
+ Examples:
145
+ heymark init https://github.com/org/my-rules.git
146
+ heymark init https://github.com/org/my-rules.git --dir rules --branch main
147
+ heymark
148
+ heymark -s https://github.com/org/other-rules.git
149
+ heymark -t cursor,claude
150
+ heymark -c
151
+ heymark -p
152
+ `);
153
+ }
154
+
155
+ function parseInitArgs(initArgs) {
156
+ const repoUrl = initArgs[0];
157
+ if (!repoUrl || repoUrl.startsWith("--")) {
158
+ exitWithError("init requires a GitHub repository URL.", [
159
+ "Example: heymark init https://github.com/org/my-rules.git",
160
+ "Example: heymark init git@github.com:org/my-rules.git",
161
+ "Optional: --branch <branch> --dir <subdir> (e.g. --dir rules)",
162
+ ]);
163
+ }
164
+
165
+ let branch = DEFAULT_BRANCH;
166
+ let rulesSourceDir = "";
167
+
168
+ for (let i = 1; i < initArgs.length; i++) {
169
+ const arg = initArgs[i];
170
+
171
+ if (arg === OPTION_BRANCH || arg === SHORT_BRANCH) {
172
+ const value = initArgs[++i];
173
+ if (!value) {
174
+ exitWithError("--branch requires a branch name.");
175
+ }
176
+ branch = value.trim();
177
+ continue;
178
+ }
179
+
180
+ if (arg === OPTION_DIR || arg === SHORT_DIR) {
181
+ const value = initArgs[++i];
182
+ if (!value) {
183
+ exitWithError("--dir requires a directory path.");
184
+ }
185
+ rulesSourceDir = value.trim();
186
+ continue;
187
+ }
188
+
189
+ exitWithError(`Unknown option for init: ${arg}`);
190
+ }
191
+
192
+ return { rulesSource: repoUrl.trim(), branch, rulesSourceDir };
193
+ }
194
+
195
+ function runInit(initArgs) {
196
+ const config = parseInitArgs(initArgs);
197
+ const configPath = writeConfig(PROJECT_ROOT, config);
198
+
199
+ console.log(
200
+ `[Init] Rules source saved to ${path.relative(PROJECT_ROOT, configPath) || configPath}`
201
+ );
202
+ console.log(` rulesSource: ${config.rulesSource}`);
203
+ if (config.branch !== DEFAULT_BRANCH) {
204
+ console.log(` branch: ${config.branch}`);
205
+ }
206
+ if (config.rulesSourceDir) {
207
+ console.log(` rulesSourceDir: ${config.rulesSourceDir}`);
208
+ }
209
+ console.log("");
210
+ console.log("Run 'heymark' to fetch rules from the repo and generate tool configs.");
211
+ }
212
+
213
+ function resolveRulesDir(config) {
214
+ const repoConfig = config.source
215
+ ? { rulesSource: config.source, branch: DEFAULT_BRANCH, rulesSourceDir: "" }
216
+ : loadConfig(PROJECT_ROOT);
217
+
218
+ if (!repoConfig) {
219
+ return null;
220
+ }
221
+
222
+ return getRulesDirFromRepo(PROJECT_ROOT, repoConfig);
223
+ }
224
+
225
+ function cleanGeneratedFiles(tools, selectedTools, ruleNames, onlyPrintWhenDeleted) {
226
+ for (const toolKey of selectedTools) {
227
+ const cleanedPaths = tools[toolKey].clean(ruleNames, PROJECT_ROOT);
228
+ if (onlyPrintWhenDeleted && cleanedPaths.length === 0) {
229
+ continue;
230
+ }
231
+
232
+ cleanedPaths.forEach((filePath) => {
233
+ console.log(` Deleted: ${filePath}`);
234
+ });
235
+ }
236
+ }
237
+
238
+ function main() {
239
+ const args = process.argv.slice(2);
240
+ const subcommand = args[0];
241
+ if (subcommand === INIT_SUBCOMMAND) {
242
+ runInit(args.slice(1));
243
+ return;
244
+ }
245
+
246
+ const tools = discoverTools();
247
+ const config = parseArgs(tools);
248
+
249
+ if (config.help) {
250
+ showHelp(tools);
251
+ return;
252
+ }
253
+
254
+ const rulesSourceDir = resolveRulesDir(config);
255
+ if (!rulesSourceDir) {
256
+ console.error("[Error] Rules source not set.");
257
+ console.error(" Run: heymark init <github-repo-url>");
258
+ console.error(" Example: heymark init https://github.com/org/my-rules.git");
259
+ console.error(" Or use: heymark --source <repo-url>");
260
+ process.exit(1);
261
+ }
262
+
263
+ const rulesRelPath = path.relative(PROJECT_ROOT, rulesSourceDir) || ".";
264
+
265
+ console.log("[Sync] Starting convention sync...");
266
+ console.log(` Source: ${rulesRelPath} (from remote repo)`);
267
+ console.log(` Target: ${PROJECT_ROOT}`);
268
+ console.log(` Tools: ${config.tools.join(", ")}`);
269
+ console.log("");
270
+
271
+ const rules = loadRules(rulesSourceDir);
272
+ console.log(`[Load] ${rules.length} rule(s): ${rules.map((rule) => rule.name).join(", ")}`);
273
+ console.log("");
274
+
275
+ const ruleNames = rules.map((rule) => rule.name);
276
+
277
+ if (config.clean) {
278
+ console.log("[Clean] Removing generated files...");
279
+ cleanGeneratedFiles(tools, config.tools, ruleNames, false);
280
+ console.log("");
281
+ console.log(`[Done] Cleaned ${config.tools.length} tool(s) successfully.`);
282
+ return;
283
+ }
284
+
285
+ if (config.preview) {
286
+ console.log("[Preview] Would generate:");
287
+ for (const toolKey of config.tools) {
288
+ const toolDefinition = tools[toolKey];
289
+ const summary = `${toolDefinition.name.padEnd(16)} -> ${toolDefinition.output}`;
290
+ console.log(` ${summary} (${rules.length} rules)`);
291
+ }
292
+ return;
293
+ }
294
+
295
+ // Ensure regenerated output is always fresh.
296
+ console.log("[Clean] Removing existing generated files...");
297
+ cleanGeneratedFiles(tools, config.tools, ruleNames, true);
298
+ console.log("");
299
+
300
+ console.log("[Generate]");
301
+ for (const toolKey of config.tools) {
302
+ const toolDefinition = tools[toolKey];
303
+ const count = toolDefinition.generate(rules, PROJECT_ROOT);
304
+ const summary = `${toolDefinition.name.padEnd(16)} -> ${toolDefinition.output}`;
305
+ console.log(` ${summary} (${count} rules)`);
306
+ }
307
+
308
+ console.log("");
309
+ console.log(`[Done] ${config.tools.length} tool(s) synced successfully.`);
310
+ }
311
+
312
+ main();
@@ -1,41 +1,53 @@
1
- "use strict";
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
-
6
- module.exports = {
7
- name: "Antigravity",
8
- output: ".agent/skills/*/SKILL.md",
9
-
10
- generate(rules, projectRoot) {
11
- for (const rule of rules) {
12
- const skillDir = path.join(projectRoot, ".agent", "skills", rule.name);
13
- fs.mkdirSync(skillDir, { recursive: true });
14
-
15
- const lines = [
16
- "---",
17
- `name: ${rule.name}`,
18
- `description: "${rule.description}"`,
19
- "---",
20
- ];
21
- const content = lines.join("\n") + "\n\n" + rule.body + "\n";
22
- fs.writeFileSync(path.join(skillDir, "SKILL.md"), content);
23
- }
24
-
25
- return rules.length;
26
- },
27
-
28
- clean(ruleNames, projectRoot) {
29
- const cleaned = [];
30
-
31
- for (const name of ruleNames) {
32
- const skillDir = path.join(projectRoot, ".agent", "skills", name);
33
- if (fs.existsSync(skillDir)) {
34
- fs.rmSync(skillDir, { recursive: true });
35
- cleaned.push(path.join(".agent", "skills", name));
36
- }
37
- }
38
-
39
- return cleaned;
40
- },
41
- };
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ const SKILLS_DIR = path.join(".agent", "skills");
7
+ const SKILL_FILE_NAME = "SKILL.md";
8
+
9
+ function getSkillDir(projectRoot, ruleName) {
10
+ return path.join(projectRoot, SKILLS_DIR, ruleName);
11
+ }
12
+
13
+ function createSkillContent(rule) {
14
+ const frontmatterLines = [
15
+ "---",
16
+ `name: ${rule.name}`,
17
+ `description: "${rule.description}"`,
18
+ "---",
19
+ ];
20
+
21
+ return `${frontmatterLines.join("\n")}\n\n${rule.body}\n`;
22
+ }
23
+
24
+ module.exports = {
25
+ name: "Antigravity",
26
+ output: ".agent/skills/*/SKILL.md",
27
+
28
+ generate(rules, projectRoot) {
29
+ for (const rule of rules) {
30
+ const skillDir = getSkillDir(projectRoot, rule.name);
31
+ fs.mkdirSync(skillDir, { recursive: true });
32
+ const filePath = path.join(skillDir, SKILL_FILE_NAME);
33
+ const content = createSkillContent(rule);
34
+ fs.writeFileSync(filePath, content, "utf8");
35
+ }
36
+
37
+ return rules.length;
38
+ },
39
+
40
+ clean(ruleNames, projectRoot) {
41
+ const cleaned = [];
42
+
43
+ for (const ruleName of ruleNames) {
44
+ const skillDir = getSkillDir(projectRoot, ruleName);
45
+ if (fs.existsSync(skillDir)) {
46
+ fs.rmSync(skillDir, { recursive: true });
47
+ cleaned.push(path.join(SKILLS_DIR, ruleName));
48
+ }
49
+ }
50
+
51
+ return cleaned;
52
+ },
53
+ };