ccjk 13.6.7 → 14.0.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 (51) hide show
  1. package/dist/chunks/api-cli.mjs +4 -2
  2. package/dist/chunks/api-config-selector.mjs +2 -4
  3. package/dist/chunks/auto-fix.mjs +3 -1
  4. package/dist/chunks/ccjk-all.mjs +5 -2
  5. package/dist/chunks/ccjk-mcp.mjs +5 -2
  6. package/dist/chunks/ccjk-setup.mjs +4 -1
  7. package/dist/chunks/ccr.mjs +5 -8
  8. package/dist/chunks/check-updates.mjs +1 -4
  9. package/dist/chunks/claude-code-incremental-manager.mjs +4 -6
  10. package/dist/chunks/code-type-resolver.mjs +878 -0
  11. package/dist/chunks/codex-config-switch.mjs +0 -1
  12. package/dist/chunks/codex-provider-manager.mjs +0 -1
  13. package/dist/chunks/codex.mjs +2 -2
  14. package/dist/chunks/config-switch.mjs +2 -4
  15. package/dist/chunks/config.mjs +1144 -5
  16. package/dist/chunks/config2.mjs +6 -4
  17. package/dist/chunks/config3.mjs +4 -2
  18. package/dist/chunks/doctor.mjs +1 -1
  19. package/dist/chunks/evolution.mjs +47 -27
  20. package/dist/chunks/features.mjs +2 -3
  21. package/dist/chunks/index10.mjs +115 -12
  22. package/dist/chunks/init.mjs +44 -17
  23. package/dist/chunks/installer.mjs +2 -2
  24. package/dist/chunks/mcp-cli.mjs +18 -19
  25. package/dist/chunks/mcp.mjs +6 -7
  26. package/dist/chunks/package.mjs +1 -1
  27. package/dist/chunks/platform.mjs +1 -1
  28. package/dist/chunks/quick-setup.mjs +2 -5
  29. package/dist/chunks/slash-commands.mjs +1 -1
  30. package/dist/chunks/status.mjs +63 -16
  31. package/dist/chunks/uninstall.mjs +1 -3
  32. package/dist/chunks/update.mjs +4 -5
  33. package/dist/cli.mjs +58 -17
  34. package/dist/i18n/locales/en/configuration.json +6 -2
  35. package/dist/i18n/locales/en/menu.json +7 -0
  36. package/dist/i18n/locales/zh-CN/configuration.json +6 -2
  37. package/dist/i18n/locales/zh-CN/menu.json +7 -0
  38. package/dist/index.d.mts +64 -17
  39. package/dist/index.d.ts +64 -17
  40. package/dist/index.mjs +12 -720
  41. package/dist/shared/{ccjk.DHaUdzX3.mjs → ccjk.B6VCKdyy.mjs} +2 -2
  42. package/dist/shared/ccjk.BO45TPXJ.mjs +807 -0
  43. package/dist/shared/{ccjk.B4aXNclK.mjs → ccjk.CVjfbEIj.mjs} +1 -1
  44. package/dist/shared/{ccjk.Dz0ssUQx.mjs → ccjk.Dh6Be-ef.mjs} +1 -1
  45. package/package.json +1 -1
  46. package/dist/chunks/claude-code-config-manager.mjs +0 -811
  47. package/dist/chunks/claude-config.mjs +0 -286
  48. package/dist/chunks/intent-engine.mjs +0 -142
  49. package/dist/chunks/smart-defaults.mjs +0 -425
  50. package/dist/shared/ccjk.DJuyfrlL.mjs +0 -348
  51. package/dist/shared/ccjk.yYQMbHH3.mjs +0 -115
