@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.
@@ -44,6 +44,5 @@ process.stdin.on('end', () => {
44
44
  // Invalid input — pass through
45
45
  }
46
46
 
47
- process.stdout.write(data);
48
47
  process.exit(0);
49
48
  });
@@ -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 ${dest}`;
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-3UNN3IBE.js";
28
- import "./chunk-K25UZZVG.js";
29
- import "./chunk-3GUKEMND.js";
27
+ } from "./chunk-SLVASXTF.js";
30
28
  import {
31
29
  installRules
32
- } from "./chunk-RMUKD7CW.js";
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
- const claudeMd = join(targetDir, "CLAUDE.md");
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 appended \u2192 ${join(targetDir, "CLAUDE.md")}`);
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("");
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  installHooks
3
- } from "./chunk-3UNN3IBE.js";
3
+ } from "./chunk-SLVASXTF.js";
4
4
  import "./chunk-K25UZZVG.js";
5
5
  import "./chunk-3GUKEMND.js";
6
6
  import "./chunk-5XOKKPAA.js";
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-IIG2XK4I.js"),
74
- import("./rules-2CPBVNNJ.js"),
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
- const claudeMd = join2(targetDir, "CLAUDE.md");
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-VCOZGDBM.js");
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-D2Q5QUO7.js");
137
+ const { runCli } = await import("./cli-6WQMAFNA.js");
139
138
  await runCli();
140
139
  }
141
140
  main().catch((err) => {
@@ -0,0 +1,9 @@
1
+ import {
2
+ installRules
3
+ } from "./chunk-ID643AV4.js";
4
+ import "./chunk-K25UZZVG.js";
5
+ import "./chunk-3GUKEMND.js";
6
+ import "./chunk-5XOKKPAA.js";
7
+ export {
8
+ installRules
9
+ };
@@ -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 claudeMdPath = join(targetDir, "CLAUDE.md");
80
- let content = "";
78
+ const rulesDir = join(targetDir, "rules");
79
+ let installedDirs = [];
81
80
  try {
82
- await access(claudeMdPath, constants.F_OK);
83
- content = await readFile(claudeMdPath, "utf-8");
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 installedCategories = [];
94
- for (const rc of allCategories) {
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, hookCommand) {
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 !== hookCommand);
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
- const hookCommand = `node ${filePath}`;
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 { readFile as readFile3, writeFile as writeFile2, access as access6 } from "fs/promises";
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, claudeMdPath) {
257
- let existing = "";
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 catDir = join6(getAssetsDir(), "rules", category);
267
- let files;
236
+ const srcCatDir = join6(assetsRulesDir, category);
237
+ let assetFiles;
268
238
  try {
269
- const { readdir: readdir2 } = await import("fs/promises");
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
- for (const file of files) {
243
+ const destCatDir = join6(targetDir, "rules", category);
244
+ for (const file of assetFiles) {
275
245
  try {
276
- const content = await readFile3(join6(catDir, file), "utf-8");
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
- if (headersToRemove.size === 0) return;
286
- const lines = existing.split("\n");
287
- const result = [];
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
- if (!inRemovedSection) {
305
- result.push(line);
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 readFile4, writeFile as writeFile3, access as access7 } from "fs/promises";
315
- import { constants as constants7 } from "fs";
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 access7(filePath, constants7.F_OK);
328
- const content = await readFile4(filePath, "utf-8");
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 writeFile3(filePath, JSON.stringify(claudeJson, null, 2) + "\n", "utf-8");
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 readFile5, writeFile as writeFile4, access as access8 } from "fs/promises";
342
- import { constants as constants8 } from "fs";
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 access8(claudeMdPath, constants8.F_OK);
349
- existing = await readFile5(claudeMdPath, "utf-8");
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 readFile5(join8(getAssetsDir(), "claudemd", item.file), "utf-8");
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 writeFile4(claudeMdPath, cleaned, "utf-8");
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
- const claudeMd = join9(targetDir, "CLAUDE.md");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juho0719/cckit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Claude Code Harness Installer - Interactive CLI for installing Claude Code agents, skills, commands, hooks, rules, and MCP servers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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
- };
@@ -1,7 +0,0 @@
1
- import {
2
- installRules
3
- } from "./chunk-RMUKD7CW.js";
4
- import "./chunk-5XOKKPAA.js";
5
- export {
6
- installRules
7
- };