@juho0719/cckit 0.2.1 → 0.2.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/assets/hooks/post-edit-format.js +0 -1
- package/assets/hooks/post-edit-typecheck.js +0 -2
- package/dist/chunk-ID643AV4.js +37 -0
- package/dist/{chunk-3UNN3IBE.js → chunk-SLVASXTF.js} +1 -1
- package/dist/{cli-D2Q5QUO7.js → cli-6WQMAFNA.js} +6 -7
- package/dist/{hooks-IIG2XK4I.js → hooks-S73JTX2I.js} +1 -1
- package/dist/index.js +5 -6
- package/dist/rules-EFSJ3L3A.js +9 -0
- package/dist/{uninstall-cli-VCOZGDBM.js → uninstall-cli-7XGNDIUC.js} +43 -88
- package/package.json +1 -1
- package/dist/chunk-RMUKD7CW.js +0 -44
- package/dist/rules-2CPBVNNJ.js +0 -7
|
@@ -32,7 +32,6 @@ process.stdin.on("end", () => {
|
|
|
32
32
|
if (filePath && /\.(ts|tsx)$/.test(filePath)) {
|
|
33
33
|
const resolvedPath = path.resolve(filePath);
|
|
34
34
|
if (!fs.existsSync(resolvedPath)) {
|
|
35
|
-
process.stdout.write(data);
|
|
36
35
|
process.exit(0);
|
|
37
36
|
}
|
|
38
37
|
// Find nearest tsconfig.json by walking up (max 20 levels to prevent infinite loop)
|
|
@@ -91,6 +90,5 @@ process.stdin.on("end", () => {
|
|
|
91
90
|
// Invalid input — pass through
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
process.stdout.write(data);
|
|
95
93
|
process.exit(0);
|
|
96
94
|
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
backupIfExists
|
|
3
|
+
} from "./chunk-K25UZZVG.js";
|
|
4
|
+
import {
|
|
5
|
+
copyFileUtil,
|
|
6
|
+
ensureDir
|
|
7
|
+
} from "./chunk-3GUKEMND.js";
|
|
8
|
+
import {
|
|
9
|
+
getAssetsDir
|
|
10
|
+
} from "./chunk-5XOKKPAA.js";
|
|
11
|
+
|
|
12
|
+
// src/installers/rules.ts
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { readdir } from "fs/promises";
|
|
15
|
+
async function installRules(categories, targetDir) {
|
|
16
|
+
const srcRulesDir = join(getAssetsDir(), "rules");
|
|
17
|
+
for (const category of categories) {
|
|
18
|
+
const srcCatDir = join(srcRulesDir, category);
|
|
19
|
+
let files;
|
|
20
|
+
try {
|
|
21
|
+
files = (await readdir(srcCatDir)).filter((f) => f.endsWith(".md"));
|
|
22
|
+
} catch {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const destCatDir = join(targetDir, "rules", category);
|
|
26
|
+
await ensureDir(destCatDir);
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const dest = join(destCatDir, file);
|
|
29
|
+
await backupIfExists(dest);
|
|
30
|
+
await copyFileUtil(join(srcCatDir, file), dest);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
installRules
|
|
37
|
+
};
|
|
@@ -44,7 +44,7 @@ async function installHooks(hooks, targetDir) {
|
|
|
44
44
|
const dest = join(hooksDir, hook.file);
|
|
45
45
|
await backupIfExists(dest);
|
|
46
46
|
await copyFileUtil(join(srcDir, hook.file), dest);
|
|
47
|
-
const hookCommand = `node ${
|
|
47
|
+
const hookCommand = `node "$CLAUDE_PROJECT_DIR"/.claude/hooks/${hook.file}`;
|
|
48
48
|
await mergeHookSettings(settingsPath, hook.hookType, hook.matcher, hookCommand);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -24,12 +24,12 @@ import {
|
|
|
24
24
|
} from "./chunk-3Y26YU4R.js";
|
|
25
25
|
import {
|
|
26
26
|
installHooks
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-K25UZZVG.js";
|
|
29
|
-
import "./chunk-3GUKEMND.js";
|
|
27
|
+
} from "./chunk-SLVASXTF.js";
|
|
30
28
|
import {
|
|
31
29
|
installRules
|
|
32
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ID643AV4.js";
|
|
31
|
+
import "./chunk-K25UZZVG.js";
|
|
32
|
+
import "./chunk-3GUKEMND.js";
|
|
33
33
|
import {
|
|
34
34
|
getGlobalDir,
|
|
35
35
|
getProjectDir
|
|
@@ -246,8 +246,7 @@ async function runCli() {
|
|
|
246
246
|
}
|
|
247
247
|
if (plan.ruleCategories.length) {
|
|
248
248
|
spinner.text = "Installing rules...";
|
|
249
|
-
|
|
250
|
-
await installRules(plan.ruleCategories, claudeMd);
|
|
249
|
+
await installRules(plan.ruleCategories, targetDir);
|
|
251
250
|
}
|
|
252
251
|
if (plan.mcps.length) {
|
|
253
252
|
spinner.text = "Installing MCP servers...";
|
|
@@ -263,7 +262,7 @@ async function runCli() {
|
|
|
263
262
|
if (plan.skills.length) console.log(` ${chalk.green("\u2713")} ${plan.skills.length} skill(s) \u2192 ${join(targetDir, "skills")}`);
|
|
264
263
|
if (plan.commands.length) console.log(` ${chalk.green("\u2713")} ${plan.commands.length} command(s) \u2192 ${join(targetDir, "commands")}`);
|
|
265
264
|
if (plan.hooks.length) console.log(` ${chalk.green("\u2713")} ${plan.hooks.length} hook(s) \u2192 ${join(targetDir, "hooks")}`);
|
|
266
|
-
if (plan.ruleCategories.length) console.log(` ${chalk.green("\u2713")} Rules
|
|
265
|
+
if (plan.ruleCategories.length) console.log(` ${chalk.green("\u2713")} Rules copied \u2192 ${join(targetDir, "rules")}`);
|
|
267
266
|
if (plan.mcps.length) console.log(` ${chalk.green("\u2713")} ${plan.mcps.length} MCP server(s) \u2192 ${scope === "global" ? "~/.claude.json" : "./.claude.json"}`);
|
|
268
267
|
if (plan.claudemds.length) console.log(` ${chalk.green("\u2713")} ClaudeMd appended \u2192 ${join(targetDir, "CLAUDE.md")}`);
|
|
269
268
|
console.log("");
|
package/dist/index.js
CHANGED
|
@@ -70,8 +70,8 @@ Installing all to ${targetDir}...
|
|
|
70
70
|
import("./agents-AEKT67A6.js"),
|
|
71
71
|
import("./skills-ULMW3UCM.js"),
|
|
72
72
|
import("./commands-P5LILVZ5.js"),
|
|
73
|
-
import("./hooks-
|
|
74
|
-
import("./rules-
|
|
73
|
+
import("./hooks-S73JTX2I.js"),
|
|
74
|
+
import("./rules-EFSJ3L3A.js"),
|
|
75
75
|
import("./mcps-67Q7TBGW.js"),
|
|
76
76
|
import("./claudemd-KKQ2DL7P.js")
|
|
77
77
|
]);
|
|
@@ -93,8 +93,7 @@ Installing all to ${targetDir}...
|
|
|
93
93
|
spinner.text = "Installing hooks...";
|
|
94
94
|
await installHooks(hooks, targetDir);
|
|
95
95
|
spinner.text = "Installing rules...";
|
|
96
|
-
|
|
97
|
-
await installRules(ruleCategories.map((rc) => rc.category), claudeMd);
|
|
96
|
+
await installRules(ruleCategories.map((rc) => rc.category), targetDir);
|
|
98
97
|
spinner.text = "Installing MCP servers...";
|
|
99
98
|
await installMcps(mcps, scope, /* @__PURE__ */ new Map());
|
|
100
99
|
spinner.text = "Installing claudemd...";
|
|
@@ -125,7 +124,7 @@ async function main() {
|
|
|
125
124
|
return;
|
|
126
125
|
}
|
|
127
126
|
if (args.includes("--uninstall") || args.includes("-u")) {
|
|
128
|
-
const { runUninstallCli } = await import("./uninstall-cli-
|
|
127
|
+
const { runUninstallCli } = await import("./uninstall-cli-7XGNDIUC.js");
|
|
129
128
|
await runUninstallCli();
|
|
130
129
|
return;
|
|
131
130
|
}
|
|
@@ -135,7 +134,7 @@ async function main() {
|
|
|
135
134
|
await installAll(scope);
|
|
136
135
|
return;
|
|
137
136
|
}
|
|
138
|
-
const { runCli } = await import("./cli-
|
|
137
|
+
const { runCli } = await import("./cli-6WQMAFNA.js");
|
|
139
138
|
await runCli();
|
|
140
139
|
}
|
|
141
140
|
main().catch((err) => {
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
import { checkbox, select, confirm } from "@inquirer/prompts";
|
|
18
18
|
import chalk from "chalk";
|
|
19
19
|
import ora from "ora";
|
|
20
|
-
import { join as join9 } from "path";
|
|
21
20
|
|
|
22
21
|
// src/scanner.ts
|
|
23
22
|
import { readdir, readFile, access } from "fs/promises";
|
|
@@ -76,38 +75,17 @@ async function getInstalledHooks(targetDir) {
|
|
|
76
75
|
return registryHooks.filter((h) => installedFiles.includes(h.file));
|
|
77
76
|
}
|
|
78
77
|
async function getInstalledRuleCategories(targetDir) {
|
|
79
|
-
const
|
|
80
|
-
let
|
|
78
|
+
const rulesDir = join(targetDir, "rules");
|
|
79
|
+
let installedDirs = [];
|
|
81
80
|
try {
|
|
82
|
-
await
|
|
83
|
-
|
|
81
|
+
const entries = await readdir(rulesDir, { withFileTypes: true });
|
|
82
|
+
installedDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
84
83
|
} catch {
|
|
85
84
|
return [];
|
|
86
85
|
}
|
|
87
|
-
const installedHeaders = /* @__PURE__ */ new Set();
|
|
88
|
-
for (const line of content.split("\n")) {
|
|
89
|
-
const match = line.match(/^(#{1,2}\s+.+)/);
|
|
90
|
-
if (match) installedHeaders.add(match[1].trim());
|
|
91
|
-
}
|
|
92
86
|
const allCategories = await getRuleCategories();
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
const catDir = join(getAssetsDir(), "rules", rc.category);
|
|
96
|
-
let found = false;
|
|
97
|
-
for (const file of rc.files) {
|
|
98
|
-
try {
|
|
99
|
-
const fileContent = await readFile(join(catDir, file), "utf-8");
|
|
100
|
-
const headerMatch = fileContent.match(/^(#{1,2}\s+.+)/m);
|
|
101
|
-
if (headerMatch && installedHeaders.has(headerMatch[1].trim())) {
|
|
102
|
-
found = true;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
} catch {
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (found) installedCategories.push(rc.category);
|
|
109
|
-
}
|
|
110
|
-
return installedCategories;
|
|
87
|
+
const registryCategoryNames = new Set(allCategories.map((rc) => rc.category));
|
|
88
|
+
return installedDirs.filter((d) => registryCategoryNames.has(d));
|
|
111
89
|
}
|
|
112
90
|
async function getInstalledClaudemd(targetDir) {
|
|
113
91
|
const claudeMdPath = join(targetDir, "CLAUDE.md");
|
|
@@ -206,7 +184,7 @@ async function uninstallCommands(commands, targetDir) {
|
|
|
206
184
|
import { join as join5 } from "path";
|
|
207
185
|
import { rm as rm4, readFile as readFile2, writeFile, access as access5 } from "fs/promises";
|
|
208
186
|
import { constants as constants5 } from "fs";
|
|
209
|
-
async function removeHookFromSettings(settingsPath,
|
|
187
|
+
async function removeHookFromSettings(settingsPath, hookFileName) {
|
|
210
188
|
let settings = {};
|
|
211
189
|
try {
|
|
212
190
|
await access5(settingsPath, constants5.F_OK);
|
|
@@ -216,11 +194,12 @@ async function removeHookFromSettings(settingsPath, hookCommand) {
|
|
|
216
194
|
return;
|
|
217
195
|
}
|
|
218
196
|
if (!settings.hooks) return;
|
|
197
|
+
const suffix = `/hooks/${hookFileName}`;
|
|
219
198
|
for (const hookType of Object.keys(settings.hooks)) {
|
|
220
199
|
const matchers = settings.hooks[hookType];
|
|
221
200
|
for (let i = matchers.length - 1; i >= 0; i--) {
|
|
222
201
|
const matcher = matchers[i];
|
|
223
|
-
matcher.hooks = matcher.hooks.filter((h) => h.command
|
|
202
|
+
matcher.hooks = matcher.hooks.filter((h) => !h.command.endsWith(suffix));
|
|
224
203
|
if (matcher.hooks.length === 0) {
|
|
225
204
|
matchers.splice(i, 1);
|
|
226
205
|
}
|
|
@@ -239,8 +218,7 @@ async function uninstallHooks(hooks, targetDir) {
|
|
|
239
218
|
const settingsPath = join5(targetDir, "settings.json");
|
|
240
219
|
for (const hook of hooks) {
|
|
241
220
|
const filePath = join5(hooksDir, hook.file);
|
|
242
|
-
|
|
243
|
-
await removeHookFromSettings(settingsPath, hookCommand);
|
|
221
|
+
await removeHookFromSettings(settingsPath, hook.file);
|
|
244
222
|
try {
|
|
245
223
|
await access5(filePath, constants5.F_OK);
|
|
246
224
|
await rm4(filePath);
|
|
@@ -250,69 +228,47 @@ async function uninstallHooks(hooks, targetDir) {
|
|
|
250
228
|
}
|
|
251
229
|
|
|
252
230
|
// src/uninstallers/rules.ts
|
|
253
|
-
import {
|
|
254
|
-
import { constants as constants6 } from "fs";
|
|
231
|
+
import { readdir as readdir2, rm as rm5 } from "fs/promises";
|
|
255
232
|
import { join as join6 } from "path";
|
|
256
|
-
async function uninstallRules(categories,
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
await access6(claudeMdPath, constants6.F_OK);
|
|
260
|
-
existing = await readFile3(claudeMdPath, "utf-8");
|
|
261
|
-
} catch {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
const headersToRemove = /* @__PURE__ */ new Set();
|
|
233
|
+
async function uninstallRules(categories, targetDir) {
|
|
234
|
+
const assetsRulesDir = join6(getAssetsDir(), "rules");
|
|
265
235
|
for (const category of categories) {
|
|
266
|
-
const
|
|
267
|
-
let
|
|
236
|
+
const srcCatDir = join6(assetsRulesDir, category);
|
|
237
|
+
let assetFiles;
|
|
268
238
|
try {
|
|
269
|
-
|
|
270
|
-
files = (await readdir2(catDir)).filter((f) => f.endsWith(".md"));
|
|
239
|
+
assetFiles = (await readdir2(srcCatDir)).filter((f) => f.endsWith(".md"));
|
|
271
240
|
} catch {
|
|
272
241
|
continue;
|
|
273
242
|
}
|
|
274
|
-
|
|
243
|
+
const destCatDir = join6(targetDir, "rules", category);
|
|
244
|
+
for (const file of assetFiles) {
|
|
275
245
|
try {
|
|
276
|
-
|
|
277
|
-
const headerMatch = content.match(/^(#{1,2}\s+.+)/m);
|
|
278
|
-
if (headerMatch) {
|
|
279
|
-
headersToRemove.add(headerMatch[1].trim());
|
|
280
|
-
}
|
|
246
|
+
await rm5(join6(destCatDir, file));
|
|
281
247
|
} catch {
|
|
282
248
|
}
|
|
283
249
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
let inRemovedSection = false;
|
|
289
|
-
let currentDepth = 0;
|
|
290
|
-
for (const line of lines) {
|
|
291
|
-
const headerMatch = line.match(/^(#{1,2})\s+/);
|
|
292
|
-
if (headerMatch) {
|
|
293
|
-
const depth = headerMatch[1].length;
|
|
294
|
-
const trimmed = line.trim();
|
|
295
|
-
if (headersToRemove.has(trimmed)) {
|
|
296
|
-
inRemovedSection = true;
|
|
297
|
-
currentDepth = depth;
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
if (inRemovedSection && depth <= currentDepth) {
|
|
301
|
-
inRemovedSection = false;
|
|
250
|
+
try {
|
|
251
|
+
const remaining = await readdir2(destCatDir);
|
|
252
|
+
if (remaining.length === 0) {
|
|
253
|
+
await rm5(destCatDir, { recursive: true });
|
|
302
254
|
}
|
|
255
|
+
} catch {
|
|
303
256
|
}
|
|
304
|
-
|
|
305
|
-
|
|
257
|
+
}
|
|
258
|
+
const rulesDir = join6(targetDir, "rules");
|
|
259
|
+
try {
|
|
260
|
+
const remaining = await readdir2(rulesDir);
|
|
261
|
+
if (remaining.length === 0) {
|
|
262
|
+
await rm5(rulesDir, { recursive: true });
|
|
306
263
|
}
|
|
264
|
+
} catch {
|
|
307
265
|
}
|
|
308
|
-
const cleaned = result.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
309
|
-
await writeFile2(claudeMdPath, cleaned, "utf-8");
|
|
310
266
|
}
|
|
311
267
|
|
|
312
268
|
// src/uninstallers/mcps.ts
|
|
313
269
|
import { join as join7 } from "path";
|
|
314
|
-
import { readFile as
|
|
315
|
-
import { constants as
|
|
270
|
+
import { readFile as readFile3, writeFile as writeFile2, access as access6 } from "fs/promises";
|
|
271
|
+
import { constants as constants6 } from "fs";
|
|
316
272
|
import { homedir as homedir2 } from "os";
|
|
317
273
|
function getClaudeJsonPath2(scope) {
|
|
318
274
|
if (scope === "global") {
|
|
@@ -324,8 +280,8 @@ async function uninstallMcps(serverNames, scope) {
|
|
|
324
280
|
const filePath = getClaudeJsonPath2(scope);
|
|
325
281
|
let claudeJson = {};
|
|
326
282
|
try {
|
|
327
|
-
await
|
|
328
|
-
const content = await
|
|
283
|
+
await access6(filePath, constants6.F_OK);
|
|
284
|
+
const content = await readFile3(filePath, "utf-8");
|
|
329
285
|
claudeJson = JSON.parse(content);
|
|
330
286
|
} catch {
|
|
331
287
|
return;
|
|
@@ -334,26 +290,26 @@ async function uninstallMcps(serverNames, scope) {
|
|
|
334
290
|
for (const name of serverNames) {
|
|
335
291
|
delete claudeJson.mcpServers[name];
|
|
336
292
|
}
|
|
337
|
-
await
|
|
293
|
+
await writeFile2(filePath, JSON.stringify(claudeJson, null, 2) + "\n", "utf-8");
|
|
338
294
|
}
|
|
339
295
|
|
|
340
296
|
// src/uninstallers/claudemd.ts
|
|
341
|
-
import { readFile as
|
|
342
|
-
import { constants as
|
|
297
|
+
import { readFile as readFile4, writeFile as writeFile3, access as access7 } from "fs/promises";
|
|
298
|
+
import { constants as constants7 } from "fs";
|
|
343
299
|
import { join as join8 } from "path";
|
|
344
300
|
async function uninstallClaudemd(items, targetDir) {
|
|
345
301
|
const claudeMdPath = join8(targetDir, "CLAUDE.md");
|
|
346
302
|
let existing = "";
|
|
347
303
|
try {
|
|
348
|
-
await
|
|
349
|
-
existing = await
|
|
304
|
+
await access7(claudeMdPath, constants7.F_OK);
|
|
305
|
+
existing = await readFile4(claudeMdPath, "utf-8");
|
|
350
306
|
} catch {
|
|
351
307
|
return;
|
|
352
308
|
}
|
|
353
309
|
const headersToRemove = /* @__PURE__ */ new Set();
|
|
354
310
|
for (const item of items) {
|
|
355
311
|
try {
|
|
356
|
-
const raw = await
|
|
312
|
+
const raw = await readFile4(join8(getAssetsDir(), "claudemd", item.file), "utf-8");
|
|
357
313
|
const content = raw.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, "");
|
|
358
314
|
const headerMatch = content.match(/^(#{1,2}\s+.+)/m);
|
|
359
315
|
if (headerMatch) {
|
|
@@ -386,7 +342,7 @@ async function uninstallClaudemd(items, targetDir) {
|
|
|
386
342
|
}
|
|
387
343
|
}
|
|
388
344
|
const cleaned = result.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
389
|
-
await
|
|
345
|
+
await writeFile3(claudeMdPath, cleaned, "utf-8");
|
|
390
346
|
}
|
|
391
347
|
|
|
392
348
|
// src/uninstall-cli.ts
|
|
@@ -613,8 +569,7 @@ async function runUninstallCli() {
|
|
|
613
569
|
}
|
|
614
570
|
if (plan.ruleCategories.length) {
|
|
615
571
|
spinner.text = "Removing rules...";
|
|
616
|
-
|
|
617
|
-
await uninstallRules(plan.ruleCategories, claudeMd);
|
|
572
|
+
await uninstallRules(plan.ruleCategories, targetDir);
|
|
618
573
|
}
|
|
619
574
|
if (plan.mcpNames.length) {
|
|
620
575
|
spinner.text = "Removing MCP servers...";
|
package/package.json
CHANGED
package/dist/chunk-RMUKD7CW.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getAssetsDir
|
|
3
|
-
} from "./chunk-5XOKKPAA.js";
|
|
4
|
-
|
|
5
|
-
// src/installers/rules.ts
|
|
6
|
-
import { join } from "path";
|
|
7
|
-
import { readFile, writeFile, access } from "fs/promises";
|
|
8
|
-
import { constants } from "fs";
|
|
9
|
-
async function installRules(categories, targetClaudeMd) {
|
|
10
|
-
const rulesDir = join(getAssetsDir(), "rules");
|
|
11
|
-
let existing = "";
|
|
12
|
-
try {
|
|
13
|
-
await access(targetClaudeMd, constants.F_OK);
|
|
14
|
-
existing = await readFile(targetClaudeMd, "utf-8");
|
|
15
|
-
} catch {
|
|
16
|
-
}
|
|
17
|
-
const toAppend = [];
|
|
18
|
-
for (const category of categories) {
|
|
19
|
-
const catDir = join(rulesDir, category);
|
|
20
|
-
let files;
|
|
21
|
-
try {
|
|
22
|
-
const { readdir } = await import("fs/promises");
|
|
23
|
-
files = (await readdir(catDir)).filter((f) => f.endsWith(".md"));
|
|
24
|
-
} catch {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
for (const file of files) {
|
|
28
|
-
const content = await readFile(join(catDir, file), "utf-8");
|
|
29
|
-
const headerMatch = content.match(/^#{1,2}\s+(.+)/m);
|
|
30
|
-
if (headerMatch) {
|
|
31
|
-
const header = headerMatch[0];
|
|
32
|
-
if (existing.includes(header)) continue;
|
|
33
|
-
}
|
|
34
|
-
toAppend.push(content.trim());
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (toAppend.length === 0) return;
|
|
38
|
-
const appendContent = (existing.endsWith("\n") ? "" : "\n") + toAppend.join("\n\n") + "\n";
|
|
39
|
-
await writeFile(targetClaudeMd, existing + appendContent, "utf-8");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export {
|
|
43
|
-
installRules
|
|
44
|
-
};
|