ccjk 9.5.6 → 9.7.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.
Files changed (103) hide show
  1. package/dist/chunks/agent.mjs +1 -1
  2. package/dist/chunks/api-providers.mjs +1 -1
  3. package/dist/chunks/api.mjs +3 -3
  4. package/dist/chunks/auto-bootstrap.mjs +1 -1
  5. package/dist/chunks/auto-updater.mjs +1 -1
  6. package/dist/chunks/boost.mjs +160 -0
  7. package/dist/chunks/ccjk-agents.mjs +1 -1
  8. package/dist/chunks/ccjk-all.mjs +1 -1
  9. package/dist/chunks/ccjk-config.mjs +1 -1
  10. package/dist/chunks/ccjk-hooks.mjs +1 -1
  11. package/dist/chunks/ccjk-mcp.mjs +2 -2
  12. package/dist/chunks/ccjk-setup.mjs +1 -1
  13. package/dist/chunks/ccjk-skills.mjs +1 -1
  14. package/dist/chunks/ccr.mjs +25 -30
  15. package/dist/chunks/ccu.mjs +1 -1
  16. package/dist/chunks/check-updates.mjs +3 -4
  17. package/dist/chunks/claude-code-config-manager.mjs +7 -7
  18. package/dist/chunks/claude-code-incremental-manager.mjs +2 -2
  19. package/dist/chunks/claude-config.mjs +4 -4
  20. package/dist/chunks/claude-wrapper.mjs +2 -2
  21. package/dist/chunks/codex-config-switch.mjs +4 -5
  22. package/dist/chunks/codex-provider-manager.mjs +2 -3
  23. package/dist/chunks/codex-uninstaller.mjs +2 -2
  24. package/dist/chunks/codex.mjs +207 -6
  25. package/dist/chunks/commands.mjs +391 -88
  26. package/dist/chunks/commands2.mjs +88 -391
  27. package/dist/chunks/completion.mjs +1 -1
  28. package/dist/chunks/config-consolidator.mjs +2 -2
  29. package/dist/chunks/config-switch.mjs +3 -4
  30. package/dist/chunks/config.mjs +78 -7
  31. package/dist/chunks/config2.mjs +400 -410
  32. package/dist/chunks/config3.mjs +410 -400
  33. package/dist/chunks/constants.mjs +1 -1
  34. package/dist/chunks/doctor.mjs +4 -4
  35. package/dist/chunks/features.mjs +24 -17
  36. package/dist/chunks/index.mjs +178 -7
  37. package/dist/chunks/index2.mjs +1162 -169
  38. package/dist/chunks/index3.mjs +910 -1076
  39. package/dist/chunks/index4.mjs +137 -947
  40. package/dist/chunks/index5.mjs +635 -167
  41. package/dist/chunks/init.mjs +141 -99
  42. package/dist/chunks/installer.mjs +147 -649
  43. package/dist/chunks/installer2.mjs +649 -147
  44. package/dist/chunks/interview.mjs +2 -2
  45. package/dist/chunks/marketplace.mjs +1 -1
  46. package/dist/chunks/mcp.mjs +1058 -17
  47. package/dist/chunks/menu.mjs +147 -56
  48. package/dist/chunks/monitor.mjs +2 -2
  49. package/dist/chunks/notification.mjs +1 -1
  50. package/dist/chunks/onboarding.mjs +2 -2
  51. package/dist/chunks/package.mjs +2 -210
  52. package/dist/chunks/permission-manager.mjs +2 -2
  53. package/dist/chunks/permissions.mjs +1 -1
  54. package/dist/chunks/platform.mjs +1 -1
  55. package/dist/chunks/plugin.mjs +1 -1
  56. package/dist/chunks/prompts.mjs +1 -1
  57. package/dist/chunks/providers.mjs +1 -1
  58. package/dist/chunks/quick-setup.mjs +16 -20
  59. package/dist/chunks/silent-updater.mjs +1 -1
  60. package/dist/chunks/simple-config.mjs +2 -2
  61. package/dist/chunks/skill.mjs +1 -1
  62. package/dist/chunks/skills-sync.mjs +1 -1
  63. package/dist/chunks/skills.mjs +1 -1
  64. package/dist/chunks/startup.mjs +1 -1
  65. package/dist/chunks/stats.mjs +1 -1
  66. package/dist/chunks/status.mjs +159 -0
  67. package/dist/chunks/team.mjs +1 -1
  68. package/dist/chunks/thinking.mjs +2 -2
  69. package/dist/chunks/uninstall.mjs +6 -6
  70. package/dist/chunks/update.mjs +6 -9
  71. package/dist/chunks/upgrade-manager.mjs +2 -2
  72. package/dist/chunks/version-checker.mjs +3 -3
  73. package/dist/chunks/vim.mjs +1 -1
  74. package/dist/chunks/workflows.mjs +616 -215
  75. package/dist/cli.mjs +70 -121
  76. package/dist/index.d.mts +17 -1482
  77. package/dist/index.d.ts +17 -1482
  78. package/dist/index.mjs +950 -4740
  79. package/dist/shared/{ccjk.zCqdxT2Y.mjs → ccjk.Br91zBIG.mjs} +2 -2
  80. package/dist/shared/ccjk.CSkyCZIM.mjs +638 -0
  81. package/dist/shared/{ccjk.BKoi8-Hy.mjs → ccjk.DE91nClQ.mjs} +1 -1
  82. package/dist/shared/{ccjk.f40us0yY.mjs → ccjk.DvIrK0wz.mjs} +2 -2
  83. package/dist/shared/ccjk.LsPZ2PYo.mjs +1048 -0
  84. package/dist/shared/{ccjk.DRweXU5F.mjs → ccjk.q1koQxEE.mjs} +2 -2
  85. package/package.json +1 -1
  86. package/templates/claude-code/common/settings.json +15 -111
  87. package/dist/chunks/api-adapter.mjs +0 -180
  88. package/dist/chunks/cli.mjs +0 -2227
  89. package/dist/chunks/context-menu.mjs +0 -913
  90. package/dist/chunks/hooks-sync.mjs +0 -1627
  91. package/dist/chunks/index6.mjs +0 -663
  92. package/dist/chunks/mcp-market.mjs +0 -1077
  93. package/dist/chunks/mcp-server.mjs +0 -776
  94. package/dist/chunks/project-detector.mjs +0 -131
  95. package/dist/chunks/provider-registry.mjs +0 -92
  96. package/dist/chunks/setup-wizard.mjs +0 -362
  97. package/dist/chunks/tools.mjs +0 -143
  98. package/dist/chunks/workflows2.mjs +0 -633
  99. package/dist/shared/ccjk.BM_HZogn.mjs +0 -347
  100. package/dist/shared/ccjk.BaEp4UHQ.mjs +0 -75
  101. package/dist/shared/ccjk.CS0ybJCf.mjs +0 -490
  102. package/dist/shared/ccjk.CZgIwikC.mjs +0 -209
  103. package/dist/shared/ccjk.tO8zeFh1.mjs +0 -397