@@ -0,0 +1,878 @@
1
+ import { i as inquirer } from './index6.mjs';
2
+ import { execSync } from 'node:child_process';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { homedir } from 'node:os';
5
+ import { CCJK_CONFIG_DIR, CODE_TOOL_INFO, CODE_TOOL_ALIASES, DEFAULT_CODE_TOOL_TYPE, isCodeToolType } from './constants.mjs';
6
+ import { writeJsonConfig } from './json-config.mjs';
7
+ import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
8
+ import { g as getPlatform, h as commandExists } from './platform.mjs';
9
+ import process__default from 'node:process';
10
+ import { i18n } from './index2.mjs';
11
+ import { readZcfConfigAsync, updateZcfConfig } from './ccjk-config.mjs';
12
+
13
+ const ORCHESTRATION_LEVELS = ["off", "minimal", "standard", "max"];
14
+ function parseOrchestrationLevel(value) {
15
+ if (!value) {
16
+ return "max";
17
+ }
18
+ const normalized = value.trim().toLowerCase();
19
+ if (ORCHESTRATION_LEVELS.includes(normalized)) {
20
+ return normalized;
21
+ }
22
+ throw new Error(`Invalid orchestration level: ${value}. Valid values: ${ORCHESTRATION_LEVELS.join(", ")}`);
23
+ }
24
+ function buildDefaults(level) {
25
+ if (level === "off") {
26
+ return {
27
+ planForNonTrivial: false,
28
+ useSubagentsForResearch: false,
29
+ verifyBeforeDone: false,
30
+ rootCauseFirst: true,
31
+ lessonsLoop: false
32
+ };
33
+ }
34
+ if (level === "minimal") {
35
+ return {
36
+ planForNonTrivial: true,
37
+ useSubagentsForResearch: false,
38
+ verifyBeforeDone: true,
39
+ rootCauseFirst: true,
40
+ lessonsLoop: false
41
+ };
42
+ }
43
+ if (level === "max") {
44
+ return {
45
+ planForNonTrivial: true,
46
+ useSubagentsForResearch: true,
47
+ verifyBeforeDone: true,
48
+ rootCauseFirst: true,
49
+ lessonsLoop: true
50
+ };
51
+ }
52
+ return {
53
+ planForNonTrivial: true,
54
+ useSubagentsForResearch: true,
55
+ verifyBeforeDone: true,
56
+ rootCauseFirst: true,
57
+ lessonsLoop: true
58
+ };
59
+ }
60
+ function resolveOrchestrationLevelFromRuntime(runtime) {
61
+ if (!runtime) {
62
+ return "max";
63
+ }
64
+ if (runtime.isCI || runtime.isContainer) {
65
+ return "minimal";
66
+ }
67
+ if (runtime.isSSH) {
68
+ return "minimal";
69
+ }
70
+ return "max";
71
+ }
72
+ function writeOrchestrationPolicy(params) {
73
+ const filePath = join(CCJK_CONFIG_DIR, "orchestration.json");
74
+ const policy = {
75
+ version: "1.0.0",
76
+ enabled: params.level !== "off",
77
+ level: params.level,
78
+ language: params.language,
79
+ defaults: buildDefaults(params.level),
80
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
81
+ source: params.source
82
+ };
83
+ writeJsonConfig(filePath, policy, { atomic: true });
84
+ return filePath;
85
+ }
86
+
87
+ function scanProject(cwd) {
88
+ const root = cwd || process__default.cwd();
89
+ const pkg = readPackageJson(root);
90
+ const language = detectLanguage(root, pkg);
91
+ const secondaryLanguages = detectSecondaryLanguages(root, pkg, language);
92
+ return {
93
+ language,
94
+ secondaryLanguages,
95
+ framework: detectFramework(root, pkg),
96
+ testRunner: detectTestRunner(root, pkg),
97
+ packageManager: detectPackageManager(root),
98
+ linter: detectLinter(root, pkg),
99
+ formatter: detectFormatter(root, pkg),
100
+ database: detectDatabase(root),
101
+ runtime: detectRuntime(),
102
+ isMonorepo: detectMonorepo(root, pkg),
103
+ usesConventionalCommits: detectConventionalCommits(root, pkg),
104
+ hasGitHooks: detectGitHooks(root, pkg),
105
+ hasDocker: existsSync(join(root, "Dockerfile")) || existsSync(join(root, "docker-compose.yml")) || existsSync(join(root, "docker-compose.yaml")),
106
+ hasCI: detectCI(root),
107
+ root
108
+ };
109
+ }
110
+ function readPackageJson(root) {
111
+ const p = join(root, "package.json");
112
+ if (!existsSync(p))
113
+ return null;
114
+ try {
115
+ return JSON.parse(readFileSync(p, "utf-8"));
116
+ } catch {
117
+ return null;
118
+ }
119
+ }
120
+ function hasDep(pkg, name) {
121
+ if (!pkg)
122
+ return false;
123
+ return !!(pkg.dependencies?.[name] || pkg.devDependencies?.[name] || pkg.peerDependencies?.[name]);
124
+ }
125
+ function detectLanguage(root, pkg) {
126
+ if (existsSync(join(root, "tsconfig.json")) || hasDep(pkg, "typescript")) {
127
+ return "typescript";
128
+ }
129
+ if (existsSync(join(root, "pyproject.toml")) || existsSync(join(root, "setup.py")) || existsSync(join(root, "requirements.txt")) || existsSync(join(root, "Pipfile"))) {
130
+ return "python";
131
+ }
132
+ if (existsSync(join(root, "go.mod"))) {
133
+ return "go";
134
+ }
135
+ if (existsSync(join(root, "Cargo.toml"))) {
136
+ return "rust";
137
+ }
138
+ if (existsSync(join(root, "pom.xml")) || existsSync(join(root, "build.gradle")) || existsSync(join(root, "build.gradle.kts"))) {
139
+ return "java";
140
+ }
141
+ if (existsSync(join(root, "Gemfile"))) {
142
+ return "ruby";
143
+ }
144
+ if (existsSync(join(root, "composer.json"))) {
145
+ return "php";
146
+ }
147
+ if (existsSync(join(root, "Package.swift"))) {
148
+ return "swift";
149
+ }
150
+ if (existsSync(join(root, "*.csproj")) || existsSync(join(root, "*.sln"))) {
151
+ return "csharp";
152
+ }
153
+ if (pkg) {
154
+ return "javascript";
155
+ }
156
+ return "unknown";
157
+ }
158
+ function detectSecondaryLanguages(root, pkg, primary) {
159
+ const langs = [];
160
+ const checks = [
161
+ ["typescript", () => existsSync(join(root, "tsconfig.json")) || hasDep(pkg, "typescript")],
162
+ ["javascript", () => !!pkg],
163
+ ["python", () => existsSync(join(root, "pyproject.toml")) || existsSync(join(root, "requirements.txt"))],
164
+ ["go", () => existsSync(join(root, "go.mod"))],
165
+ ["rust", () => existsSync(join(root, "Cargo.toml"))]
166
+ ];
167
+ for (const [lang, check] of checks) {
168
+ if (lang !== primary && check())
169
+ langs.push(lang);
170
+ }
171
+ return langs;
172
+ }
173
+ function detectFramework(root, pkg) {
174
+ if (!pkg) {
175
+ if (existsSync(join(root, "pyproject.toml"))) {
176
+ const content = safeRead(join(root, "pyproject.toml"));
177
+ if (content.includes("fastapi"))
178
+ return "fastapi";
179
+ if (content.includes("django"))
180
+ return "django";
181
+ if (content.includes("flask"))
182
+ return "flask";
183
+ }
184
+ if (existsSync(join(root, "requirements.txt"))) {
185
+ const content = safeRead(join(root, "requirements.txt"));
186
+ if (content.includes("fastapi"))
187
+ return "fastapi";
188
+ if (content.includes("django"))
189
+ return "django";
190
+ if (content.includes("flask"))
191
+ return "flask";
192
+ }
193
+ return "none";
194
+ }
195
+ if (hasDep(pkg, "next"))
196
+ return "next";
197
+ if (hasDep(pkg, "nuxt"))
198
+ return "nuxt";
199
+ if (hasDep(pkg, "@angular/core"))
200
+ return "angular";
201
+ if (hasDep(pkg, "svelte") || hasDep(pkg, "@sveltejs/kit"))
202
+ return "svelte";
203
+ if (hasDep(pkg, "@nestjs/core"))
204
+ return "nest";
205
+ if (hasDep(pkg, "@tauri-apps/api") || hasDep(pkg, "@tauri-apps/cli"))
206
+ return "tauri";
207
+ if (hasDep(pkg, "electron"))
208
+ return "electron";
209
+ if (hasDep(pkg, "vue"))
210
+ return "vue";
211
+ if (hasDep(pkg, "react"))
212
+ return "react";
213
+ if (hasDep(pkg, "fastify"))
214
+ return "fastify";
215
+ if (hasDep(pkg, "express"))
216
+ return "express";
217
+ return "none";
218
+ }
219
+ function detectTestRunner(root, pkg) {
220
+ if (hasDep(pkg, "vitest"))
221
+ return "vitest";
222
+ if (hasDep(pkg, "jest") || hasDep(pkg, "@jest/core"))
223
+ return "jest";
224
+ if (hasDep(pkg, "mocha"))
225
+ return "mocha";
226
+ if (existsSync(join(root, "pytest.ini")) || existsSync(join(root, "conftest.py")))
227
+ return "pytest";
228
+ if (existsSync(join(root, "pyproject.toml"))) {
229
+ const content = safeRead(join(root, "pyproject.toml"));
230
+ if (content.includes("[tool.pytest") || content.includes("pytest"))
231
+ return "pytest";
232
+ }
233
+ if (existsSync(join(root, "go.mod")))
234
+ return "go-test";
235
+ if (existsSync(join(root, "Cargo.toml")))
236
+ return "cargo-test";
237
+ if (existsSync(join(root, "pom.xml")) || existsSync(join(root, "build.gradle")))
238
+ return "junit";
239
+ if (existsSync(join(root, "Gemfile"))) {
240
+ const content = safeRead(join(root, "Gemfile"));
241
+ if (content.includes("rspec"))
242
+ return "rspec";
243
+ }
244
+ if (hasDep(pkg, "phpunit") || existsSync(join(root, "phpunit.xml")))
245
+ return "phpunit";
246
+ return "none";
247
+ }
248
+ function detectPackageManager(root) {
249
+ if (existsSync(join(root, "pnpm-lock.yaml")) || existsSync(join(root, "pnpm-workspace.yaml")))
250
+ return "pnpm";
251
+ if (existsSync(join(root, "bun.lockb")) || existsSync(join(root, "bun.lock")))
252
+ return "bun";
253
+ if (existsSync(join(root, "yarn.lock")))
254
+ return "yarn";
255
+ if (existsSync(join(root, "package-lock.json")))
256
+ return "npm";
257
+ if (existsSync(join(root, "poetry.lock")))
258
+ return "poetry";
259
+ if (existsSync(join(root, "Pipfile.lock")) || existsSync(join(root, "requirements.txt")))
260
+ return "pip";
261
+ if (existsSync(join(root, "Cargo.lock")))
262
+ return "cargo";
263
+ if (existsSync(join(root, "go.sum")))
264
+ return "go";
265
+ if (existsSync(join(root, "pom.xml")))
266
+ return "maven";
267
+ if (existsSync(join(root, "build.gradle")) || existsSync(join(root, "build.gradle.kts")))
268
+ return "gradle";
269
+ return "none";
270
+ }
271
+ function detectLinter(root, pkg) {
272
+ if (hasDep(pkg, "@biomejs/biome") || existsSync(join(root, "biome.json")) || existsSync(join(root, "biome.jsonc")))
273
+ return "biome";
274
+ if (hasDep(pkg, "oxlint") || hasDep(pkg, "oxc"))
275
+ return "oxlint";
276
+ if (hasDep(pkg, "eslint") || existsSync(join(root, ".eslintrc.json")) || existsSync(join(root, ".eslintrc.js")) || existsSync(join(root, "eslint.config.js")) || existsSync(join(root, "eslint.config.mjs")))
277
+ return "eslint";
278
+ if (existsSync(join(root, "ruff.toml")) || existsSync(join(root, ".ruff.toml")))
279
+ return "ruff";
280
+ if (existsSync(join(root, "pyproject.toml"))) {
281
+ const content = safeRead(join(root, "pyproject.toml"));
282
+ if (content.includes("[tool.ruff"))
283
+ return "ruff";
284
+ if (content.includes("[tool.pylint") || content.includes("pylint"))
285
+ return "pylint";
286
+ if (content.includes("flake8"))
287
+ return "flake8";
288
+ }
289
+ if (existsSync(join(root, ".golangci.yml")) || existsSync(join(root, ".golangci.yaml")))
290
+ return "golangci-lint";
291
+ if (existsSync(join(root, "Cargo.toml")))
292
+ return "clippy";
293
+ if (existsSync(join(root, ".rubocop.yml")))
294
+ return "rubocop";
295
+ return "none";
296
+ }
297
+ function detectFormatter(root, pkg) {
298
+ if (hasDep(pkg, "@biomejs/biome") || existsSync(join(root, "biome.json")))
299
+ return "biome";
300
+ if (hasDep(pkg, "prettier") || existsSync(join(root, ".prettierrc")) || existsSync(join(root, ".prettierrc.json")) || existsSync(join(root, "prettier.config.js")) || existsSync(join(root, "prettier.config.mjs")))
301
+ return "prettier";
302
+ if (existsSync(join(root, "pyproject.toml"))) {
303
+ const content = safeRead(join(root, "pyproject.toml"));
304
+ if (content.includes("[tool.ruff") && content.includes("format"))
305
+ return "ruff";
306
+ if (content.includes("[tool.black") || content.includes("black"))
307
+ return "black";
308
+ }
309
+ if (existsSync(join(root, "go.mod")))
310
+ return "gofmt";
311
+ if (existsSync(join(root, "Cargo.toml")))
312
+ return "rustfmt";
313
+ return "none";
314
+ }
315
+ function detectDatabase(root) {
316
+ for (const f of ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"]) {
317
+ const content = safeRead(join(root, f));
318
+ if (!content)
319
+ continue;
320
+ if (content.includes("postgres"))
321
+ return "postgresql";
322
+ if (content.includes("mysql") || content.includes("mariadb"))
323
+ return "mysql";
324
+ if (content.includes("mongo"))
325
+ return "mongodb";
326
+ if (content.includes("redis"))
327
+ return "redis";
328
+ }
329
+ for (const f of [".env", ".env.local", ".env.development"]) {
330
+ const content = safeRead(join(root, f));
331
+ if (!content)
332
+ continue;
333
+ if (content.includes("postgres"))
334
+ return "postgresql";
335
+ if (content.includes("mysql"))
336
+ return "mysql";
337
+ if (content.includes("mongodb") || content.includes("mongo+srv"))
338
+ return "mongodb";
339
+ if (content.includes("redis://"))
340
+ return "redis";
341
+ }
342
+ if (existsSync(join(root, "prisma", "schema.prisma"))) {
343
+ const content = safeRead(join(root, "prisma", "schema.prisma"));
344
+ if (content.includes("postgresql"))
345
+ return "postgresql";
346
+ if (content.includes("mysql"))
347
+ return "mysql";
348
+ if (content.includes("sqlite"))
349
+ return "sqlite";
350
+ if (content.includes("mongodb"))
351
+ return "mongodb";
352
+ }
353
+ for (const f of ["*.db", "*.sqlite", "*.sqlite3"]) {
354
+ if (existsSync(join(root, "db.sqlite")) || existsSync(join(root, "database.sqlite")) || existsSync(join(root, "dev.db"))) {
355
+ return "sqlite";
356
+ }
357
+ }
358
+ return "none";
359
+ }
360
+ function detectRuntime() {
361
+ const isContainer = existsSync("/.dockerenv") || existsSync("/run/.containerenv") || safeRead("/proc/1/cgroup").includes("docker");
362
+ const isSSH = !!process__default.env.SSH_CLIENT || !!process__default.env.SSH_TTY || !!process__default.env.SSH_CONNECTION;
363
+ const isCI = !!(process__default.env.CI || process__default.env.GITHUB_ACTIONS || process__default.env.GITLAB_CI || process__default.env.JENKINS_URL || process__default.env.CIRCLECI || process__default.env.TRAVIS || process__default.env.BUILDKITE);
364
+ const isWSL = safeRead("/proc/version").toLowerCase().includes("microsoft");
365
+ const isMac = process__default.platform === "darwin";
366
+ const hasDisplay = !!(process__default.env.DISPLAY || process__default.env.WAYLAND_DISPLAY || process__default.env.TERM_PROGRAM);
367
+ const isHeadless = !isMac && !hasDisplay && !isWSL;
368
+ const hasBrowser = isMac || hasDisplay || isWSL;
369
+ return {
370
+ isContainer,
371
+ isHeadless,
372
+ isSSH,
373
+ isCI,
374
+ isWSL,
375
+ hasBrowser
376
+ };
377
+ }
378
+ function detectMonorepo(root, pkg) {
379
+ if (pkg?.workspaces)
380
+ return true;
381
+ if (existsSync(join(root, "pnpm-workspace.yaml")))
382
+ return true;
383
+ if (existsSync(join(root, "lerna.json")))
384
+ return true;
385
+ if (existsSync(join(root, "nx.json")))
386
+ return true;
387
+ if (existsSync(join(root, "turbo.json")))
388
+ return true;
389
+ return false;
390
+ }
391
+ function detectConventionalCommits(root, pkg) {
392
+ if (existsSync(join(root, ".commitlintrc.json")) || existsSync(join(root, ".commitlintrc.js")) || existsSync(join(root, "commitlint.config.js")) || existsSync(join(root, "commitlint.config.mjs"))) {
393
+ return true;
394
+ }
395
+ if (hasDep(pkg, "@commitlint/cli") || hasDep(pkg, "@commitlint/config-conventional"))
396
+ return true;
397
+ try {
398
+ const log = execSync("git log --oneline -10 2>/dev/null", { cwd: root, encoding: "utf-8", timeout: 3e3 });
399
+ const conventionalPattern = /^[a-f0-9]+ (feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)(\(.+\))?!?:/m;
400
+ const lines = log.trim().split("\n").filter(Boolean);
401
+ const matches = lines.filter((l) => conventionalPattern.test(l));
402
+ return lines.length > 0 && matches.length / lines.length > 0.5;
403
+ } catch {
404
+ return false;
405
+ }
406
+ }
407
+ function detectGitHooks(root, pkg) {
408
+ if (existsSync(join(root, ".husky")))
409
+ return true;
410
+ if (hasDep(pkg, "husky") || hasDep(pkg, "simple-git-hooks") || hasDep(pkg, "lefthook"))
411
+ return true;
412
+ if (existsSync(join(root, ".lefthook.yml")))
413
+ return true;
414
+ return false;
415
+ }
416
+ function detectCI(root) {
417
+ return existsSync(join(root, ".github", "workflows")) || existsSync(join(root, ".gitlab-ci.yml")) || existsSync(join(root, ".circleci")) || existsSync(join(root, "Jenkinsfile")) || existsSync(join(root, ".travis.yml")) || existsSync(join(root, "bitbucket-pipelines.yml"));
418
+ }
419
+ function safeRead(path) {
420
+ try {
421
+ if (!existsSync(path))
422
+ return "";
423
+ return readFileSync(path, "utf-8");
424
+ } catch {
425
+ return "";
426
+ }
427
+ }
428
+
429
+ class SmartDefaultsDetector {
430
+ /**
431
+ * Detect environment and generate smart defaults
432
+ */
433
+ async detect(cwd) {
434
+ const platform = getPlatform();
435
+ const apiKey = this.detectApiKey();
436
+ const apiProvider = this.detectApiProvider(apiKey);
437
+ const ccVersion = await this.detectClaudeCodeVersion();
438
+ const projectContext = scanProject(cwd);
439
+ return {
440
+ // Environment detection
441
+ platform,
442
+ homeDir: homedir(),
443
+ // API configuration
444
+ apiKey,
445
+ apiProvider,
446
+ // Recommended MCP services based on platform + project
447
+ mcpServices: this.getRecommendedMcpServices(platform, projectContext),
448
+ // Essential skills — reduced in CI/container (non-interactive)
449
+ skills: projectContext.runtime.isCI || projectContext.runtime.isContainer ? ["ccjk:git-commit"] : [
450
+ "ccjk:git-commit",
451
+ "ccjk:feat",
452
+ "ccjk:workflow",
453
+ "ccjk:init-project",
454
+ "ccjk:git-worktree"
455
+ ],
456
+ // Core agents — skip in CI/container (non-interactive)
457
+ agents: projectContext.runtime.isCI || projectContext.runtime.isContainer ? [] : [
458
+ "typescript-cli-architect",
459
+ "ccjk-testing-specialist"
460
+ ],
461
+ // Code tool detection
462
+ codeToolType: this.detectCodeToolType(),
463
+ // Workflow preferences
464
+ workflows: {
465
+ outputStyle: "engineer-professional",
466
+ gitWorkflow: projectContext.usesConventionalCommits ? "conventional-commits" : "conventional-commits",
467
+ sixStepWorkflow: true,
468
+ orchestrationLevel: resolveOrchestrationLevelFromRuntime(projectContext.runtime)
469
+ },
470
+ // Tool integrations
471
+ tools: {
472
+ ccr: this.shouldEnableCCR(),
473
+ cometix: this.shouldEnableCometix(),
474
+ ccusage: this.shouldEnableCCUsage()
475
+ },
476
+ // Claude Code native features
477
+ claudeCodeVersion: ccVersion,
478
+ nativeFeatures: this.detectNativeFeatures(ccVersion),
479
+ // Project context
480
+ projectContext,
481
+ // Recommended hooks based on project toolchain
482
+ recommendedHooks: this.getRecommendedHooks(projectContext),
483
+ // SSH session flag for quick-setup notice
484
+ sshDetected: projectContext.runtime.isSSH || void 0
485
+ };
486
+ }
487
+ /**
488
+ * Detect installed Claude Code version
489
+ */
490
+ async detectClaudeCodeVersion() {
491
+ const candidateCommands = [
492
+ CODE_TOOL_INFO["claude-code"].runtimeCommand,
493
+ CODE_TOOL_INFO.myclaude.runtimeCommand
494
+ ];
495
+ for (const command of candidateCommands) {
496
+ try {
497
+ if (!await commandExists(command)) {
498
+ continue;
499
+ }
500
+ const output = execSync(`${command} --version 2>/dev/null || echo ""`, {
501
+ encoding: "utf-8",
502
+ timeout: 5e3
503
+ }).trim();
504
+ const match = output.match(/(\d+\.\d+\.\d+)/);
505
+ if (match) {
506
+ return match[1];
507
+ }
508
+ } catch {
509
+ }
510
+ }
511
+ return void 0;
512
+ }
513
+ /**
514
+ * Detect which Claude Code native features are available
515
+ * based on installed version
516
+ */
517
+ detectNativeFeatures(version) {
518
+ return {
519
+ hooks: this.versionSupports(version, "1.0.6"),
520
+ plansDirectory: this.versionSupports(version, "1.0.10"),
521
+ memory: this.versionSupports(version, "1.0.12"),
522
+ subagents: this.versionSupports(version, "1.0.3"),
523
+ toolSearch: this.versionSupports(version, "1.0.10"),
524
+ statusLine: this.versionSupports(version, "1.0.8")
525
+ };
526
+ }
527
+ /**
528
+ * Check if a version meets the minimum requirement
529
+ */
530
+ versionSupports(version, minVersion) {
531
+ if (!version)
532
+ return false;
533
+ const parts = version.split(".").map(Number);
534
+ const minParts = minVersion.split(".").map(Number);
535
+ for (let i = 0; i < 3; i++) {
536
+ if ((parts[i] || 0) > (minParts[i] || 0))
537
+ return true;
538
+ if ((parts[i] || 0) < (minParts[i] || 0))
539
+ return false;
540
+ }
541
+ return true;
542
+ }
543
+ /**
544
+ * Detect API key from environment variables
545
+ */
546
+ detectApiKey() {
547
+ const envVars = [
548
+ "ANTHROPIC_API_KEY",
549
+ "CLAUDE_API_KEY",
550
+ "API_KEY"
551
+ ];
552
+ for (const envVar of envVars) {
553
+ const value = process.env[envVar];
554
+ if (value && value.length >= 10) {
555
+ return value;
556
+ }
557
+ }
558
+ const claudeConfigPath = join(homedir(), ".config", "claude", "config.json");
559
+ if (existsSync(claudeConfigPath)) {
560
+ try {
561
+ const configContent = readFileSync(claudeConfigPath, "utf-8");
562
+ const config = JSON.parse(configContent);
563
+ if (config.apiKey && config.apiKey.length >= 10) {
564
+ return config.apiKey;
565
+ }
566
+ } catch {
567
+ }
568
+ }
569
+ return void 0;
570
+ }
571
+ /**
572
+ * Detect API provider based on API key pattern
573
+ */
574
+ detectApiProvider(apiKey) {
575
+ if (!apiKey) {
576
+ return void 0;
577
+ }
578
+ if (apiKey.startsWith("sk-ant-")) {
579
+ return "anthropic";
580
+ }
581
+ return void 0;
582
+ }
583
+ /**
584
+ * Detect installed code tool type (instance method delegates to static)
585
+ */
586
+ detectCodeToolType() {
587
+ return SmartDefaultsDetector.detectCodeToolType();
588
+ }
589
+ /**
590
+ * Detect installed code tool type by checking filesystem markers.
591
+ * This is a static method so it can be called without instantiating the full detector.
592
+ */
593
+ static detectCodeToolType() {
594
+ const myclaudeMarkers = [
595
+ join(homedir(), ".claude.json"),
596
+ join(homedir(), ".claude", "config.json")
597
+ ];
598
+ try {
599
+ if (myclaudeMarkers.some((p) => existsSync(p))) {
600
+ const globalConfigPath = join(homedir(), ".claude.json");
601
+ if (existsSync(globalConfigPath)) {
602
+ const configContent = readFileSync(globalConfigPath, "utf-8");
603
+ const config = JSON.parse(configContent);
604
+ if (config.myclaudeActiveProviderProfileId || config.myclaudeProviderProfiles) {
605
+ return "myclaude";
606
+ }
607
+ }
608
+ }
609
+ } catch {
610
+ }
611
+ const claudeCodePaths = [
612
+ join(homedir(), ".claude"),
613
+ join(homedir(), ".config", "claude")
614
+ ];
615
+ if (claudeCodePaths.some((p) => existsSync(p))) {
616
+ return "claude-code";
617
+ }
618
+ const codexPath = join(homedir(), ".codex");
619
+ if (existsSync(codexPath)) {
620
+ return "codex";
621
+ }
622
+ return "myclaude";
623
+ }
624
+ /**
625
+ * Check if CCR (Claude Code Router) should be enabled
626
+ */
627
+ shouldEnableCCR() {
628
+ const ccrPaths = [
629
+ join(homedir(), ".local", "bin", "ccr"),
630
+ join(homedir(), ".cargo", "bin", "ccr"),
631
+ "/usr/local/bin/ccr"
632
+ ];
633
+ return ccrPaths.some((path) => existsSync(path));
634
+ }
635
+ /**
636
+ * Check if Cometix should be enabled
637
+ */
638
+ shouldEnableCometix() {
639
+ const cometixPaths = [
640
+ join(homedir(), ".local", "bin", "cometix"),
641
+ join(homedir(), ".cargo", "bin", "cometix"),
642
+ "/usr/local/bin/cometix"
643
+ ];
644
+ return cometixPaths.some((path) => existsSync(path));
645
+ }
646
+ /**
647
+ * Check if CCUsage should be enabled
648
+ */
649
+ shouldEnableCCUsage() {
650
+ const ccusagePaths = [
651
+ join(homedir(), ".local", "bin", "ccusage"),
652
+ join(homedir(), ".cargo", "bin", "ccusage"),
653
+ "/usr/local/bin/ccusage"
654
+ ];
655
+ return ccusagePaths.some((path) => existsSync(path));
656
+ }
657
+ /**
658
+ * Get recommended MCP services based on environment + project context
659
+ */
660
+ getRecommendedMcpServices(platform, project) {
661
+ return ["context7"];
662
+ }
663
+ /**
664
+ * Get recommended hook template IDs based on project toolchain
665
+ */
666
+ getRecommendedHooks(project) {
667
+ const runtime = project.runtime;
668
+ if (runtime.isCI) {
669
+ const hooks2 = [];
670
+ if (project.linter !== "none")
671
+ hooks2.push("pre-commit-lint-check");
672
+ if (project.testRunner !== "none")
673
+ hooks2.push("test-before-commit");
674
+ return hooks2;
675
+ }
676
+ if (runtime.isContainer) {
677
+ const hooks2 = [];
678
+ if (project.linter !== "none")
679
+ hooks2.push("pre-commit-lint-check");
680
+ if (project.testRunner !== "none")
681
+ hooks2.push("test-before-commit");
682
+ return hooks2;
683
+ }
684
+ const hooks = [];
685
+ if (!runtime.isHeadless) {
686
+ hooks.push("block-dev-server");
687
+ }
688
+ hooks.push("git-push-confirm");
689
+ const jsLangs = ["typescript", "javascript"];
690
+ if (jsLangs.includes(project.language)) {
691
+ hooks.push("warn-console-log");
692
+ }
693
+ hooks.push("block-unwanted-docs");
694
+ if (project.testRunner !== "none") {
695
+ hooks.push("test-before-commit");
696
+ }
697
+ if (project.formatter !== "none") {
698
+ hooks.push("auto-format-on-save");
699
+ }
700
+ if (project.linter !== "none") {
701
+ hooks.push("pre-commit-lint-check");
702
+ }
703
+ return hooks;
704
+ }
705
+ /**
706
+ * Get recommended skills based on user type
707
+ */
708
+ getRecommendedSkills(userType = "intermediate") {
709
+ const core = [
710
+ "ccjk:git-commit",
711
+ "ccjk:init-project"
712
+ ];
713
+ if (userType === "beginner") {
714
+ return [...core, "ccjk:workflow"];
715
+ }
716
+ if (userType === "intermediate") {
717
+ return [...core, "ccjk:feat", "ccjk:workflow", "ccjk:git-worktree"];
718
+ }
719
+ if (userType === "advanced") {
720
+ return [
721
+ ...core,
722
+ "ccjk:feat",
723
+ "ccjk:workflow",
724
+ "ccjk:git-worktree",
725
+ "ccjk:git-rollback",
726
+ "ccjk:git-cleanBranches"
727
+ ];
728
+ }
729
+ return core;
730
+ }
731
+ /**
732
+ * Validate detected defaults
733
+ */
734
+ validateDefaults(defaults) {
735
+ const issues = [];
736
+ if (defaults.apiKey) {
737
+ if (defaults.apiKey.length < 10) {
738
+ issues.push("API key appears too short to be valid");
739
+ } else if (defaults.apiProvider === "anthropic" && !defaults.apiKey.startsWith("sk-ant-")) {
740
+ issues.push("API key format appears invalid (should start with sk-ant-)");
741
+ }
742
+ }
743
+ if (!["darwin", "linux", "win32"].includes(defaults.platform)) {
744
+ issues.push(`Platform ${defaults.platform} may not be fully supported`);
745
+ }
746
+ if (!existsSync(defaults.homeDir)) {
747
+ issues.push("Home directory is not accessible");
748
+ }
749
+ return {
750
+ valid: issues.length === 0,
751
+ issues
752
+ };
753
+ }
754
+ }
755
+ async function detectSmartDefaults() {
756
+ const detector = new SmartDefaultsDetector();
757
+ return detector.detect();
758
+ }
759
+ function detectCodeToolType() {
760
+ return SmartDefaultsDetector.detectCodeToolType();
761
+ }
762
+
763
+ const smartDefaults = {
764
+ __proto__: null,
765
+ SmartDefaultsDetector: SmartDefaultsDetector,
766
+ detectCodeToolType: detectCodeToolType,
767
+ detectSmartDefaults: detectSmartDefaults
768
+ };
769
+
770
+ const CODE_TYPE_ABBREVIATIONS = {
771
+ cc: "claude-code",
772
+ mc: "myclaude",
773
+ mycode: "myclaude",
774
+ cx: "codex"
775
+ };
776
+ const STARTUP_CODE_TOOL_CHOICES = ["myclaude", "claude-code", "codex"];
777
+ async function resolveCodeType(codeTypeParam) {
778
+ if (codeTypeParam) {
779
+ const normalizedParam = codeTypeParam.toLowerCase().trim();
780
+ if (normalizedParam in CODE_TYPE_ABBREVIATIONS) {
781
+ return CODE_TYPE_ABBREVIATIONS[normalizedParam];
782
+ }
783
+ if (normalizedParam in CODE_TOOL_ALIASES) {
784
+ return CODE_TOOL_ALIASES[normalizedParam];
785
+ }
786
+ if (isValidCodeType(normalizedParam)) {
787
+ return normalizedParam;
788
+ }
789
+ const validAbbreviations = Object.keys(CODE_TYPE_ABBREVIATIONS);
790
+ const validFullTypes = Object.values(CODE_TYPE_ABBREVIATIONS);
791
+ const validOptions = [...validAbbreviations, ...validFullTypes].join(", ");
792
+ let defaultValue = DEFAULT_CODE_TOOL_TYPE;
793
+ try {
794
+ const config = await readZcfConfigAsync();
795
+ if (config?.codeToolType && isValidCodeType(config.codeToolType)) {
796
+ defaultValue = config.codeToolType;
797
+ }
798
+ } catch {
799
+ }
800
+ throw new Error(
801
+ i18n.t("errors:invalidCodeType", { value: codeTypeParam, validOptions, defaultValue })
802
+ );
803
+ }
804
+ const storedType = await getStoredCodeType();
805
+ if (storedType) {
806
+ return storedType;
807
+ }
808
+ try {
809
+ const freshDetected = detectCodeToolType();
810
+ if (isValidCodeType(freshDetected)) {
811
+ return freshDetected;
812
+ }
813
+ } catch {
814
+ }
815
+ return DEFAULT_CODE_TOOL_TYPE;
816
+ }
817
+ function isValidCodeType(value) {
818
+ return isCodeToolType(value);
819
+ }
820
+ async function getStoredCodeType() {
821
+ try {
822
+ const config = await readZcfConfigAsync();
823
+ if (config?.codeToolType && isValidCodeType(config.codeToolType)) {
824
+ return config.codeToolType;
825
+ }
826
+ } catch {
827
+ }
828
+ return null;
829
+ }
830
+ function persistCodeType(codeToolType) {
831
+ updateZcfConfig({ codeToolType });
832
+ }
833
+ async function promptStartupCodeType() {
834
+ const isZh = i18n.language === "zh-CN";
835
+ const { codeToolType } = await inquirer.prompt({
836
+ type: "list",
837
+ name: "codeToolType",
838
+ message: isZh ? "\u9009\u62E9\u4EE3\u7801\u5DE5\u5177" : "Choose your code tool",
839
+ choices: STARTUP_CODE_TOOL_CHOICES.map((tool) => {
840
+ if (tool === "myclaude") {
841
+ return {
842
+ name: isZh ? `${tool} - Provider-first \u63A7\u5236\u4E2D\u5FC3\uFF08\u9ED8\u8BA4\u63A8\u8350\uFF09` : `${tool} - Provider-first control center (recommended default)`,
843
+ value: tool
844
+ };
845
+ }
846
+ if (tool === "claude-code") {
847
+ return {
848
+ name: isZh ? "Claude Code - Claude \u5BB6\u65CF\u7ECF\u5178\u63A7\u5236\u4E2D\u5FC3" : "Claude Code - Classic Claude-family control center",
849
+ value: tool
850
+ };
851
+ }
852
+ return {
853
+ name: isZh ? "Codex - Codex \u4E13\u5C5E\u63A7\u5236\u4E2D\u5FC3\u3001Provider / MCP / Memory \u914D\u7F6E" : "Codex - Codex-specific control center for provider, MCP, and memory setup",
854
+ value: tool
855
+ };
856
+ }),
857
+ default: 0
858
+ });
859
+ persistCodeType(codeToolType);
860
+ return codeToolType;
861
+ }
862
+ async function resolveStartupCodeType(options = {}) {
863
+ if (options.codeTypeParam) {
864
+ const resolvedType = await resolveCodeType(options.codeTypeParam);
865
+ persistCodeType(resolvedType);
866
+ return resolvedType;
867
+ }
868
+ const storedType = await getStoredCodeType();
869
+ if (storedType) {
870
+ return storedType;
871
+ }
872
+ if (options.interactive) {
873
+ return await promptStartupCodeType();
874
+ }
875
+ return await resolveCodeType();
876
+ }
877
+
878
+ export { STARTUP_CODE_TOOL_CHOICES as S, resolveStartupCodeType as a, smartDefaults as b, detectSmartDefaults as d, parseOrchestrationLevel as p, resolveCodeType as r, scanProject as s, writeOrchestrationPolicy as w };