@juho0719/cckit 0.1.1
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/agents/architect.md +211 -0
- package/assets/agents/build-error-resolver.md +114 -0
- package/assets/agents/ccwin-code-reviewer.md +224 -0
- package/assets/agents/database-reviewer.md +91 -0
- package/assets/agents/doc-updater.md +107 -0
- package/assets/agents/e2e-runner.md +107 -0
- package/assets/agents/planner.md +212 -0
- package/assets/agents/python-reviewer.md +98 -0
- package/assets/agents/refactor-cleaner.md +85 -0
- package/assets/agents/security-reviewer.md +108 -0
- package/assets/agents/superpower-code-reviewer.md +48 -0
- package/assets/agents/tdd-guide.md +80 -0
- package/assets/commands/build-fix.md +62 -0
- package/assets/commands/checkpoint.md +74 -0
- package/assets/commands/code-review.md +40 -0
- package/assets/commands/e2e.md +362 -0
- package/assets/commands/eval.md +120 -0
- package/assets/commands/orchestrate.md +172 -0
- package/assets/commands/plan.md +113 -0
- package/assets/commands/python-review.md +297 -0
- package/assets/commands/refactor-clean.md +80 -0
- package/assets/commands/sessions.md +305 -0
- package/assets/commands/tdd.md +326 -0
- package/assets/commands/test-coverage.md +69 -0
- package/assets/commands/update-codemaps.md +72 -0
- package/assets/commands/update-docs.md +84 -0
- package/assets/commands/verify.md +59 -0
- package/assets/hooks/post-edit-format.js +49 -0
- package/assets/hooks/post-edit-typecheck.js +96 -0
- package/assets/mcps/mcp-servers.json +92 -0
- package/assets/rules/common/agents.md +49 -0
- package/assets/rules/common/coding-style.md +48 -0
- package/assets/rules/common/git-workflow.md +45 -0
- package/assets/rules/common/hooks.md +30 -0
- package/assets/rules/common/patterns.md +31 -0
- package/assets/rules/common/performance.md +55 -0
- package/assets/rules/common/security.md +29 -0
- package/assets/rules/common/testing.md +29 -0
- package/assets/rules/python/coding-style.md +42 -0
- package/assets/rules/python/hooks.md +19 -0
- package/assets/rules/python/patterns.md +39 -0
- package/assets/rules/python/security.md +30 -0
- package/assets/rules/python/testing.md +38 -0
- package/assets/rules/typescript/coding-style.md +18 -0
- package/assets/rules/typescript/hooks.md +19 -0
- package/assets/rules/typescript/patterns.md +39 -0
- package/assets/rules/typescript/security.md +30 -0
- package/assets/rules/typescript/testing.md +38 -0
- package/assets/skills/api-design/SKILL.md +522 -0
- package/assets/skills/backend-patterns/SKILL.md +597 -0
- package/assets/skills/brainstorming/SKILL.md +96 -0
- package/assets/skills/coding-standards/SKILL.md +529 -0
- package/assets/skills/database-migrations/SKILL.md +334 -0
- package/assets/skills/deployment-patterns/SKILL.md +426 -0
- package/assets/skills/dispatching-parallel-agents/SKILL.md +180 -0
- package/assets/skills/docker-patterns/SKILL.md +363 -0
- package/assets/skills/e2e-testing/SKILL.md +325 -0
- package/assets/skills/eval-harness/SKILL.md +235 -0
- package/assets/skills/executing-plans/SKILL.md +84 -0
- package/assets/skills/finishing-a-development-branch/SKILL.md +200 -0
- package/assets/skills/frontend-patterns/SKILL.md +641 -0
- package/assets/skills/iterative-retrieval/SKILL.md +210 -0
- package/assets/skills/postgres-patterns/SKILL.md +145 -0
- package/assets/skills/python-patterns/SKILL.md +749 -0
- package/assets/skills/python-testing/SKILL.md +815 -0
- package/assets/skills/receiving-code-review/SKILL.md +213 -0
- package/assets/skills/requesting-code-review/SKILL.md +105 -0
- package/assets/skills/requesting-code-review/code-reviewer-template.md +146 -0
- package/assets/skills/subagent-driven-development/SKILL.md +242 -0
- package/assets/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
- package/assets/skills/subagent-driven-development/implementer-prompt.md +78 -0
- package/assets/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/assets/skills/systematic-debugging/CREATION-LOG.md +114 -0
- package/assets/skills/systematic-debugging/SKILL.md +296 -0
- package/assets/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/assets/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/assets/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/assets/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/assets/skills/systematic-debugging/scripts/find-polluter.sh +63 -0
- package/assets/skills/systematic-debugging/test-academic.md +14 -0
- package/assets/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/assets/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/assets/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/assets/skills/tdd-workflow/SKILL.md +409 -0
- package/assets/skills/test-driven-development/SKILL.md +371 -0
- package/assets/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/assets/skills/using-git-worktrees/SKILL.md +218 -0
- package/assets/skills/verification-before-completion/SKILL.md +139 -0
- package/assets/skills/verification-loop/SKILL.md +125 -0
- package/assets/skills/writing-plans/SKILL.md +116 -0
- package/dist/agents-AEKT67A6.js +9 -0
- package/dist/chunk-3GUKEMND.js +28 -0
- package/dist/chunk-3UNN3IBE.js +54 -0
- package/dist/chunk-3Y26YU4R.js +27 -0
- package/dist/chunk-5XOKKPAA.js +21 -0
- package/dist/chunk-6B46AIFM.js +136 -0
- package/dist/chunk-EYY2IZ7N.js +27 -0
- package/dist/chunk-K25UZZVG.js +17 -0
- package/dist/chunk-KEENFBLL.js +24 -0
- package/dist/chunk-RMUKD7CW.js +44 -0
- package/dist/chunk-W63UKEIT.js +50 -0
- package/dist/cli-VZRGF733.js +238 -0
- package/dist/commands-P5LILVZ5.js +9 -0
- package/dist/hooks-IIG2XK4I.js +9 -0
- package/dist/index.js +131 -0
- package/dist/mcps-67Q7TBGW.js +6 -0
- package/dist/paths-FT6KBIRD.js +10 -0
- package/dist/registry-EGXWYWWK.js +17 -0
- package/dist/rules-2CPBVNNJ.js +7 -0
- package/dist/skills-ULMW3UCM.js +8 -0
- package/package.json +36 -0
|
@@ -0,0 +1,27 @@
|
|
|
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/commands.ts
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
async function installCommands(commands, targetDir) {
|
|
15
|
+
const destDir = join(targetDir, "commands");
|
|
16
|
+
await ensureDir(destDir);
|
|
17
|
+
const srcDir = join(getAssetsDir(), "commands");
|
|
18
|
+
for (const cmd of commands) {
|
|
19
|
+
const dest = join(destDir, cmd.file);
|
|
20
|
+
await backupIfExists(dest);
|
|
21
|
+
await copyFileUtil(join(srcDir, cmd.file), dest);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
installCommands
|
|
27
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/utils/paths.ts
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
function getGlobalDir() {
|
|
6
|
+
return join(homedir(), ".claude");
|
|
7
|
+
}
|
|
8
|
+
function getProjectDir() {
|
|
9
|
+
return join(process.cwd(), ".claude");
|
|
10
|
+
}
|
|
11
|
+
function getAssetsDir() {
|
|
12
|
+
const __filename2 = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname2 = dirname(__filename2);
|
|
14
|
+
return join(__dirname2, "..", "assets");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
getGlobalDir,
|
|
19
|
+
getProjectDir,
|
|
20
|
+
getAssetsDir
|
|
21
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAssetsDir
|
|
3
|
+
} from "./chunk-5XOKKPAA.js";
|
|
4
|
+
|
|
5
|
+
// src/registry.ts
|
|
6
|
+
import { readFile, readdir } from "fs/promises";
|
|
7
|
+
import { join, basename } from "path";
|
|
8
|
+
function parseFrontmatter(content) {
|
|
9
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
10
|
+
if (!match) return {};
|
|
11
|
+
const result = {};
|
|
12
|
+
for (const line of match[1].split("\n")) {
|
|
13
|
+
const colonIdx = line.indexOf(":");
|
|
14
|
+
if (colonIdx === -1) continue;
|
|
15
|
+
const key = line.slice(0, colonIdx).trim();
|
|
16
|
+
const value = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, "");
|
|
17
|
+
if (key) result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
async function getAgents() {
|
|
22
|
+
const dir = join(getAssetsDir(), "agents");
|
|
23
|
+
const files = (await readdir(dir)).filter((f) => f.endsWith(".md"));
|
|
24
|
+
const items = [];
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const content = await readFile(join(dir, file), "utf-8");
|
|
27
|
+
const fm = parseFrontmatter(content);
|
|
28
|
+
items.push({
|
|
29
|
+
name: fm["name"] || basename(file, ".md"),
|
|
30
|
+
description: fm["description"] || "",
|
|
31
|
+
file
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return items;
|
|
35
|
+
}
|
|
36
|
+
async function getSkills() {
|
|
37
|
+
const dir = join(getAssetsDir(), "skills");
|
|
38
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
39
|
+
const items = [];
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
if (!entry.isDirectory()) continue;
|
|
42
|
+
const skillFile = join(dir, entry.name, "SKILL.md");
|
|
43
|
+
let fm = {};
|
|
44
|
+
try {
|
|
45
|
+
const content = await readFile(skillFile, "utf-8");
|
|
46
|
+
fm = parseFrontmatter(content);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
items.push({
|
|
50
|
+
name: fm["name"] || entry.name,
|
|
51
|
+
description: fm["description"] || "",
|
|
52
|
+
dir: entry.name
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return items;
|
|
56
|
+
}
|
|
57
|
+
async function getCommands() {
|
|
58
|
+
const dir = join(getAssetsDir(), "commands");
|
|
59
|
+
const files = (await readdir(dir)).filter((f) => f.endsWith(".md"));
|
|
60
|
+
const items = [];
|
|
61
|
+
for (const file of files) {
|
|
62
|
+
const content = await readFile(join(dir, file), "utf-8");
|
|
63
|
+
const fm = parseFrontmatter(content);
|
|
64
|
+
const name = fm["name"] || basename(file, ".md");
|
|
65
|
+
items.push({
|
|
66
|
+
name,
|
|
67
|
+
description: fm["description"] || "",
|
|
68
|
+
file
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return items;
|
|
72
|
+
}
|
|
73
|
+
async function getHooks() {
|
|
74
|
+
const dir = join(getAssetsDir(), "hooks");
|
|
75
|
+
const files = (await readdir(dir)).filter((f) => f.endsWith(".js"));
|
|
76
|
+
const items = [];
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const content = await readFile(join(dir, file), "utf-8");
|
|
79
|
+
const descMatch = content.match(/\*\s+PostToolUse Hook:\s*(.+)/);
|
|
80
|
+
const description = descMatch ? descMatch[1].trim() : file;
|
|
81
|
+
const hookType = "PostToolUse";
|
|
82
|
+
let matcher = "Edit";
|
|
83
|
+
if (file.includes("typecheck")) matcher = "Edit|Write";
|
|
84
|
+
if (file.includes("format")) matcher = "Edit|Write";
|
|
85
|
+
items.push({ name: file, description, file, hookType, matcher });
|
|
86
|
+
}
|
|
87
|
+
return items;
|
|
88
|
+
}
|
|
89
|
+
async function getRuleCategories() {
|
|
90
|
+
const dir = join(getAssetsDir(), "rules");
|
|
91
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
92
|
+
const categories = [];
|
|
93
|
+
for (const entry of entries) {
|
|
94
|
+
if (!entry.isDirectory()) continue;
|
|
95
|
+
const catDir = join(dir, entry.name);
|
|
96
|
+
const files = (await readdir(catDir)).filter((f) => f.endsWith(".md"));
|
|
97
|
+
categories.push({ category: entry.name, files });
|
|
98
|
+
}
|
|
99
|
+
return categories;
|
|
100
|
+
}
|
|
101
|
+
async function getMcpServers() {
|
|
102
|
+
const filePath = join(getAssetsDir(), "mcps", "mcp-servers.json");
|
|
103
|
+
const content = await readFile(filePath, "utf-8");
|
|
104
|
+
const json = JSON.parse(content);
|
|
105
|
+
const servers = [];
|
|
106
|
+
for (const [name, cfg] of Object.entries(json.mcpServers)) {
|
|
107
|
+
const type = cfg["type"] === "http" ? "http" : "stdio";
|
|
108
|
+
const description = cfg["description"] || name;
|
|
109
|
+
const envVars = [];
|
|
110
|
+
if (cfg["env"] && typeof cfg["env"] === "object") {
|
|
111
|
+
for (const [k, v] of Object.entries(cfg["env"])) {
|
|
112
|
+
if (typeof v === "string" && v.includes("YOUR_")) {
|
|
113
|
+
envVars.push(k);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (Array.isArray(cfg["args"])) {
|
|
118
|
+
for (const arg of cfg["args"]) {
|
|
119
|
+
if (typeof arg === "string" && arg.includes("YOUR_")) {
|
|
120
|
+
envVars.push(arg);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
servers.push({ name, description, type, envVars, config: cfg });
|
|
125
|
+
}
|
|
126
|
+
return servers;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
getAgents,
|
|
131
|
+
getSkills,
|
|
132
|
+
getCommands,
|
|
133
|
+
getHooks,
|
|
134
|
+
getRuleCategories,
|
|
135
|
+
getMcpServers
|
|
136
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
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/agents.ts
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
async function installAgents(agents, targetDir) {
|
|
15
|
+
const destDir = join(targetDir, "agents");
|
|
16
|
+
await ensureDir(destDir);
|
|
17
|
+
const srcDir = join(getAssetsDir(), "agents");
|
|
18
|
+
for (const agent of agents) {
|
|
19
|
+
const dest = join(destDir, agent.file);
|
|
20
|
+
await backupIfExists(dest);
|
|
21
|
+
await copyFileUtil(join(srcDir, agent.file), dest);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
installAgents
|
|
27
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/utils/backup.ts
|
|
2
|
+
import { copyFile, access } from "fs/promises";
|
|
3
|
+
import { constants } from "fs";
|
|
4
|
+
async function backupFile(filePath) {
|
|
5
|
+
await copyFile(filePath, `${filePath}.bak`);
|
|
6
|
+
}
|
|
7
|
+
async function backupIfExists(filePath) {
|
|
8
|
+
try {
|
|
9
|
+
await access(filePath, constants.F_OK);
|
|
10
|
+
await backupFile(filePath);
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
backupIfExists
|
|
17
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyDir,
|
|
3
|
+
ensureDir
|
|
4
|
+
} from "./chunk-3GUKEMND.js";
|
|
5
|
+
import {
|
|
6
|
+
getAssetsDir
|
|
7
|
+
} from "./chunk-5XOKKPAA.js";
|
|
8
|
+
|
|
9
|
+
// src/installers/skills.ts
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
async function installSkills(skills, targetDir) {
|
|
12
|
+
const destBase = join(targetDir, "skills");
|
|
13
|
+
await ensureDir(destBase);
|
|
14
|
+
const srcBase = join(getAssetsDir(), "skills");
|
|
15
|
+
for (const skill of skills) {
|
|
16
|
+
const src = join(srcBase, skill.dir);
|
|
17
|
+
const dest = join(destBase, skill.dir);
|
|
18
|
+
await copyDir(src, dest);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
installSkills
|
|
24
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/installers/mcps.ts
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { readFile, writeFile, access } from "fs/promises";
|
|
4
|
+
import { constants } from "fs";
|
|
5
|
+
import { homedir } from "os";
|
|
6
|
+
function getClaudeJsonPath(scope) {
|
|
7
|
+
if (scope === "global") {
|
|
8
|
+
return join(homedir(), ".claude.json");
|
|
9
|
+
}
|
|
10
|
+
return join(process.cwd(), ".claude.json");
|
|
11
|
+
}
|
|
12
|
+
async function installMcps(servers, scope, envValues) {
|
|
13
|
+
const filePath = getClaudeJsonPath(scope);
|
|
14
|
+
let claudeJson = {};
|
|
15
|
+
try {
|
|
16
|
+
await access(filePath, constants.F_OK);
|
|
17
|
+
const content = await readFile(filePath, "utf-8");
|
|
18
|
+
claudeJson = JSON.parse(content);
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
if (!claudeJson.mcpServers) claudeJson.mcpServers = {};
|
|
22
|
+
for (const server of servers) {
|
|
23
|
+
if (server.name in claudeJson.mcpServers) continue;
|
|
24
|
+
const cfg = structuredClone(server.config);
|
|
25
|
+
const userEnv = envValues.get(server.name) ?? {};
|
|
26
|
+
if (cfg["env"] && typeof cfg["env"] === "object") {
|
|
27
|
+
const env = cfg["env"];
|
|
28
|
+
for (const [k, v] of Object.entries(env)) {
|
|
29
|
+
if (typeof v === "string" && v.includes("YOUR_") && userEnv[k]) {
|
|
30
|
+
env[k] = userEnv[k];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(cfg["args"])) {
|
|
35
|
+
cfg["args"] = cfg["args"].map((arg) => {
|
|
36
|
+
if (typeof arg === "string" && arg.includes("YOUR_")) {
|
|
37
|
+
return userEnv[arg] ?? arg;
|
|
38
|
+
}
|
|
39
|
+
return arg;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
delete cfg["description"];
|
|
43
|
+
claudeJson.mcpServers[server.name] = cfg;
|
|
44
|
+
}
|
|
45
|
+
await writeFile(filePath, JSON.stringify(claudeJson, null, 2) + "\n", "utf-8");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
installMcps
|
|
50
|
+
};
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
installMcps
|
|
3
|
+
} from "./chunk-W63UKEIT.js";
|
|
4
|
+
import {
|
|
5
|
+
getAgents,
|
|
6
|
+
getCommands,
|
|
7
|
+
getHooks,
|
|
8
|
+
getMcpServers,
|
|
9
|
+
getRuleCategories,
|
|
10
|
+
getSkills
|
|
11
|
+
} from "./chunk-6B46AIFM.js";
|
|
12
|
+
import {
|
|
13
|
+
installAgents
|
|
14
|
+
} from "./chunk-EYY2IZ7N.js";
|
|
15
|
+
import {
|
|
16
|
+
installSkills
|
|
17
|
+
} from "./chunk-KEENFBLL.js";
|
|
18
|
+
import {
|
|
19
|
+
installCommands
|
|
20
|
+
} from "./chunk-3Y26YU4R.js";
|
|
21
|
+
import {
|
|
22
|
+
installHooks
|
|
23
|
+
} from "./chunk-3UNN3IBE.js";
|
|
24
|
+
import "./chunk-K25UZZVG.js";
|
|
25
|
+
import "./chunk-3GUKEMND.js";
|
|
26
|
+
import {
|
|
27
|
+
installRules
|
|
28
|
+
} from "./chunk-RMUKD7CW.js";
|
|
29
|
+
import {
|
|
30
|
+
getGlobalDir,
|
|
31
|
+
getProjectDir
|
|
32
|
+
} from "./chunk-5XOKKPAA.js";
|
|
33
|
+
|
|
34
|
+
// src/cli.ts
|
|
35
|
+
import { checkbox, select, input, confirm } from "@inquirer/prompts";
|
|
36
|
+
import chalk from "chalk";
|
|
37
|
+
import ora from "ora";
|
|
38
|
+
import { join } from "path";
|
|
39
|
+
function printBanner() {
|
|
40
|
+
console.log(
|
|
41
|
+
chalk.cyan.bold(`
|
|
42
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
43
|
+
\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D
|
|
44
|
+
\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
45
|
+
\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
46
|
+
\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
47
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
48
|
+
`)
|
|
49
|
+
);
|
|
50
|
+
console.log(chalk.gray(" Claude Code Harness Installer\n"));
|
|
51
|
+
}
|
|
52
|
+
async function runCli() {
|
|
53
|
+
printBanner();
|
|
54
|
+
const scopeAnswer = await select({
|
|
55
|
+
message: "Install scope:",
|
|
56
|
+
choices: [
|
|
57
|
+
{
|
|
58
|
+
name: `Global ${chalk.gray("~/.claude/")}`,
|
|
59
|
+
value: "global"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: `Project ${chalk.gray("./.claude/")}`,
|
|
63
|
+
value: "project"
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
});
|
|
67
|
+
const scope = scopeAnswer;
|
|
68
|
+
const targetDir = scope === "global" ? getGlobalDir() : getProjectDir();
|
|
69
|
+
const selectedCategories = await checkbox({
|
|
70
|
+
message: "Select categories to install:",
|
|
71
|
+
choices: [
|
|
72
|
+
{ name: "Agents - AI sub-agents", value: "agents" },
|
|
73
|
+
{ name: "Skills - Reusable skill prompts", value: "skills" },
|
|
74
|
+
{ name: "Commands - Slash commands", value: "commands" },
|
|
75
|
+
{ name: "Hooks - Post-tool hooks", value: "hooks" },
|
|
76
|
+
{ name: "Rules - CLAUDE.md rules", value: "rules" },
|
|
77
|
+
{ name: "MCPs - MCP server configs", value: "mcps" }
|
|
78
|
+
]
|
|
79
|
+
});
|
|
80
|
+
if (selectedCategories.length === 0) {
|
|
81
|
+
console.log(chalk.yellow("\nNo categories selected. Exiting."));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const plan = {
|
|
85
|
+
scope,
|
|
86
|
+
agents: [],
|
|
87
|
+
skills: [],
|
|
88
|
+
commands: [],
|
|
89
|
+
hooks: [],
|
|
90
|
+
ruleCategories: [],
|
|
91
|
+
mcps: [],
|
|
92
|
+
mcpEnvValues: /* @__PURE__ */ new Map()
|
|
93
|
+
};
|
|
94
|
+
if (selectedCategories.includes("agents")) {
|
|
95
|
+
const allAgents = await getAgents();
|
|
96
|
+
plan.agents = await checkbox({
|
|
97
|
+
message: "Select agents:",
|
|
98
|
+
choices: allAgents.map((a) => ({
|
|
99
|
+
name: `${chalk.bold(a.name.padEnd(30))} ${chalk.gray(a.description.slice(0, 60))}`,
|
|
100
|
+
value: a,
|
|
101
|
+
checked: false
|
|
102
|
+
}))
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (selectedCategories.includes("skills")) {
|
|
106
|
+
const allSkills = await getSkills();
|
|
107
|
+
plan.skills = await checkbox({
|
|
108
|
+
message: "Select skills:",
|
|
109
|
+
choices: allSkills.map((s) => ({
|
|
110
|
+
name: `${chalk.bold(s.name.padEnd(35))} ${chalk.gray(s.description.slice(0, 55))}`,
|
|
111
|
+
value: s,
|
|
112
|
+
checked: false
|
|
113
|
+
}))
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (selectedCategories.includes("commands")) {
|
|
117
|
+
const allCommands = await getCommands();
|
|
118
|
+
plan.commands = await checkbox({
|
|
119
|
+
message: "Select commands:",
|
|
120
|
+
choices: allCommands.map((c) => ({
|
|
121
|
+
name: `${chalk.bold(c.name.padEnd(25))} ${chalk.gray(c.description.slice(0, 65))}`,
|
|
122
|
+
value: c,
|
|
123
|
+
checked: false
|
|
124
|
+
}))
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (selectedCategories.includes("hooks")) {
|
|
128
|
+
const allHooks = await getHooks();
|
|
129
|
+
plan.hooks = await checkbox({
|
|
130
|
+
message: "Select hooks:",
|
|
131
|
+
choices: allHooks.map((h) => ({
|
|
132
|
+
name: `${chalk.bold(h.name.padEnd(35))} ${chalk.gray(h.description.slice(0, 55))}`,
|
|
133
|
+
value: h,
|
|
134
|
+
checked: false
|
|
135
|
+
}))
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (selectedCategories.includes("rules")) {
|
|
139
|
+
const allCategories = await getRuleCategories();
|
|
140
|
+
plan.ruleCategories = await checkbox({
|
|
141
|
+
message: "Select rule categories:",
|
|
142
|
+
choices: allCategories.map((rc) => ({
|
|
143
|
+
name: `${chalk.bold(rc.category.padEnd(20))} ${chalk.gray(`(${rc.files.length} files)`)}`,
|
|
144
|
+
value: rc.category,
|
|
145
|
+
checked: false
|
|
146
|
+
}))
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (selectedCategories.includes("mcps")) {
|
|
150
|
+
const allMcps = await getMcpServers();
|
|
151
|
+
plan.mcps = await checkbox({
|
|
152
|
+
message: "Select MCP servers:",
|
|
153
|
+
choices: allMcps.map((m) => ({
|
|
154
|
+
name: `${chalk.bold(m.name.padEnd(30))} ${chalk.gray(m.description.slice(0, 55))}`,
|
|
155
|
+
value: m,
|
|
156
|
+
checked: false
|
|
157
|
+
}))
|
|
158
|
+
});
|
|
159
|
+
for (const server of plan.mcps) {
|
|
160
|
+
if (server.type === "http" || server.envVars.length === 0) continue;
|
|
161
|
+
console.log(chalk.yellow(`
|
|
162
|
+
${server.name} requires environment variables:`));
|
|
163
|
+
const envMap = {};
|
|
164
|
+
for (const envKey of server.envVars) {
|
|
165
|
+
const value = await input({
|
|
166
|
+
message: ` ${envKey}:`,
|
|
167
|
+
default: ""
|
|
168
|
+
});
|
|
169
|
+
if (value) envMap[envKey] = value;
|
|
170
|
+
}
|
|
171
|
+
plan.mcpEnvValues.set(server.name, envMap);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
console.log(chalk.bold("\n Installation Summary"));
|
|
175
|
+
console.log(chalk.gray(" \u2500".repeat(40)));
|
|
176
|
+
console.log(` Scope : ${chalk.cyan(scope)} (${targetDir})`);
|
|
177
|
+
if (plan.agents.length) console.log(` Agents : ${plan.agents.map((a) => a.name).join(", ")}`);
|
|
178
|
+
if (plan.skills.length) console.log(` Skills : ${plan.skills.map((s) => s.name).join(", ")}`);
|
|
179
|
+
if (plan.commands.length) console.log(` Commands: ${plan.commands.map((c) => c.name).join(", ")}`);
|
|
180
|
+
if (plan.hooks.length) console.log(` Hooks : ${plan.hooks.map((h) => h.name).join(", ")}`);
|
|
181
|
+
if (plan.ruleCategories.length) console.log(` Rules : ${plan.ruleCategories.join(", ")}`);
|
|
182
|
+
if (plan.mcps.length) console.log(` MCPs : ${plan.mcps.map((m) => m.name).join(", ")}`);
|
|
183
|
+
console.log("");
|
|
184
|
+
const totalItems = plan.agents.length + plan.skills.length + plan.commands.length + plan.hooks.length + plan.ruleCategories.length + plan.mcps.length;
|
|
185
|
+
if (totalItems === 0) {
|
|
186
|
+
console.log(chalk.yellow(" Nothing selected. Exiting."));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const ok = await confirm({ message: "Proceed with installation?", default: true });
|
|
190
|
+
if (!ok) {
|
|
191
|
+
console.log(chalk.yellow("\n Aborted."));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
console.log("");
|
|
195
|
+
const spinner = ora("Installing...").start();
|
|
196
|
+
try {
|
|
197
|
+
if (plan.agents.length) {
|
|
198
|
+
spinner.text = "Installing agents...";
|
|
199
|
+
await installAgents(plan.agents, targetDir);
|
|
200
|
+
}
|
|
201
|
+
if (plan.skills.length) {
|
|
202
|
+
spinner.text = "Installing skills...";
|
|
203
|
+
await installSkills(plan.skills, targetDir);
|
|
204
|
+
}
|
|
205
|
+
if (plan.commands.length) {
|
|
206
|
+
spinner.text = "Installing commands...";
|
|
207
|
+
await installCommands(plan.commands, targetDir);
|
|
208
|
+
}
|
|
209
|
+
if (plan.hooks.length) {
|
|
210
|
+
spinner.text = "Installing hooks...";
|
|
211
|
+
await installHooks(plan.hooks, targetDir);
|
|
212
|
+
}
|
|
213
|
+
if (plan.ruleCategories.length) {
|
|
214
|
+
spinner.text = "Installing rules...";
|
|
215
|
+
const claudeMd = join(targetDir, "CLAUDE.md");
|
|
216
|
+
await installRules(plan.ruleCategories, claudeMd);
|
|
217
|
+
}
|
|
218
|
+
if (plan.mcps.length) {
|
|
219
|
+
spinner.text = "Installing MCP servers...";
|
|
220
|
+
await installMcps(plan.mcps, plan.scope, plan.mcpEnvValues);
|
|
221
|
+
}
|
|
222
|
+
spinner.succeed(chalk.green("Installation complete!"));
|
|
223
|
+
console.log("");
|
|
224
|
+
if (plan.agents.length) console.log(` ${chalk.green("\u2713")} ${plan.agents.length} agent(s) \u2192 ${join(targetDir, "agents")}`);
|
|
225
|
+
if (plan.skills.length) console.log(` ${chalk.green("\u2713")} ${plan.skills.length} skill(s) \u2192 ${join(targetDir, "skills")}`);
|
|
226
|
+
if (plan.commands.length) console.log(` ${chalk.green("\u2713")} ${plan.commands.length} command(s) \u2192 ${join(targetDir, "commands")}`);
|
|
227
|
+
if (plan.hooks.length) console.log(` ${chalk.green("\u2713")} ${plan.hooks.length} hook(s) \u2192 ${join(targetDir, "hooks")}`);
|
|
228
|
+
if (plan.ruleCategories.length) console.log(` ${chalk.green("\u2713")} Rules appended \u2192 ${join(targetDir, "CLAUDE.md")}`);
|
|
229
|
+
if (plan.mcps.length) console.log(` ${chalk.green("\u2713")} ${plan.mcps.length} MCP server(s) \u2192 ${scope === "global" ? "~/.claude.json" : "./.claude.json"}`);
|
|
230
|
+
console.log("");
|
|
231
|
+
} catch (err) {
|
|
232
|
+
spinner.fail(chalk.red("Installation failed"));
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
export {
|
|
237
|
+
runCli
|
|
238
|
+
};
|