@@ -1,6 +1,6 @@
1
1
  import ansis from 'ansis';
2
2
  import { homepage, version } from '../chunks/package.mjs';
3
- import { ensureI18nInitialized, i18n } from '../chunks/index2.mjs';
3
+ import { ensureI18nInitialized, i18n } from '../chunks/index.mjs';
4
4
 
5
5
  const theme = {
6
6
  // === Core Colors ===
@@ -135,4 +135,4 @@ const STATUS = {
135
135
  inProgress: status.work
136
136
  };
137
137
 
138
- export { STATUS as S, displayBannerWithInfo as a, boxify as b, displayBanner as d, padToDisplayWidth as p, theme as t };
138
+ export { STATUS as S, displayBanner as a, boxify as b, displayBannerWithInfo as d, padToDisplayWidth as p, theme as t };
@@ -0,0 +1,638 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import process__default from 'node:process';
3
+ import { join } from 'pathe';
4
+ import { SETTINGS_FILE, CLAUDE_AGENTS_DIR, CCJK_SKILLS_DIR } from '../chunks/constants.mjs';
5
+
6
+ function analyzeProject(root) {
7
+ const cwd = process__default.cwd();
8
+ const profile = {
9
+ language: "unknown",
10
+ frameworks: [],
11
+ packageManager: "unknown",
12
+ hasCI: false,
13
+ hasDocker: false,
14
+ hasMCP: false,
15
+ hasClaudeMd: false,
16
+ isMonorepo: false,
17
+ tags: []
18
+ };
19
+ const pkgPath = join(cwd, "package.json");
20
+ let pkg = null;
21
+ if (existsSync(pkgPath)) {
22
+ try {
23
+ pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
24
+ profile.projectName = pkg?.name;
25
+ } catch {
26
+ }
27
+ }
28
+ profile.language = detectLanguage(cwd, pkg);
29
+ profile.packageManager = detectPackageManager(cwd);
30
+ profile.frameworks = detectFrameworks(cwd, pkg);
31
+ profile.testFramework = detectTestFramework(cwd, pkg);
32
+ profile.buildTool = detectBuildTool(cwd, pkg);
33
+ profile.hasCI = existsSync(join(cwd, ".github/workflows")) || existsSync(join(cwd, ".gitlab-ci.yml")) || existsSync(join(cwd, ".circleci")) || existsSync(join(cwd, "Jenkinsfile"));
34
+ profile.hasDocker = existsSync(join(cwd, "Dockerfile")) || existsSync(join(cwd, "docker-compose.yml")) || existsSync(join(cwd, "docker-compose.yaml"));
35
+ profile.hasMCP = checkMcpConfigured();
36
+ profile.hasClaudeMd = existsSync(join(cwd, "CLAUDE.md"));
37
+ profile.isMonorepo = existsSync(join(cwd, "pnpm-workspace.yaml")) || existsSync(join(cwd, "lerna.json")) || pkg?.workspaces != null;
38
+ profile.tags = generateTags(profile);
39
+ return profile;
40
+ }
41
+ function detectLanguage(cwd, pkg) {
42
+ if (existsSync(join(cwd, "tsconfig.json")) || pkg?.devDependencies?.typescript) return "typescript";
43
+ if (existsSync(join(cwd, "pyproject.toml")) || existsSync(join(cwd, "setup.py"))) return "python";
44
+ if (existsSync(join(cwd, "go.mod"))) return "go";
45
+ if (existsSync(join(cwd, "Cargo.toml"))) return "rust";
46
+ if (existsSync(join(cwd, "Gemfile"))) return "ruby";
47
+ if (existsSync(join(cwd, "pom.xml")) || existsSync(join(cwd, "build.gradle"))) return "java";
48
+ if (existsSync(join(cwd, "Package.swift"))) return "swift";
49
+ if (pkg) return "javascript";
50
+ return "unknown";
51
+ }
52
+ function detectPackageManager(cwd) {
53
+ if (existsSync(join(cwd, "pnpm-lock.yaml")) || existsSync(join(cwd, "pnpm-workspace.yaml"))) return "pnpm";
54
+ if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
55
+ if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock"))) return "bun";
56
+ if (existsSync(join(cwd, "package-lock.json"))) return "npm";
57
+ return "unknown";
58
+ }
59
+ function detectFrameworks(_cwd, pkg) {
60
+ const frameworks = [];
61
+ const allDeps = { ...pkg?.dependencies, ...pkg?.devDependencies };
62
+ if (allDeps?.react || allDeps?.["react-dom"]) frameworks.push("react");
63
+ if (allDeps?.vue) frameworks.push("vue");
64
+ if (allDeps?.svelte) frameworks.push("svelte");
65
+ if (allDeps?.angular || allDeps?.["@angular/core"]) frameworks.push("angular");
66
+ if (allDeps?.next) frameworks.push("nextjs");
67
+ if (allDeps?.nuxt) frameworks.push("nuxt");
68
+ if (allDeps?.astro) frameworks.push("astro");
69
+ if (allDeps?.express) frameworks.push("express");
70
+ if (allDeps?.fastify) frameworks.push("fastify");
71
+ if (allDeps?.koa) frameworks.push("koa");
72
+ if (allDeps?.hono) frameworks.push("hono");
73
+ if (allDeps?.["@nestjs/core"]) frameworks.push("nestjs");
74
+ if (allDeps?.electron) frameworks.push("electron");
75
+ if (allDeps?.["@tauri-apps/api"]) frameworks.push("tauri");
76
+ if (allDeps?.["react-native"]) frameworks.push("react-native");
77
+ if (allDeps?.cac || allDeps?.commander || allDeps?.yargs) frameworks.push("cli");
78
+ return frameworks;
79
+ }
80
+ function detectTestFramework(cwd, pkg) {
81
+ const allDeps = { ...pkg?.dependencies, ...pkg?.devDependencies };
82
+ if (allDeps?.vitest || existsSync(join(cwd, "vitest.config.ts"))) return "vitest";
83
+ if (allDeps?.jest || existsSync(join(cwd, "jest.config.js"))) return "jest";
84
+ if (allDeps?.mocha) return "mocha";
85
+ if (allDeps?.playwright || allDeps?.["@playwright/test"]) return "playwright";
86
+ if (allDeps?.cypress) return "cypress";
87
+ if (existsSync(join(cwd, "pytest.ini")) || existsSync(join(cwd, "conftest.py"))) return "pytest";
88
+ return void 0;
89
+ }
90
+ function detectBuildTool(cwd, pkg) {
91
+ const allDeps = { ...pkg?.dependencies, ...pkg?.devDependencies };
92
+ if (allDeps?.vite || existsSync(join(cwd, "vite.config.ts"))) return "vite";
93
+ if (allDeps?.webpack) return "webpack";
94
+ if (allDeps?.esbuild) return "esbuild";
95
+ if (allDeps?.unbuild) return "unbuild";
96
+ if (allDeps?.rollup) return "rollup";
97
+ if (allDeps?.turbo || existsSync(join(cwd, "turbo.json"))) return "turbo";
98
+ return void 0;
99
+ }
100
+ function checkMcpConfigured() {
101
+ try {
102
+ if (!existsSync(SETTINGS_FILE)) return false;
103
+ const settings = JSON.parse(readFileSync(SETTINGS_FILE, "utf-8"));
104
+ return Object.keys(settings.mcpServers || {}).length > 0;
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
109
+ function generateTags(profile) {
110
+ const tags = [];
111
+ tags.push(profile.language);
112
+ tags.push(...profile.frameworks);
113
+ if (profile.testFramework) tags.push(profile.testFramework);
114
+ if (profile.buildTool) tags.push(profile.buildTool);
115
+ if (profile.packageManager !== "unknown") tags.push(profile.packageManager);
116
+ if (profile.hasCI) tags.push("ci");
117
+ if (profile.hasDocker) tags.push("docker");
118
+ if (profile.isMonorepo) tags.push("monorepo");
119
+ if (profile.frameworks.some((f) => ["react", "vue", "svelte", "angular"].includes(f))) tags.push("frontend");
120
+ if (profile.frameworks.some((f) => ["express", "fastify", "koa", "nestjs", "hono"].includes(f))) tags.push("backend");
121
+ if (profile.frameworks.some((f) => ["nextjs", "nuxt", "astro"].includes(f))) tags.push("fullstack");
122
+ if (profile.frameworks.includes("cli")) tags.push("cli-tool");
123
+ return [...new Set(tags)];
124
+ }
125
+
126
+ const SKILL_RULES = [
127
+ {
128
+ tags: ["typescript", "javascript", "python", "go", "rust", "ruby", "java"],
129
+ skill: { id: "git-commit", name: "Smart Git Commit", description: "AI-powered conventional commit messages", reason: "Every project needs good commits", category: "git" }
130
+ },
131
+ {
132
+ tags: ["typescript", "javascript", "python", "go", "rust"],
133
+ skill: { id: "code-review", name: "Code Review", description: "Two-phase deep code review", reason: "Catch bugs before they ship", category: "review" }
134
+ },
135
+ {
136
+ tags: ["react", "vue", "svelte", "angular", "frontend"],
137
+ skill: { id: "component-gen", name: "Component Generator", description: "Generate UI components with tests", reason: "Frontend framework detected", category: "dev" }
138
+ },
139
+ {
140
+ tags: ["express", "fastify", "koa", "nestjs", "hono", "backend"],
141
+ skill: { id: "api-design", name: "API Design", description: "Design RESTful/GraphQL APIs", reason: "Backend framework detected", category: "dev" }
142
+ },
143
+ {
144
+ tags: ["backend", "fullstack"],
145
+ skill: { id: "security-audit", name: "Security Audit", description: "Check for common vulnerabilities", reason: "Server-side code needs security review", category: "review" }
146
+ },
147
+ {
148
+ tags: ["vitest", "jest", "pytest", "mocha"],
149
+ skill: { id: "tdd-workflow", name: "TDD Workflow", description: "Test-driven development cycle", reason: "Test framework detected", category: "testing" }
150
+ },
151
+ {
152
+ tags: ["playwright", "cypress"],
153
+ skill: { id: "e2e-helper", name: "E2E Test Helper", description: "Generate end-to-end tests", reason: "E2E framework detected", category: "testing" }
154
+ },
155
+ {
156
+ tags: ["docker"],
157
+ skill: { id: "docker-optimize", name: "Docker Optimizer", description: "Optimize Dockerfile", reason: "Docker detected", category: "devops" }
158
+ },
159
+ {
160
+ tags: ["ci"],
161
+ skill: { id: "ci-pipeline", name: "CI Pipeline", description: "Optimize CI/CD pipeline", reason: "CI configuration detected", category: "devops" }
162
+ },
163
+ {
164
+ tags: ["cli-tool", "cli"],
165
+ skill: { id: "cli-ux", name: "CLI UX Design", description: "Better CLI interfaces", reason: "CLI tool detected", category: "dev" }
166
+ },
167
+ {
168
+ tags: ["monorepo"],
169
+ skill: { id: "monorepo-manage", name: "Monorepo Manager", description: "Manage packages and releases", reason: "Monorepo detected", category: "dev" }
170
+ },
171
+ {
172
+ tags: ["typescript", "javascript", "python"],
173
+ skill: { id: "doc-gen", name: "Documentation Generator", description: "Generate API docs and README", reason: "Good docs improve maintainability", category: "docs" }
174
+ },
175
+ {
176
+ tags: ["react", "vue", "nextjs", "nuxt", "frontend"],
177
+ skill: { id: "perf-audit", name: "Performance Audit", description: "Bundle size and Core Web Vitals", reason: "Frontend performance matters", category: "review" }
178
+ },
179
+ {
180
+ tags: ["nextjs", "nuxt", "astro", "fullstack"],
181
+ skill: { id: "fullstack-debug", name: "Fullstack Debugger", description: "Debug across client/server boundary", reason: "Fullstack framework detected", category: "debug" }
182
+ }
183
+ ];
184
+ const MCP_RULES = [
185
+ {
186
+ tags: ["typescript", "javascript", "python", "go", "rust", "ruby", "java"],
187
+ mcp: { id: "context7", name: "Context7", description: "Up-to-date library docs", reason: "Essential for accurate API usage" }
188
+ },
189
+ {
190
+ tags: ["playwright", "frontend", "fullstack"],
191
+ mcp: { id: "playwright", name: "Playwright MCP", description: "Browser automation", reason: "Frontend/E2E project detected" }
192
+ },
193
+ {
194
+ tags: ["backend", "fullstack", "express", "fastify", "nestjs"],
195
+ mcp: { id: "sqlite", name: "SQLite MCP", description: "Local database", reason: "Backend project detected" }
196
+ },
197
+ {
198
+ tags: ["typescript", "javascript", "python", "go", "rust"],
199
+ mcp: { id: "mcp-search", name: "Web Search", description: "Search for docs and solutions", reason: "Quick access to online resources" }
200
+ }
201
+ ];
202
+ function matchSkills(profile) {
203
+ const results = [];
204
+ const seen = /* @__PURE__ */ new Set();
205
+ for (const rule of SKILL_RULES) {
206
+ if (seen.has(rule.skill.id)) continue;
207
+ const matchingTags = rule.tags.filter((t) => profile.tags.includes(t));
208
+ if (matchingTags.length === 0) continue;
209
+ const matchScore = Math.min(100, Math.round(matchingTags.length / rule.tags.length * 100) + 20);
210
+ results.push({ ...rule.skill, matchScore });
211
+ seen.add(rule.skill.id);
212
+ }
213
+ results.sort((a, b) => b.matchScore - a.matchScore);
214
+ return results;
215
+ }
216
+ function matchMcpServices(profile) {
217
+ const results = [];
218
+ const seen = /* @__PURE__ */ new Set();
219
+ for (const rule of MCP_RULES) {
220
+ if (seen.has(rule.mcp.id)) continue;
221
+ const matchingTags = rule.tags.filter((t) => profile.tags.includes(t));
222
+ if (matchingTags.length === 0) continue;
223
+ const matchScore = Math.min(100, Math.round(matchingTags.length / rule.tags.length * 100) + 20);
224
+ results.push({ ...rule.mcp, matchScore });
225
+ seen.add(rule.mcp.id);
226
+ }
227
+ results.sort((a, b) => b.matchScore - a.matchScore);
228
+ return results;
229
+ }
230
+ function getRecommendations(profile) {
231
+ const skills = matchSkills(profile);
232
+ const mcpServices = matchMcpServices(profile);
233
+ const parts = [];
234
+ if (profile.language !== "unknown") parts.push(profile.language);
235
+ parts.push(...profile.frameworks.slice(0, 3));
236
+ const stackDesc = parts.join(" + ") || "your project";
237
+ return {
238
+ skills,
239
+ mcpServices,
240
+ summary: `Found ${skills.length} skills and ${mcpServices.length} MCP services for ${stackDesc}`
241
+ };
242
+ }
243
+
244
+ const agentsCheck = {
245
+ name: "Agents",
246
+ weight: 4,
247
+ async check() {
248
+ try {
249
+ if (!existsSync(CLAUDE_AGENTS_DIR)) {
250
+ return {
251
+ name: this.name,
252
+ status: "warn",
253
+ score: 30,
254
+ weight: this.weight,
255
+ message: "No agents directory",
256
+ fix: "Create agents for specialized tasks",
257
+ command: "ccjk ccjk:agents --list"
258
+ };
259
+ }
260
+ const files = readdirSync(CLAUDE_AGENTS_DIR).filter((f) => f.endsWith(".md"));
261
+ const agentCount = files.length;
262
+ if (agentCount === 0) {
263
+ return {
264
+ name: this.name,
265
+ status: "warn",
266
+ score: 30,
267
+ weight: this.weight,
268
+ message: "No agents configured",
269
+ fix: "Create agents for your project",
270
+ command: "ccjk ccjk:agents"
271
+ };
272
+ }
273
+ const score = Math.min(100, 40 + agentCount * 15);
274
+ return {
275
+ name: this.name,
276
+ status: score >= 60 ? "pass" : "warn",
277
+ score,
278
+ weight: this.weight,
279
+ message: `${agentCount} agent${agentCount > 1 ? "s" : ""} configured`,
280
+ details: files.slice(0, 5).map((f) => ` ${f.replace(".md", "")}`)
281
+ };
282
+ } catch {
283
+ return { name: this.name, status: "fail", score: 0, weight: this.weight, message: "Failed to read agents" };
284
+ }
285
+ }
286
+ };
287
+
288
+ const claudeMdCheck = {
289
+ name: "CLAUDE.md",
290
+ weight: 7,
291
+ async check() {
292
+ const cwd = process.cwd();
293
+ const claudeMdPath = join(cwd, "CLAUDE.md");
294
+ try {
295
+ if (!existsSync(claudeMdPath)) {
296
+ return {
297
+ name: this.name,
298
+ status: "fail",
299
+ score: 0,
300
+ weight: this.weight,
301
+ message: "No CLAUDE.md in project root",
302
+ fix: "Create CLAUDE.md for project-specific AI instructions",
303
+ command: "ccjk init --smart"
304
+ };
305
+ }
306
+ const stat = statSync(claudeMdPath);
307
+ const content = readFileSync(claudeMdPath, "utf-8");
308
+ const lines = content.split("\n").length;
309
+ const sizeKb = Math.round(stat.size / 1024);
310
+ const hasHeaders = (content.match(/^#{1,3}\s/gm) || []).length;
311
+ const hasCodeBlocks = (content.match(/```/g) || []).length / 2;
312
+ const hasBuildCommands = /build|test|lint|dev/i.test(content);
313
+ let score = 40;
314
+ if (lines > 20) score += 15;
315
+ if (hasHeaders >= 3) score += 15;
316
+ if (hasCodeBlocks >= 1) score += 10;
317
+ if (hasBuildCommands) score += 20;
318
+ score = Math.min(100, score);
319
+ return {
320
+ name: this.name,
321
+ status: score >= 60 ? "pass" : "warn",
322
+ score,
323
+ weight: this.weight,
324
+ message: `${lines} lines, ${sizeKb}KB`,
325
+ details: [
326
+ ` Sections: ${hasHeaders}`,
327
+ ` Code blocks: ${Math.floor(hasCodeBlocks)}`,
328
+ ` Build info: ${hasBuildCommands ? "yes" : "no"}`
329
+ ],
330
+ ...score < 80 && { fix: "Enrich CLAUDE.md with more project context", command: "ccjk init --smart" }
331
+ };
332
+ } catch {
333
+ return { name: this.name, status: "fail", score: 0, weight: this.weight, message: "Failed to read CLAUDE.md" };
334
+ }
335
+ }
336
+ };
337
+
338
+ const mcpCheck = {
339
+ name: "MCP Services",
340
+ weight: 8,
341
+ async check() {
342
+ try {
343
+ if (!existsSync(SETTINGS_FILE)) {
344
+ return {
345
+ name: this.name,
346
+ status: "fail",
347
+ score: 0,
348
+ weight: this.weight,
349
+ message: "No settings.json found",
350
+ fix: "Run ccjk init to create settings",
351
+ command: "ccjk init"
352
+ };
353
+ }
354
+ const settings = JSON.parse(readFileSync(SETTINGS_FILE, "utf-8"));
355
+ const mcpServers = settings.mcpServers || {};
356
+ const serverCount = Object.keys(mcpServers).length;
357
+ if (serverCount === 0) {
358
+ return {
359
+ name: this.name,
360
+ status: "fail",
361
+ score: 0,
362
+ weight: this.weight,
363
+ message: "No MCP services configured",
364
+ fix: "Install MCP services for enhanced capabilities",
365
+ command: "ccjk ccjk:mcp"
366
+ };
367
+ }
368
+ const essentialServices = ["context7"];
369
+ const hasEssentials = essentialServices.filter(
370
+ (s) => Object.keys(mcpServers).some((k) => k.toLowerCase().includes(s))
371
+ );
372
+ const score = Math.min(100, serverCount * 20 + hasEssentials.length * 20);
373
+ const status = score >= 60 ? "pass" : "warn";
374
+ const details = Object.keys(mcpServers).map((name) => ` ${name}`);
375
+ return {
376
+ name: this.name,
377
+ status,
378
+ score,
379
+ weight: this.weight,
380
+ message: `${serverCount} service${serverCount > 1 ? "s" : ""} active`,
381
+ details,
382
+ ...score < 80 && { fix: "Add more MCP services", command: "ccjk ccjk:mcp" }
383
+ };
384
+ } catch {
385
+ return {
386
+ name: this.name,
387
+ status: "fail",
388
+ score: 0,
389
+ weight: this.weight,
390
+ message: "Failed to read MCP configuration",
391
+ command: "ccjk doctor"
392
+ };
393
+ }
394
+ }
395
+ };
396
+
397
+ const modelCheck = {
398
+ name: "Default Model",
399
+ weight: 5,
400
+ async check() {
401
+ try {
402
+ if (!existsSync(SETTINGS_FILE)) {
403
+ return {
404
+ name: this.name,
405
+ status: "fail",
406
+ score: 0,
407
+ weight: this.weight,
408
+ message: "No settings file",
409
+ command: "ccjk init"
410
+ };
411
+ }
412
+ const settings = JSON.parse(readFileSync(SETTINGS_FILE, "utf-8"));
413
+ const hasModel = settings.model || settings.defaultModel || settings.preferredModel;
414
+ const hasApiKey = settings.apiKey || settings.env?.ANTHROPIC_API_KEY || process__default.env.ANTHROPIC_API_KEY;
415
+ if (!hasApiKey) {
416
+ return {
417
+ name: this.name,
418
+ status: "warn",
419
+ score: 40,
420
+ weight: this.weight,
421
+ message: "No API key configured (using default)",
422
+ fix: "Configure API for direct access",
423
+ command: "ccjk menu",
424
+ details: [" Using Claude Code default API"]
425
+ };
426
+ }
427
+ return {
428
+ name: this.name,
429
+ status: "pass",
430
+ score: hasModel ? 100 : 70,
431
+ weight: this.weight,
432
+ message: hasModel ? `Model: ${hasModel}` : "API configured (default model)"
433
+ };
434
+ } catch {
435
+ return { name: this.name, status: "fail", score: 0, weight: this.weight, message: "Failed to read model config" };
436
+ }
437
+ }
438
+ };
439
+
440
+ const INVALID_PERMISSION_NAMES = /* @__PURE__ */ new Set([
441
+ "AllowEdit",
442
+ "AllowWrite",
443
+ "AllowRead",
444
+ "AllowExec",
445
+ "AllowCreateProcess",
446
+ "AllowKillProcess",
447
+ "AllowNetworkAccess",
448
+ "AllowFileSystemAccess",
449
+ "AllowShellAccess",
450
+ "AllowHttpAccess"
451
+ ]);
452
+ function isValidPermission(perm) {
453
+ if (INVALID_PERMISSION_NAMES.has(perm)) return false;
454
+ if (["mcp__.*", "mcp__*", "mcp__(*)"].includes(perm)) return false;
455
+ return true;
456
+ }
457
+ const permissionsCheck = {
458
+ name: "Permissions",
459
+ weight: 3,
460
+ async check() {
461
+ try {
462
+ if (!existsSync(SETTINGS_FILE)) {
463
+ return {
464
+ name: this.name,
465
+ status: "warn",
466
+ score: 30,
467
+ weight: this.weight,
468
+ message: "No settings file",
469
+ command: "ccjk init"
470
+ };
471
+ }
472
+ const settings = JSON.parse(readFileSync(SETTINGS_FILE, "utf-8"));
473
+ const allowedTools = settings.permissions?.allow || [];
474
+ if (allowedTools.length === 0) {
475
+ return {
476
+ name: this.name,
477
+ status: "warn",
478
+ score: 40,
479
+ weight: this.weight,
480
+ message: "No tool permissions configured",
481
+ fix: "Configure permissions to reduce prompts",
482
+ command: "ccjk menu"
483
+ };
484
+ }
485
+ const invalidPerms = allowedTools.filter((p) => !isValidPermission(p));
486
+ const validPerms = allowedTools.filter((p) => isValidPermission(p));
487
+ if (invalidPerms.length > 0) {
488
+ return {
489
+ name: this.name,
490
+ status: "warn",
491
+ score: 50,
492
+ weight: this.weight,
493
+ message: `${invalidPerms.length} invalid permission(s) found (${validPerms.length} valid)`,
494
+ fix: "Run ccjk init to repair permissions",
495
+ command: "ccjk init"
496
+ };
497
+ }
498
+ const score = Math.min(100, 60 + validPerms.length * 2);
499
+ return {
500
+ name: this.name,
501
+ status: "pass",
502
+ score,
503
+ weight: this.weight,
504
+ message: `${validPerms.length} valid permission${validPerms.length > 1 ? "s" : ""} configured`
505
+ };
506
+ } catch {
507
+ return { name: this.name, status: "fail", score: 0, weight: this.weight, message: "Failed to read permissions" };
508
+ }
509
+ }
510
+ };
511
+
512
+ const skillsCheck = {
513
+ name: "Skills",
514
+ weight: 6,
515
+ async check() {
516
+ try {
517
+ if (!existsSync(CCJK_SKILLS_DIR)) {
518
+ return {
519
+ name: this.name,
520
+ status: "warn",
521
+ score: 20,
522
+ weight: this.weight,
523
+ message: "No skills directory found",
524
+ fix: "Install skills to enhance Claude Code",
525
+ command: "ccjk ccjk:skills"
526
+ };
527
+ }
528
+ const files = readdirSync(CCJK_SKILLS_DIR).filter((f) => f.endsWith(".md"));
529
+ const skillCount = files.length;
530
+ if (skillCount === 0) {
531
+ return {
532
+ name: this.name,
533
+ status: "warn",
534
+ score: 20,
535
+ weight: this.weight,
536
+ message: "No skills installed",
537
+ fix: "Install skills based on your project",
538
+ command: "ccjk ccjk:skills"
539
+ };
540
+ }
541
+ const score = Math.min(100, 30 + skillCount * 10);
542
+ return {
543
+ name: this.name,
544
+ status: score >= 60 ? "pass" : "warn",
545
+ score,
546
+ weight: this.weight,
547
+ message: `${skillCount} skill${skillCount > 1 ? "s" : ""} installed`,
548
+ details: files.slice(0, 8).map((f) => ` ${f.replace(".md", "")}`),
549
+ ...skillCount < 5 && { fix: "Install more project-specific skills", command: "ccjk ccjk:skills" }
550
+ };
551
+ } catch {
552
+ return { name: this.name, status: "fail", score: 0, weight: this.weight, message: "Failed to read skills" };
553
+ }
554
+ }
555
+ };
556
+
557
+ const DEFAULT_CHECKS = [
558
+ mcpCheck,
559
+ skillsCheck,
560
+ claudeMdCheck,
561
+ modelCheck,
562
+ agentsCheck,
563
+ permissionsCheck
564
+ ];
565
+ function calculateGrade(score) {
566
+ if (score >= 95) return "S";
567
+ if (score >= 80) return "A";
568
+ if (score >= 65) return "B";
569
+ if (score >= 50) return "C";
570
+ if (score >= 30) return "D";
571
+ return "F";
572
+ }
573
+ function generateRecommendations(results) {
574
+ const recs = [];
575
+ for (const r of results) {
576
+ if (r.status === "fail" && r.command) {
577
+ recs.push({
578
+ priority: "high",
579
+ title: `Fix: ${r.name}`,
580
+ description: r.fix || r.message,
581
+ command: r.command,
582
+ category: mapCategory(r.name)
583
+ });
584
+ } else if (r.status === "warn" && r.command) {
585
+ recs.push({
586
+ priority: "medium",
587
+ title: `Improve: ${r.name}`,
588
+ description: r.fix || r.message,
589
+ command: r.command,
590
+ category: mapCategory(r.name)
591
+ });
592
+ }
593
+ }
594
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
595
+ recs.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
596
+ return recs;
597
+ }
598
+ function mapCategory(name) {
599
+ const lower = name.toLowerCase();
600
+ if (lower.includes("mcp")) return "mcp";
601
+ if (lower.includes("skill")) return "skills";
602
+ if (lower.includes("agent")) return "agents";
603
+ if (lower.includes("model") || lower.includes("api")) return "model";
604
+ if (lower.includes("sync")) return "sync";
605
+ if (lower.includes("perm")) return "permissions";
606
+ return "general";
607
+ }
608
+ async function runHealthCheck(checks) {
609
+ const activeChecks = DEFAULT_CHECKS;
610
+ const results = [];
611
+ const promises = activeChecks.map(async (check) => {
612
+ try {
613
+ return await check.check();
614
+ } catch {
615
+ return {
616
+ name: check.name,
617
+ status: "fail",
618
+ score: 0,
619
+ weight: check.weight,
620
+ message: "Check failed unexpectedly"
621
+ };
622
+ }
623
+ });
624
+ const settled = await Promise.all(promises);
625
+ results.push(...settled);
626
+ const totalWeight = results.reduce((sum, r) => sum + r.weight, 0);
627
+ const weightedSum = results.reduce((sum, r) => sum + r.score * r.weight, 0);
628
+ const totalScore = totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
629
+ return {
630
+ totalScore,
631
+ grade: calculateGrade(totalScore),
632
+ results,
633
+ recommendations: generateRecommendations(results),
634
+ timestamp: Date.now()
635
+ };
636
+ }
637
+
638
+ export { analyzeProject as a, getRecommendations as g, runHealthCheck as r };
@@ -4,7 +4,7 @@ import { readFile } from 'node:fs/promises';
4
4
  import { homedir } from 'node:os';
5
5
  import { promisify } from 'node:util';
6
6
  import { join } from 'pathe';
7
- import { i18n } from '../chunks/index2.mjs';
7
+ import { i18n } from '../chunks/index.mjs';
8
8
 
9
9
  const execAsync = promisify(exec);
10
10
  function getClaudePluginDir() {
@@ -1,6 +1,6 @@
1
1
  import process__default from 'node:process';
2
2
  import ansis from 'ansis';
3
- import { ensureI18nInitialized, i18n } from '../chunks/index2.mjs';
3
+ import { ensureI18nInitialized, i18n } from '../chunks/index.mjs';
4
4
 
5
5
  function handleExitPromptError(error) {
6
6
  const isExitError = error instanceof Error && (error.name === "ExitPromptError" || error.message?.includes("ExitPromptError") || error.message?.includes("User force closed the prompt"));
@@ -22,4 +22,4 @@ function handleGeneralError(error) {
22
22
  process__default.exit(1);
23
23
  }
24
24
 
25
- export { handleExitPromptError as a, handleGeneralError as h };
25
+ export { handleGeneralError as a, handleExitPromptError as h };