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.
- package/dist/chunks/api-cli.mjs +4 -2
- package/dist/chunks/api-config-selector.mjs +2 -4
- package/dist/chunks/auto-fix.mjs +3 -1
- package/dist/chunks/ccjk-all.mjs +5 -2
- package/dist/chunks/ccjk-mcp.mjs +5 -2
- package/dist/chunks/ccjk-setup.mjs +4 -1
- package/dist/chunks/ccr.mjs +5 -8
- package/dist/chunks/check-updates.mjs +1 -4
- package/dist/chunks/claude-code-incremental-manager.mjs +4 -6
- package/dist/chunks/code-type-resolver.mjs +878 -0
- package/dist/chunks/codex-config-switch.mjs +0 -1
- package/dist/chunks/codex-provider-manager.mjs +0 -1
- package/dist/chunks/codex.mjs +2 -2
- package/dist/chunks/config-switch.mjs +2 -4
- package/dist/chunks/config.mjs +1144 -5
- package/dist/chunks/config2.mjs +6 -4
- package/dist/chunks/config3.mjs +4 -2
- package/dist/chunks/doctor.mjs +1 -1
- package/dist/chunks/evolution.mjs +47 -27
- package/dist/chunks/features.mjs +2 -3
- package/dist/chunks/index10.mjs +115 -12
- package/dist/chunks/init.mjs +44 -17
- package/dist/chunks/installer.mjs +2 -2
- package/dist/chunks/mcp-cli.mjs +18 -19
- package/dist/chunks/mcp.mjs +6 -7
- package/dist/chunks/package.mjs +1 -1
- package/dist/chunks/platform.mjs +1 -1
- package/dist/chunks/quick-setup.mjs +2 -5
- package/dist/chunks/slash-commands.mjs +1 -1
- package/dist/chunks/status.mjs +63 -16
- package/dist/chunks/uninstall.mjs +1 -3
- package/dist/chunks/update.mjs +4 -5
- package/dist/cli.mjs +58 -17
- package/dist/i18n/locales/en/configuration.json +6 -2
- package/dist/i18n/locales/en/menu.json +7 -0
- package/dist/i18n/locales/zh-CN/configuration.json +6 -2
- package/dist/i18n/locales/zh-CN/menu.json +7 -0
- package/dist/index.d.mts +64 -17
- package/dist/index.d.ts +64 -17
- package/dist/index.mjs +12 -720
- package/dist/shared/{ccjk.DHaUdzX3.mjs → ccjk.B6VCKdyy.mjs} +2 -2
- package/dist/shared/ccjk.BO45TPXJ.mjs +807 -0
- package/dist/shared/{ccjk.B4aXNclK.mjs → ccjk.CVjfbEIj.mjs} +1 -1
- package/dist/shared/{ccjk.Dz0ssUQx.mjs → ccjk.Dh6Be-ef.mjs} +1 -1
- package/package.json +1 -1
- package/dist/chunks/claude-code-config-manager.mjs +0 -811
- package/dist/chunks/claude-config.mjs +0 -286
- package/dist/chunks/intent-engine.mjs +0 -142
- package/dist/chunks/smart-defaults.mjs +0 -425
- package/dist/shared/ccjk.DJuyfrlL.mjs +0 -348
- 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 };
|