ccjk 2.0.20 → 2.2.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.
Files changed (71) hide show
  1. package/README.md +601 -35
  2. package/README.zh-CN.md +651 -0
  3. package/dist/chunks/api.mjs +100 -0
  4. package/dist/chunks/auto-updater.mjs +252 -0
  5. package/dist/chunks/ccjk-config.mjs +261 -0
  6. package/dist/chunks/ccr.mjs +77 -0
  7. package/dist/chunks/ccu.mjs +36 -0
  8. package/dist/chunks/check-updates.mjs +93 -0
  9. package/dist/chunks/claude-code-config-manager.mjs +28 -21
  10. package/dist/chunks/claude-code-incremental-manager.mjs +26 -18
  11. package/dist/chunks/claude-config.mjs +228 -0
  12. package/dist/chunks/codex.mjs +2134 -0
  13. package/dist/chunks/commands.mjs +2 -15
  14. package/dist/chunks/commit.mjs +119 -0
  15. package/dist/chunks/config-consolidator.mjs +281 -0
  16. package/dist/chunks/config-switch.mjs +302 -0
  17. package/dist/chunks/constants.mjs +156 -0
  18. package/dist/chunks/doctor.mjs +708 -0
  19. package/dist/chunks/features.mjs +35 -640
  20. package/dist/chunks/features2.mjs +661 -0
  21. package/dist/chunks/fs-operations.mjs +180 -0
  22. package/dist/chunks/index.mjs +3082 -0
  23. package/dist/chunks/index2.mjs +145 -0
  24. package/dist/chunks/init.mjs +2468 -0
  25. package/dist/chunks/interview.mjs +2916 -0
  26. package/dist/chunks/json-config.mjs +59 -0
  27. package/dist/chunks/marketplace.mjs +258 -0
  28. package/dist/chunks/mcp-doctor.mjs +160 -0
  29. package/dist/chunks/mcp-market.mjs +475 -0
  30. package/dist/chunks/mcp-performance.mjs +110 -0
  31. package/dist/chunks/mcp-profile.mjs +220 -0
  32. package/dist/chunks/mcp-release.mjs +138 -0
  33. package/dist/chunks/menu.mjs +3599 -0
  34. package/dist/chunks/notification.mjs +2336 -0
  35. package/dist/chunks/onboarding.mjs +711 -0
  36. package/dist/chunks/package.mjs +4 -0
  37. package/dist/chunks/permission-manager.mjs +210 -0
  38. package/dist/chunks/platform.mjs +321 -0
  39. package/dist/chunks/prompts.mjs +228 -0
  40. package/dist/chunks/session.mjs +355 -0
  41. package/dist/chunks/shencha.mjs +320 -0
  42. package/dist/chunks/skills-sync.mjs +4 -13
  43. package/dist/chunks/team.mjs +51 -0
  44. package/dist/chunks/tools.mjs +169 -0
  45. package/dist/chunks/uninstall.mjs +784 -0
  46. package/dist/chunks/update.mjs +104 -0
  47. package/dist/chunks/upgrade-manager.mjs +197 -0
  48. package/dist/chunks/workflows.mjs +100 -0
  49. package/dist/cli.mjs +581 -15348
  50. package/dist/i18n/locales/zh-CN/cli.json +1 -1
  51. package/dist/i18n/locales/zh-CN/common.json +1 -1
  52. package/dist/index.mjs +43 -2062
  53. package/dist/shared/ccjk.-FoZ3zat.mjs +761 -0
  54. package/dist/shared/ccjk.B7169qud.mjs +25 -0
  55. package/dist/shared/ccjk.BhKlRJ0h.mjs +114 -0
  56. package/dist/shared/ccjk.Bi-m3LKY.mjs +357 -0
  57. package/dist/shared/ccjk.COdsoe-Y.mjs +64 -0
  58. package/dist/shared/ccjk.CUdzQluX.mjs +46 -0
  59. package/dist/shared/ccjk.Cy-RH2qV.mjs +506 -0
  60. package/dist/shared/ccjk.DGjQxTq_.mjs +34 -0
  61. package/dist/shared/ccjk.DJM5aVQJ.mjs +586 -0
  62. package/dist/shared/ccjk.DhBeLRzf.mjs +28 -0
  63. package/dist/shared/ccjk.DwDtZ5cK.mjs +266 -0
  64. package/dist/shared/ccjk.n_AtlHzB.mjs +186 -0
  65. package/dist/shared/ccjk.qYAnUMuy.mjs +749 -0
  66. package/package.json +29 -25
  67. package/dist/chunks/codex-config-switch.mjs +0 -429
  68. package/dist/chunks/codex-provider-manager.mjs +0 -234
  69. package/dist/chunks/codex-uninstaller.mjs +0 -406
  70. package/dist/chunks/plugin-recommendation.mjs +0 -575
  71. package/dist/chunks/simple-config.mjs +0 -10950
@@ -0,0 +1,711 @@
1
+ import { existsSync, readFileSync, readdirSync, mkdirSync, statSync } from 'node:fs';
2
+ import process from 'node:process';
3
+ import ansis from 'ansis';
4
+ import dayjs from 'dayjs';
5
+ import inquirer from 'inquirer';
6
+ import ora from 'ora';
7
+ import { join, basename } from 'pathe';
8
+ import { CCJK_CONFIG_DIR } from './constants.mjs';
9
+ import { b as boxify, C as COLORS, S as STATUS } from '../shared/ccjk.BhKlRJ0h.mjs';
10
+ import { writeFileAtomic } from './fs-operations.mjs';
11
+
12
+ function readPackageJson(dir) {
13
+ const pkgPath = join(dir, "package.json");
14
+ if (!existsSync(pkgPath))
15
+ return null;
16
+ try {
17
+ return JSON.parse(readFileSync(pkgPath, "utf-8"));
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ function detectPackageManager(dir) {
23
+ if (existsSync(join(dir, "bun.lockb")))
24
+ return "bun";
25
+ if (existsSync(join(dir, "pnpm-lock.yaml")))
26
+ return "pnpm";
27
+ if (existsSync(join(dir, "yarn.lock")))
28
+ return "yarn";
29
+ if (existsSync(join(dir, "package-lock.json")))
30
+ return "npm";
31
+ const pkg = readPackageJson(dir);
32
+ if (pkg?.packageManager) {
33
+ if (pkg.packageManager.startsWith("pnpm"))
34
+ return "pnpm";
35
+ if (pkg.packageManager.startsWith("yarn"))
36
+ return "yarn";
37
+ if (pkg.packageManager.startsWith("bun"))
38
+ return "bun";
39
+ }
40
+ return "unknown";
41
+ }
42
+ function detectFrameworks(dir) {
43
+ const frameworks = [];
44
+ const pkg = readPackageJson(dir);
45
+ if (!pkg)
46
+ return frameworks;
47
+ const allDeps = {
48
+ ...pkg.dependencies,
49
+ ...pkg.devDependencies
50
+ };
51
+ if (allDeps.react)
52
+ frameworks.push("react");
53
+ if (allDeps.vue)
54
+ frameworks.push("vue");
55
+ if (allDeps["@angular/core"])
56
+ frameworks.push("angular");
57
+ if (allDeps.svelte)
58
+ frameworks.push("svelte");
59
+ if (allDeps.next)
60
+ frameworks.push("nextjs");
61
+ if (allDeps.nuxt)
62
+ frameworks.push("nuxt");
63
+ if (allDeps["@remix-run/react"])
64
+ frameworks.push("remix");
65
+ if (allDeps.astro)
66
+ frameworks.push("astro");
67
+ if (allDeps.express)
68
+ frameworks.push("express");
69
+ if (allDeps.fastify)
70
+ frameworks.push("fastify");
71
+ if (allDeps["@nestjs/core"])
72
+ frameworks.push("nestjs");
73
+ if (allDeps.koa)
74
+ frameworks.push("koa");
75
+ if (allDeps.hono)
76
+ frameworks.push("hono");
77
+ if (allDeps.electron)
78
+ frameworks.push("electron");
79
+ if (allDeps["@tauri-apps/api"])
80
+ frameworks.push("tauri");
81
+ if (allDeps["react-native"])
82
+ frameworks.push("react-native");
83
+ if (existsSync(join(dir, "requirements.txt")) || existsSync(join(dir, "pyproject.toml"))) {
84
+ const reqPath = join(dir, "requirements.txt");
85
+ if (existsSync(reqPath)) {
86
+ const reqs = readFileSync(reqPath, "utf-8").toLowerCase();
87
+ if (reqs.includes("django"))
88
+ frameworks.push("django");
89
+ if (reqs.includes("flask"))
90
+ frameworks.push("flask");
91
+ if (reqs.includes("fastapi"))
92
+ frameworks.push("fastapi");
93
+ }
94
+ }
95
+ if (existsSync(join(dir, "Gemfile"))) {
96
+ const gemfile = readFileSync(join(dir, "Gemfile"), "utf-8").toLowerCase();
97
+ if (gemfile.includes("rails"))
98
+ frameworks.push("rails");
99
+ }
100
+ if (existsSync(join(dir, "composer.json"))) {
101
+ try {
102
+ const composer = JSON.parse(readFileSync(join(dir, "composer.json"), "utf-8"));
103
+ if (composer.require?.["laravel/framework"])
104
+ frameworks.push("laravel");
105
+ } catch {
106
+ }
107
+ }
108
+ return frameworks;
109
+ }
110
+ function detectBuildTools(dir) {
111
+ const tools = [];
112
+ const pkg = readPackageJson(dir);
113
+ if (existsSync(join(dir, "vite.config.ts")) || existsSync(join(dir, "vite.config.js")))
114
+ tools.push("vite");
115
+ if (existsSync(join(dir, "webpack.config.js")) || existsSync(join(dir, "webpack.config.ts")))
116
+ tools.push("webpack");
117
+ if (existsSync(join(dir, "rollup.config.js")) || existsSync(join(dir, "rollup.config.ts")))
118
+ tools.push("rollup");
119
+ if (existsSync(join(dir, "tsup.config.ts")) || existsSync(join(dir, "tsup.config.js")))
120
+ tools.push("tsup");
121
+ if (pkg) {
122
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
123
+ if (allDeps.esbuild)
124
+ tools.push("esbuild");
125
+ if (allDeps["@swc/core"])
126
+ tools.push("swc");
127
+ if (allDeps.turbo)
128
+ tools.push("turbopack");
129
+ if (allDeps.parcel)
130
+ tools.push("parcel");
131
+ if (allDeps.unbuild)
132
+ tools.push("unbuild");
133
+ }
134
+ return tools;
135
+ }
136
+ function detectTestFrameworks(dir) {
137
+ const frameworks = [];
138
+ const pkg = readPackageJson(dir);
139
+ if (existsSync(join(dir, "vitest.config.ts")) || existsSync(join(dir, "vitest.config.js")))
140
+ frameworks.push("vitest");
141
+ if (existsSync(join(dir, "jest.config.js")) || existsSync(join(dir, "jest.config.ts")))
142
+ frameworks.push("jest");
143
+ if (existsSync(join(dir, "cypress.config.ts")) || existsSync(join(dir, "cypress.config.js")))
144
+ frameworks.push("cypress");
145
+ if (existsSync(join(dir, "playwright.config.ts")))
146
+ frameworks.push("playwright");
147
+ if (existsSync(join(dir, "pytest.ini")) || existsSync(join(dir, "conftest.py")))
148
+ frameworks.push("pytest");
149
+ if (pkg) {
150
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
151
+ if (allDeps.vitest && !frameworks.includes("vitest"))
152
+ frameworks.push("vitest");
153
+ if (allDeps.jest && !frameworks.includes("jest"))
154
+ frameworks.push("jest");
155
+ if (allDeps.mocha)
156
+ frameworks.push("mocha");
157
+ if (allDeps.cypress && !frameworks.includes("cypress"))
158
+ frameworks.push("cypress");
159
+ if (allDeps["@playwright/test"] && !frameworks.includes("playwright"))
160
+ frameworks.push("playwright");
161
+ }
162
+ return frameworks;
163
+ }
164
+ function detectCICDSystems(dir) {
165
+ const systems = [];
166
+ if (existsSync(join(dir, ".github", "workflows")))
167
+ systems.push("github-actions");
168
+ if (existsSync(join(dir, ".gitlab-ci.yml")))
169
+ systems.push("gitlab-ci");
170
+ if (existsSync(join(dir, "Jenkinsfile")))
171
+ systems.push("jenkins");
172
+ if (existsSync(join(dir, ".circleci")))
173
+ systems.push("circleci");
174
+ if (existsSync(join(dir, ".travis.yml")))
175
+ systems.push("travis");
176
+ if (existsSync(join(dir, "azure-pipelines.yml")))
177
+ systems.push("azure-pipelines");
178
+ return systems;
179
+ }
180
+ function detectLanguages(dir) {
181
+ const languages = [];
182
+ if (existsSync(join(dir, "tsconfig.json")))
183
+ languages.push("typescript");
184
+ if (existsSync(join(dir, "package.json"))) {
185
+ if (!languages.includes("typescript"))
186
+ languages.push("javascript");
187
+ }
188
+ if (existsSync(join(dir, "requirements.txt")) || existsSync(join(dir, "pyproject.toml")) || existsSync(join(dir, "setup.py")))
189
+ languages.push("python");
190
+ if (existsSync(join(dir, "Gemfile")))
191
+ languages.push("ruby");
192
+ if (existsSync(join(dir, "go.mod")))
193
+ languages.push("go");
194
+ if (existsSync(join(dir, "Cargo.toml")))
195
+ languages.push("rust");
196
+ if (existsSync(join(dir, "pom.xml")) || existsSync(join(dir, "build.gradle"))) {
197
+ languages.push("java");
198
+ if (existsSync(join(dir, "build.gradle.kts")))
199
+ languages.push("kotlin");
200
+ }
201
+ if (existsSync(join(dir, "composer.json")))
202
+ languages.push("php");
203
+ if (existsSync(join(dir, "Package.swift")))
204
+ languages.push("swift");
205
+ if (existsSync(join(dir, "pubspec.yaml")))
206
+ languages.push("dart");
207
+ return languages;
208
+ }
209
+ function determineProjectType(info) {
210
+ const frameworks = info.frameworks || [];
211
+ if (frameworks.includes("react-native") || frameworks.includes("flutter"))
212
+ return "mobile";
213
+ if (frameworks.includes("electron") || frameworks.includes("tauri"))
214
+ return "desktop";
215
+ const pkg = info.rootDir ? readPackageJson(info.rootDir) : null;
216
+ if (pkg?.bin)
217
+ return "cli";
218
+ if (pkg?.main || pkg?.exports) {
219
+ const hasAppFramework = frameworks.some(
220
+ (f) => ["react", "vue", "angular", "svelte", "nextjs", "nuxt", "express", "fastify", "nestjs"].includes(f)
221
+ );
222
+ if (!hasAppFramework)
223
+ return "library";
224
+ }
225
+ const frontendFrameworks = ["react", "vue", "angular", "svelte"];
226
+ const backendFrameworks = ["express", "fastify", "nestjs", "koa", "hono", "django", "flask", "fastapi", "rails", "laravel"];
227
+ const metaFrameworks = ["nextjs", "nuxt", "remix", "astro"];
228
+ const hasFrontend = frameworks.some((f) => frontendFrameworks.includes(f));
229
+ const hasBackend = frameworks.some((f) => backendFrameworks.includes(f));
230
+ const hasMeta = frameworks.some((f) => metaFrameworks.includes(f));
231
+ if (hasMeta)
232
+ return "fullstack";
233
+ if (hasFrontend && hasBackend)
234
+ return "fullstack";
235
+ if (hasFrontend)
236
+ return "frontend";
237
+ if (hasBackend)
238
+ return "backend";
239
+ return "unknown";
240
+ }
241
+ function detectProject(dir = process.cwd()) {
242
+ const pkg = readPackageJson(dir);
243
+ const frameworks = detectFrameworks(dir);
244
+ const languages = detectLanguages(dir);
245
+ const info = {
246
+ name: pkg?.name || "unknown",
247
+ type: "unknown",
248
+ packageManager: detectPackageManager(dir),
249
+ frameworks,
250
+ buildTools: detectBuildTools(dir),
251
+ testFrameworks: detectTestFrameworks(dir),
252
+ cicd: detectCICDSystems(dir),
253
+ languages,
254
+ hasTypeScript: existsSync(join(dir, "tsconfig.json")),
255
+ hasDocker: existsSync(join(dir, "Dockerfile")) || existsSync(join(dir, "docker-compose.yml")),
256
+ hasMonorepo: existsSync(join(dir, "pnpm-workspace.yaml")) || existsSync(join(dir, "lerna.json")) || pkg?.workspaces != null,
257
+ rootDir: dir
258
+ };
259
+ info.type = determineProjectType(info);
260
+ return info;
261
+ }
262
+ function generateSuggestions(project) {
263
+ const suggestions = {
264
+ workflows: ["git"],
265
+ mcpServices: [],
266
+ agents: [],
267
+ skills: [],
268
+ subagentGroups: [],
269
+ outputStyle: "technical-precise"
270
+ };
271
+ if (project.hasTypeScript || project.languages.includes("typescript")) {
272
+ suggestions.subagentGroups.push("typescript-dev");
273
+ suggestions.skills.push("ts-debug", "ts-refactor", "ts-test");
274
+ }
275
+ if (project.languages.includes("python")) {
276
+ suggestions.subagentGroups.push("python-dev");
277
+ suggestions.skills.push("py-debug", "py-refactor", "py-test");
278
+ }
279
+ if (project.frameworks.includes("nextjs") || project.frameworks.includes("nuxt")) {
280
+ suggestions.workflows.push("frontend", "testing");
281
+ suggestions.agents.push("ccjk-performance-expert");
282
+ }
283
+ if (project.frameworks.includes("express") || project.frameworks.includes("fastify") || project.frameworks.includes("nestjs")) {
284
+ suggestions.workflows.push("backend", "testing");
285
+ suggestions.agents.push("ccjk-security-expert");
286
+ }
287
+ if (project.hasDocker || project.cicd.length > 0) {
288
+ suggestions.workflows.push("devops");
289
+ suggestions.subagentGroups.push("devops-team");
290
+ suggestions.skills.push("devops-docker", "devops-ci");
291
+ }
292
+ if (project.testFrameworks.length > 0) {
293
+ suggestions.workflows.push("testing");
294
+ suggestions.agents.push("ccjk-testing-specialist");
295
+ }
296
+ if (project.hasMonorepo) {
297
+ suggestions.agents.push("ccjk-code-reviewer");
298
+ }
299
+ if (project.type === "frontend" || project.type === "fullstack") {
300
+ suggestions.subagentGroups.push("seo-team");
301
+ suggestions.skills.push("seo-meta", "seo-schema");
302
+ }
303
+ suggestions.subagentGroups.push("security-team");
304
+ suggestions.workflows = [...new Set(suggestions.workflows)];
305
+ suggestions.agents = [...new Set(suggestions.agents)];
306
+ suggestions.skills = [...new Set(suggestions.skills)];
307
+ suggestions.subagentGroups = [...new Set(suggestions.subagentGroups)];
308
+ return suggestions;
309
+ }
310
+ function getProjectSummary(project) {
311
+ const parts = [];
312
+ parts.push(`Project: ${project.name}`);
313
+ parts.push(`Type: ${project.type}`);
314
+ if (project.languages.length > 0) {
315
+ parts.push(`Languages: ${project.languages.join(", ")}`);
316
+ }
317
+ if (project.frameworks.length > 0) {
318
+ parts.push(`Frameworks: ${project.frameworks.join(", ")}`);
319
+ }
320
+ if (project.buildTools.length > 0) {
321
+ parts.push(`Build: ${project.buildTools.join(", ")}`);
322
+ }
323
+ if (project.testFrameworks.length > 0) {
324
+ parts.push(`Testing: ${project.testFrameworks.join(", ")}`);
325
+ }
326
+ parts.push(`Package Manager: ${project.packageManager}`);
327
+ const features = [];
328
+ if (project.hasTypeScript)
329
+ features.push("TypeScript");
330
+ if (project.hasDocker)
331
+ features.push("Docker");
332
+ if (project.hasMonorepo)
333
+ features.push("Monorepo");
334
+ if (features.length > 0) {
335
+ parts.push(`Features: ${features.join(", ")}`);
336
+ }
337
+ return parts.join("\n");
338
+ }
339
+
340
+ const KNOWLEDGE_BASE_FILE = join(CCJK_CONFIG_DIR, "knowledge-base.json");
341
+ function simpleHash(content) {
342
+ let hash = 0;
343
+ for (let i = 0; i < content.length; i++) {
344
+ const char = content.charCodeAt(i);
345
+ hash = (hash << 5) - hash + char;
346
+ hash = hash & hash;
347
+ }
348
+ return hash.toString(16);
349
+ }
350
+ function loadKnowledgeBase() {
351
+ if (existsSync(KNOWLEDGE_BASE_FILE)) {
352
+ try {
353
+ return JSON.parse(readFileSync(KNOWLEDGE_BASE_FILE, "utf-8"));
354
+ } catch {
355
+ }
356
+ }
357
+ return {
358
+ version: "1.0.0",
359
+ lastSync: (/* @__PURE__ */ new Date()).toISOString(),
360
+ entries: [],
361
+ projectContexts: []
362
+ };
363
+ }
364
+ function saveKnowledgeBase(kb) {
365
+ if (!existsSync(CCJK_CONFIG_DIR)) {
366
+ mkdirSync(CCJK_CONFIG_DIR, { recursive: true });
367
+ }
368
+ kb.lastSync = (/* @__PURE__ */ new Date()).toISOString();
369
+ writeFileAtomic(KNOWLEDGE_BASE_FILE, JSON.stringify(kb, null, 2));
370
+ }
371
+ function isFileOutdated(filePath, daysThreshold = 30) {
372
+ try {
373
+ const stat = statSync(filePath);
374
+ const daysSinceModified = dayjs().diff(dayjs(stat.mtime), "day");
375
+ return daysSinceModified > daysThreshold;
376
+ } catch {
377
+ return true;
378
+ }
379
+ }
380
+ function scanClaudeMd(projectDir) {
381
+ const possiblePaths = [
382
+ join(projectDir, "CLAUDE.md"),
383
+ join(projectDir, "claude.md"),
384
+ join(projectDir, ".claude", "CLAUDE.md"),
385
+ join(projectDir, "docs", "CLAUDE.md")
386
+ ];
387
+ for (const path of possiblePaths) {
388
+ if (existsSync(path)) {
389
+ const content = readFileSync(path, "utf-8");
390
+ return {
391
+ path,
392
+ content,
393
+ outdated: isFileOutdated(path)
394
+ };
395
+ }
396
+ }
397
+ return null;
398
+ }
399
+ function scanAgents(projectDir) {
400
+ const agents = [];
401
+ const agentDirs = [
402
+ join(projectDir, ".claude", "agents"),
403
+ join(projectDir, "agents"),
404
+ join(projectDir, ".agents")
405
+ ];
406
+ for (const dir of agentDirs) {
407
+ if (existsSync(dir)) {
408
+ try {
409
+ const files = readdirSync(dir);
410
+ for (const file of files) {
411
+ if (file.endsWith(".md")) {
412
+ const filePath = join(dir, file);
413
+ agents.push({
414
+ path: filePath,
415
+ name: basename(file, ".md"),
416
+ content: readFileSync(filePath, "utf-8")
417
+ });
418
+ }
419
+ }
420
+ } catch {
421
+ }
422
+ }
423
+ }
424
+ return agents;
425
+ }
426
+ function scanSkills(projectDir) {
427
+ const skills = [];
428
+ const skillDirs = [
429
+ join(projectDir, ".claude", "commands"),
430
+ join(projectDir, ".claude", "skills"),
431
+ join(projectDir, "skills")
432
+ ];
433
+ for (const dir of skillDirs) {
434
+ if (existsSync(dir)) {
435
+ try {
436
+ const files = readdirSync(dir);
437
+ for (const file of files) {
438
+ if (file.endsWith(".md")) {
439
+ const filePath = join(dir, file);
440
+ skills.push({
441
+ path: filePath,
442
+ name: basename(file, ".md"),
443
+ content: readFileSync(filePath, "utf-8")
444
+ });
445
+ }
446
+ }
447
+ } catch {
448
+ }
449
+ }
450
+ }
451
+ return skills;
452
+ }
453
+ function addToKnowledgeBase(kb, type, name, path, content, projectRoot) {
454
+ const hash = simpleHash(content);
455
+ const now = (/* @__PURE__ */ new Date()).toISOString();
456
+ const existingIndex = kb.entries.findIndex((e) => e.path === path);
457
+ if (existingIndex >= 0) {
458
+ if (kb.entries[existingIndex].hash !== hash) {
459
+ kb.entries[existingIndex] = {
460
+ ...kb.entries[existingIndex],
461
+ content,
462
+ hash,
463
+ updatedAt: now
464
+ };
465
+ }
466
+ } else {
467
+ kb.entries.push({
468
+ id: `${type}-${Date.now()}`,
469
+ type,
470
+ name,
471
+ path,
472
+ content,
473
+ hash,
474
+ createdAt: now,
475
+ updatedAt: now,
476
+ projectRoot
477
+ });
478
+ }
479
+ }
480
+ function generateDefaultClaudeMd(project) {
481
+ return `# ${project.name}
482
+
483
+ ## Project Overview
484
+
485
+ This is a ${project.type} project using ${project.frameworks.join(", ") || "standard tools"}.
486
+
487
+ ## Tech Stack
488
+
489
+ ${project.languages.map((l) => `- ${l}`).join("\n")}
490
+ ${project.frameworks.map((f) => `- ${f}`).join("\n")}
491
+
492
+ ## Development Guidelines
493
+
494
+ ### Code Style
495
+ - Follow existing code conventions
496
+ - Use TypeScript strict mode
497
+ - Write meaningful commit messages
498
+
499
+ ### Testing
500
+ ${project.testFrameworks.length > 0 ? `Using: ${project.testFrameworks.join(", ")}` : "- Add tests for new features"}
501
+
502
+ ### Build & Deploy
503
+ ${project.buildTools.length > 0 ? `Build tools: ${project.buildTools.join(", ")}` : "- Follow standard build process"}
504
+
505
+ ## Important Files
506
+
507
+ - \`README.md\` - Project documentation
508
+ - \`package.json\` - Dependencies and scripts
509
+
510
+ ## AI Assistant Notes
511
+
512
+ - Prefer concise, actionable responses
513
+ - Follow existing patterns in the codebase
514
+ - Ask before making breaking changes
515
+
516
+ ---
517
+ *Generated by CCJK on ${dayjs().format("YYYY-MM-DD")}*
518
+ `;
519
+ }
520
+ async function runOnboarding(projectDir = process.cwd()) {
521
+ console.log(boxify(`
522
+ Welcome to CCJK!
523
+
524
+ Let's set up your project for optimal AI-assisted development.
525
+ This will scan your project and create a knowledge base.
526
+ `, "double", "\u{1F680} CCJK Setup"));
527
+ const result = {
528
+ success: false,
529
+ projectDetected: false,
530
+ claudeMdFound: false,
531
+ claudeMdUpdated: false,
532
+ agentsFound: 0,
533
+ skillsFound: 0,
534
+ knowledgeEntriesCreated: 0,
535
+ recommendations: []
536
+ };
537
+ const kb = loadKnowledgeBase();
538
+ const spinner = ora("Scanning project...").start();
539
+ const project = detectProject(projectDir);
540
+ spinner.succeed("Project detected");
541
+ result.projectDetected = true;
542
+ console.log("");
543
+ console.log(COLORS.secondary("\u{1F4C1} Project Info:"));
544
+ console.log(ansis.gray(getProjectSummary(project)));
545
+ console.log("");
546
+ spinner.start("Looking for CLAUDE.md...");
547
+ const claudeMd = scanClaudeMd(projectDir);
548
+ if (claudeMd) {
549
+ spinner.succeed(`Found CLAUDE.md at ${claudeMd.path}`);
550
+ result.claudeMdFound = true;
551
+ if (claudeMd.outdated) {
552
+ console.log(STATUS.warning("CLAUDE.md appears to be outdated (>30 days old)"));
553
+ const { updateClaudeMd } = await inquirer.prompt([
554
+ {
555
+ type: "confirm",
556
+ name: "updateClaudeMd",
557
+ message: "Would you like to refresh it with current project info?",
558
+ default: true
559
+ }
560
+ ]);
561
+ if (updateClaudeMd) {
562
+ const newContent = generateDefaultClaudeMd(project);
563
+ const backupPath = `${claudeMd.path}.backup-${dayjs().format("YYYYMMDD")}`;
564
+ writeFileAtomic(backupPath, claudeMd.content);
565
+ writeFileAtomic(claudeMd.path, newContent);
566
+ console.log(STATUS.success(`Updated! Backup saved to ${backupPath}`));
567
+ result.claudeMdUpdated = true;
568
+ addToKnowledgeBase(kb, "claude-md", "CLAUDE.md", claudeMd.path, newContent, projectDir);
569
+ } else {
570
+ addToKnowledgeBase(kb, "claude-md", "CLAUDE.md", claudeMd.path, claudeMd.content, projectDir);
571
+ }
572
+ } else {
573
+ addToKnowledgeBase(kb, "claude-md", "CLAUDE.md", claudeMd.path, claudeMd.content, projectDir);
574
+ }
575
+ result.knowledgeEntriesCreated++;
576
+ } else {
577
+ spinner.warn("No CLAUDE.md found");
578
+ const { createClaudeMd } = await inquirer.prompt([
579
+ {
580
+ type: "confirm",
581
+ name: "createClaudeMd",
582
+ message: "Would you like to create one? (Recommended for AI assistance)",
583
+ default: true
584
+ }
585
+ ]);
586
+ if (createClaudeMd) {
587
+ const newContent = generateDefaultClaudeMd(project);
588
+ const newPath = join(projectDir, "CLAUDE.md");
589
+ writeFileAtomic(newPath, newContent);
590
+ console.log(STATUS.success(`Created ${newPath}`));
591
+ result.claudeMdFound = true;
592
+ result.claudeMdUpdated = true;
593
+ addToKnowledgeBase(kb, "claude-md", "CLAUDE.md", newPath, newContent, projectDir);
594
+ result.knowledgeEntriesCreated++;
595
+ } else {
596
+ result.recommendations.push("Consider creating a CLAUDE.md file for better AI assistance");
597
+ }
598
+ }
599
+ spinner.start("Scanning for agents...");
600
+ const agents = scanAgents(projectDir);
601
+ spinner.succeed(`Found ${agents.length} agent(s)`);
602
+ result.agentsFound = agents.length;
603
+ for (const agent of agents) {
604
+ addToKnowledgeBase(kb, "agent", agent.name, agent.path, agent.content, projectDir);
605
+ result.knowledgeEntriesCreated++;
606
+ }
607
+ if (agents.length === 0) {
608
+ result.recommendations.push("Add custom agents in .claude/agents/ for specialized assistance");
609
+ }
610
+ spinner.start("Scanning for skills...");
611
+ const skills = scanSkills(projectDir);
612
+ spinner.succeed(`Found ${skills.length} skill(s)`);
613
+ result.skillsFound = skills.length;
614
+ for (const skill of skills) {
615
+ addToKnowledgeBase(kb, "skill", skill.name, skill.path, skill.content, projectDir);
616
+ result.knowledgeEntriesCreated++;
617
+ }
618
+ if (skills.length === 0) {
619
+ result.recommendations.push("Add custom skills in .claude/commands/ for quick actions");
620
+ }
621
+ const suggestions = generateSuggestions(project);
622
+ const existingContextIndex = kb.projectContexts.findIndex((c) => c.rootDir === projectDir);
623
+ const projectContext = {
624
+ rootDir: projectDir,
625
+ name: project.name,
626
+ type: project.type,
627
+ frameworks: project.frameworks,
628
+ lastScanned: (/* @__PURE__ */ new Date()).toISOString(),
629
+ claudeMdHash: claudeMd ? simpleHash(claudeMd.content) : void 0,
630
+ agentsCount: agents.length,
631
+ skillsCount: skills.length
632
+ };
633
+ if (existingContextIndex >= 0) {
634
+ kb.projectContexts[existingContextIndex] = projectContext;
635
+ } else {
636
+ kb.projectContexts.push(projectContext);
637
+ }
638
+ addToKnowledgeBase(
639
+ kb,
640
+ "project-info",
641
+ project.name,
642
+ projectDir,
643
+ JSON.stringify({ project, suggestions }, null, 2),
644
+ projectDir
645
+ );
646
+ result.knowledgeEntriesCreated++;
647
+ saveKnowledgeBase(kb);
648
+ console.log("");
649
+ console.log(COLORS.primary("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
650
+ console.log(COLORS.accent(" Setup Complete! "));
651
+ console.log(COLORS.primary("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
652
+ console.log("");
653
+ console.log(` \u{1F4DA} Knowledge entries: ${result.knowledgeEntriesCreated}`);
654
+ console.log(` \u{1F4C4} CLAUDE.md: ${result.claudeMdFound ? "\u2713" : "\u2717"}`);
655
+ console.log(` \u{1F916} Agents: ${result.agentsFound}`);
656
+ console.log(` \u26A1 Skills: ${result.skillsFound}`);
657
+ console.log("");
658
+ if (result.recommendations.length > 0) {
659
+ console.log(COLORS.secondary("\u{1F4A1} Recommendations:"));
660
+ for (const rec of result.recommendations) {
661
+ console.log(ansis.gray(` \u2022 ${rec}`));
662
+ }
663
+ console.log("");
664
+ }
665
+ console.log(COLORS.secondary("\u{1F4CC} Next Steps:"));
666
+ console.log(ansis.gray(" \u2022 Run `ccjk` to open the main menu"));
667
+ console.log(ansis.gray(" \u2022 Run `ccjk doctor` to check environment"));
668
+ console.log(ansis.gray(" \u2022 Run `ccjk groups enable typescript-dev` for TypeScript support"));
669
+ console.log("");
670
+ result.success = true;
671
+ return result;
672
+ }
673
+ async function quickSync(projectDir = process.cwd()) {
674
+ const spinner = ora("Syncing project knowledge...").start();
675
+ const kb = loadKnowledgeBase();
676
+ detectProject(projectDir);
677
+ const claudeMd = scanClaudeMd(projectDir);
678
+ if (claudeMd) {
679
+ addToKnowledgeBase(kb, "claude-md", "CLAUDE.md", claudeMd.path, claudeMd.content, projectDir);
680
+ }
681
+ const agents = scanAgents(projectDir);
682
+ for (const agent of agents) {
683
+ addToKnowledgeBase(kb, "agent", agent.name, agent.path, agent.content, projectDir);
684
+ }
685
+ const skills = scanSkills(projectDir);
686
+ for (const skill of skills) {
687
+ addToKnowledgeBase(kb, "skill", skill.name, skill.path, skill.content, projectDir);
688
+ }
689
+ saveKnowledgeBase(kb);
690
+ spinner.succeed(`Synced: ${claudeMd ? 1 : 0} CLAUDE.md, ${agents.length} agents, ${skills.length} skills`);
691
+ }
692
+ function getProjectKnowledge(projectDir = process.cwd()) {
693
+ const kb = loadKnowledgeBase();
694
+ return kb.entries.filter((e) => e.projectRoot === projectDir);
695
+ }
696
+ function exportProjectKnowledge(projectDir = process.cwd()) {
697
+ const entries = getProjectKnowledge(projectDir);
698
+ return JSON.stringify(entries, null, 2);
699
+ }
700
+
701
+ const onboarding = {
702
+ __proto__: null,
703
+ exportProjectKnowledge: exportProjectKnowledge,
704
+ getProjectKnowledge: getProjectKnowledge,
705
+ loadKnowledgeBase: loadKnowledgeBase,
706
+ quickSync: quickSync,
707
+ runOnboarding: runOnboarding,
708
+ saveKnowledgeBase: saveKnowledgeBase
709
+ };
710
+
711
+ export { detectFrameworks as a, detectBuildTools as b, detectTestFrameworks as c, detectPackageManager as d, detectCICDSystems as e, detectLanguages as f, determineProjectType as g, detectProject as h, generateSuggestions as i, getProjectSummary as j, getProjectKnowledge as k, loadKnowledgeBase as l, exportProjectKnowledge as m, onboarding as o, quickSync as q, runOnboarding as r, saveKnowledgeBase as s };