claude360 0.2.2 → 0.2.4
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/README.md +16 -1
- package/package.json +1 -1
- package/src/account-status.js +60 -43
- package/src/backup.js +54 -0
- package/src/diagnostics.js +63 -35
- package/src/index.js +444 -45
- package/src/init-config.js +383 -0
- package/src/init-flow.js +70 -0
- package/src/mcp-skill.js +257 -41
- package/src/menu.js +67 -5
- package/src/token-manager.js +49 -1
- package/src/tool-launcher.js +15 -8
- package/src/ui.js +137 -0
- package/src/workflows.js +331 -0
- package/src/zcf-notice.js +40 -0
package/src/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import readline from "node:readline/promises";
|
|
2
2
|
import { stdin as input, stdout as output } from "node:process";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
|
+
import { readFile as fsReadFile } from "node:fs/promises";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
6
|
+
import path from "node:path";
|
|
5
7
|
|
|
6
8
|
import { ApiClient } from "./api-client.js";
|
|
7
9
|
import { authenticateWithBrowser } from "./auth.js";
|
|
@@ -15,26 +17,41 @@ import {
|
|
|
15
17
|
formatDiagnosticsSummary,
|
|
16
18
|
runDiagnostics as collectDiagnostics,
|
|
17
19
|
} from "./diagnostics.js";
|
|
20
|
+
import {
|
|
21
|
+
configureClaudeDefaultModel,
|
|
22
|
+
configureCodexDefaultModel,
|
|
23
|
+
configureOutputLanguage,
|
|
24
|
+
configurePromptStyle,
|
|
25
|
+
importClaudeEnvPermissions,
|
|
26
|
+
resolveClaudeDir,
|
|
27
|
+
resolveCodexDir,
|
|
28
|
+
} from "./init-config.js";
|
|
29
|
+
import { buildClaudeInitSteps, buildCodexInitSteps, runFullInit } from "./init-flow.js";
|
|
18
30
|
import {
|
|
19
31
|
buildDailyMenu,
|
|
20
32
|
buildFirstRunMenu,
|
|
21
33
|
promptMenu,
|
|
34
|
+
promptMultiSelect,
|
|
22
35
|
} from "./menu.js";
|
|
23
36
|
import {
|
|
24
37
|
installCodexAgents,
|
|
38
|
+
installCodexMcps,
|
|
25
39
|
installRecommendedMcps,
|
|
26
40
|
installRecommendedSkills,
|
|
27
41
|
listInstalledEnhancements,
|
|
28
42
|
} from "./mcp-skill.js";
|
|
29
43
|
import { ensureEnvironment } from "./onboarding.js";
|
|
30
44
|
import { safeErrorMessage } from "./sanitize.js";
|
|
31
|
-
import { installOrUpdateTools as installTools } from "./tool-installer.js";
|
|
45
|
+
import { buildInstallCommand, installOrUpdateTools as installTools } from "./tool-installer.js";
|
|
32
46
|
import {
|
|
33
47
|
checkCodexCompat,
|
|
34
48
|
configureCodexProvider,
|
|
35
49
|
launchClaudeCode as startClaudeCode,
|
|
36
50
|
launchCodex as startCodex,
|
|
51
|
+
resolveCodexConfigPath,
|
|
37
52
|
} from "./tool-launcher.js";
|
|
53
|
+
import { installClaudeWorkflows, installCodexWorkflows } from "./workflows.js";
|
|
54
|
+
import { showOpenSourceNotice } from "./zcf-notice.js";
|
|
38
55
|
import { runWechatTopUp } from "./topup.js";
|
|
39
56
|
import { chooseOrCreateToken, createNewToken } from "./token-manager.js";
|
|
40
57
|
|
|
@@ -65,9 +82,22 @@ export async function runCli({
|
|
|
65
82
|
codexCompat = checkCodexCompat,
|
|
66
83
|
configureCodex = configureCodexProvider,
|
|
67
84
|
installMcps = installRecommendedMcps,
|
|
85
|
+
installCodexMcpServers = installCodexMcps,
|
|
68
86
|
installSkills = installRecommendedSkills,
|
|
69
87
|
installAgents = installCodexAgents,
|
|
88
|
+
installClaudeWfs = installClaudeWorkflows,
|
|
89
|
+
installCodexWfs = installCodexWorkflows,
|
|
70
90
|
listEnhancements = listInstalledEnhancements,
|
|
91
|
+
showNotice = showOpenSourceNotice,
|
|
92
|
+
configureLanguage = configureOutputLanguage,
|
|
93
|
+
configureStyle = configurePromptStyle,
|
|
94
|
+
configureClaudeModel = configureClaudeDefaultModel,
|
|
95
|
+
configureCodexModel = configureCodexDefaultModel,
|
|
96
|
+
importEnvPermissions = importClaudeEnvPermissions,
|
|
97
|
+
multiSelectInput = promptMultiSelect,
|
|
98
|
+
readFileImpl = fsReadFile,
|
|
99
|
+
claudeDir = resolveClaudeDir(),
|
|
100
|
+
codexDir = resolveCodexDir(),
|
|
71
101
|
ccSwitchGenerator = runCcSwitchGenerator,
|
|
72
102
|
runDiagnostics = collectDiagnostics,
|
|
73
103
|
execCommand = defaultExecCommand,
|
|
@@ -165,7 +195,7 @@ export async function runCli({
|
|
|
165
195
|
if (config.apiKey) {
|
|
166
196
|
return { apiKey: config.apiKey, tokenName: config.tokenName };
|
|
167
197
|
}
|
|
168
|
-
const token = await chooseToken({ api, promptSelect, promptInput });
|
|
198
|
+
const token = await chooseToken({ api, promptSelect, promptInput, writeLine });
|
|
169
199
|
await saveConfig({
|
|
170
200
|
apiKey: token.apiKey,
|
|
171
201
|
selectedTokenId: token.tokenId,
|
|
@@ -206,6 +236,316 @@ export async function runCli({
|
|
|
206
236
|
});
|
|
207
237
|
}
|
|
208
238
|
|
|
239
|
+
// 多选交互:基于 promptInput 的复选列表(A 全选 / I 反选 / Enter 确认)
|
|
240
|
+
const multiSelect = (options) => multiSelectInput({ ...options, promptInput, writeLine });
|
|
241
|
+
|
|
242
|
+
// 终端宽度:仅真实终端下用于表格降级,测试/管道输出不限宽保证稳定
|
|
243
|
+
const outputWidth = () => (writeLine === console.log ? (process.stdout.columns || 0) : 0);
|
|
244
|
+
|
|
245
|
+
// 开源参考声明(PRD 第 2 章):进入借鉴自 NPX ZCF 的功能前展示
|
|
246
|
+
const confirmNotice = () => showNotice({ promptSelect, writeLine });
|
|
247
|
+
|
|
248
|
+
// 检查 / 安装 / 更新工具(PRD 6.1 / 8.1):展示当前与最新版本,更新需确认
|
|
249
|
+
async function checkInstallOrUpdateTool(target, toolName, command) {
|
|
250
|
+
writeLine(`正在检查 ${toolName}...`);
|
|
251
|
+
const check = await commandVersion(execCommand, command, ["--version"]);
|
|
252
|
+
if (!check.ok) {
|
|
253
|
+
return ensureToolInstalled(target, toolName, command);
|
|
254
|
+
}
|
|
255
|
+
writeLine(`当前版本:${check.version}`);
|
|
256
|
+
const packageName = buildInstallCommand(target).packageName;
|
|
257
|
+
const latest = await execCommand("npm", ["view", packageName, "version"]);
|
|
258
|
+
if (latest.ok) {
|
|
259
|
+
writeLine(`最新版本:v${latest.stdout.trim()}`);
|
|
260
|
+
} else {
|
|
261
|
+
writeLine("最新版本:获取失败(npm 网络异常时可使用国内镜像)");
|
|
262
|
+
}
|
|
263
|
+
writeLine(`检测到 ${toolName} 将通过 npm 更新。`);
|
|
264
|
+
const action = await promptSelect(`是否更新 ${toolName}?`, [
|
|
265
|
+
{ label: "更新到最新版", value: "update" },
|
|
266
|
+
{ label: "跳过", value: "skip" },
|
|
267
|
+
]);
|
|
268
|
+
if (action !== "update") {
|
|
269
|
+
writeLine(`已跳过 ${toolName} 更新。`);
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
const results = await installOrUpdateTools({ targets: [target], confirm });
|
|
273
|
+
const result = (results || []).find((item) => item.target === target);
|
|
274
|
+
if (result?.skipped) {
|
|
275
|
+
writeLine(`已跳过 ${toolName} 更新。`);
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
if (result?.ok === false) {
|
|
279
|
+
writeLine(`更新 ${toolName} 失败:${result.error || ""}${result.remediation ? `\n建议:${result.remediation}` : ""}`);
|
|
280
|
+
writeLine("国内网络失败时可尝试:npm install -g --registry=https://registry.npmmirror.com");
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
writeLine(`✓ ${toolName} 已更新到最新版。`);
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 配置 Claude360 API(PRD 6.2):Key 选择 / 创建 / 重选,Base URL 不可手填
|
|
288
|
+
async function runClaudeApiConfigMenu() {
|
|
289
|
+
while (true) {
|
|
290
|
+
const action = await promptSelect("配置 Claude360 API", [
|
|
291
|
+
{ label: `使用当前 API Key:${config.tokenName || "(未选择)"}`, value: "current" },
|
|
292
|
+
{ label: "创建新的 API Key", value: "create" },
|
|
293
|
+
{ label: "重新选择 API Key", value: "reselect" },
|
|
294
|
+
{ label: "返回", value: "back" },
|
|
295
|
+
]);
|
|
296
|
+
if (action === "back") {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (action === "create") {
|
|
300
|
+
await doCreateKey();
|
|
301
|
+
} else if (action === "reselect") {
|
|
302
|
+
const token = await chooseToken({ api, promptSelect, promptInput, writeLine });
|
|
303
|
+
await saveConfig({
|
|
304
|
+
apiKey: token.apiKey,
|
|
305
|
+
selectedTokenId: token.tokenId,
|
|
306
|
+
tokenName: token.tokenName,
|
|
307
|
+
group: token.group,
|
|
308
|
+
});
|
|
309
|
+
writeLine(`✓ 当前 Key 已切换为 ${token.tokenName}`);
|
|
310
|
+
} else {
|
|
311
|
+
await ensureApiKey();
|
|
312
|
+
}
|
|
313
|
+
await markConfigured("claudeCode");
|
|
314
|
+
writeLine("✓ Claude Code 将在启动时注入 Claude360 配置(不修改 shell profile):");
|
|
315
|
+
writeLine(` ANTHROPIC_BASE_URL=${baseUrl}`);
|
|
316
|
+
writeLine(" ANTHROPIC_AUTH_TOKEN=<当前 API Key>");
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Claude 全局记忆(PRD 5.1 第 6 项):语言 / 风格 / 助手规则,全部写标记区块
|
|
322
|
+
async function runClaudeMemoryMenu() {
|
|
323
|
+
const claudeMemoryPath = path.join(claudeDir, "CLAUDE.md");
|
|
324
|
+
while (true) {
|
|
325
|
+
const action = await promptSelect("配置 Claude 全局记忆(~/.claude/CLAUDE.md)", [
|
|
326
|
+
{ label: "AI 输出语言", value: "language" },
|
|
327
|
+
{ label: "系统提示词风格", value: "style" },
|
|
328
|
+
{ label: "编程助手规则 / 工作流 Skill", value: "skills" },
|
|
329
|
+
{ label: "返回", value: "back" },
|
|
330
|
+
]);
|
|
331
|
+
switch (action) {
|
|
332
|
+
case "language":
|
|
333
|
+
await configureLanguage({ baseDir: claudeDir, filePath: claudeMemoryPath, promptSelect, writeLine });
|
|
334
|
+
break;
|
|
335
|
+
case "style":
|
|
336
|
+
await configureStyle({ baseDir: claudeDir, filePath: claudeMemoryPath, promptSelect, writeLine });
|
|
337
|
+
break;
|
|
338
|
+
case "skills":
|
|
339
|
+
await installSkills({ promptSelect, confirm, writeLine });
|
|
340
|
+
break;
|
|
341
|
+
default:
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Codex 全局记忆(PRD 7.1 第 6 项):写 ~/.codex/AGENTS.md 标记区块
|
|
348
|
+
async function runCodexMemoryMenu() {
|
|
349
|
+
const agentsPath = path.join(codexDir, "AGENTS.md");
|
|
350
|
+
while (true) {
|
|
351
|
+
const action = await promptSelect("配置 Codex 全局记忆(~/.codex/AGENTS.md)", [
|
|
352
|
+
{ label: "AI 输出语言", value: "language" },
|
|
353
|
+
{ label: "系统提示词风格", value: "style" },
|
|
354
|
+
{ label: "Claude360 协作规范(AGENTS)", value: "agents" },
|
|
355
|
+
{ label: "返回", value: "back" },
|
|
356
|
+
]);
|
|
357
|
+
switch (action) {
|
|
358
|
+
case "language":
|
|
359
|
+
await configureLanguage({ baseDir: codexDir, filePath: agentsPath, promptSelect, writeLine });
|
|
360
|
+
break;
|
|
361
|
+
case "style":
|
|
362
|
+
await configureStyle({ baseDir: codexDir, filePath: agentsPath, promptSelect, writeLine });
|
|
363
|
+
break;
|
|
364
|
+
case "agents":
|
|
365
|
+
await installAgents({ confirm, writeLine });
|
|
366
|
+
break;
|
|
367
|
+
default:
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Claude360 Provider 菜单(PRD 8.5)
|
|
374
|
+
async function runCodexProviderMenu() {
|
|
375
|
+
while (true) {
|
|
376
|
+
writeLine("配置 Claude360 Provider\n");
|
|
377
|
+
writeLine("当前 Provider:claude360");
|
|
378
|
+
writeLine("当前 Profile:claude360\n");
|
|
379
|
+
const action = await promptSelect("请选择:", [
|
|
380
|
+
{ label: "写入 / 修复 Claude360 Provider", value: "write" },
|
|
381
|
+
{ label: "查看当前 Codex 配置", value: "view" },
|
|
382
|
+
{ label: "返回", value: "back" },
|
|
383
|
+
]);
|
|
384
|
+
if (action === "back") {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (action === "write") {
|
|
388
|
+
await doConfigureCodex();
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
const content = await readFileImpl(resolveCodexConfigPath(), "utf8");
|
|
393
|
+
writeLine("当前 ~/.codex/config.toml 内容:\n");
|
|
394
|
+
writeLine(content);
|
|
395
|
+
} catch (error) {
|
|
396
|
+
if (error?.code === "ENOENT") {
|
|
397
|
+
writeLine("未找到 ~/.codex/config.toml,可先执行「写入 / 修复 Claude360 Provider」。");
|
|
398
|
+
} else {
|
|
399
|
+
writeLine(`读取 Codex 配置失败:${safeErrorMessage(error)}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Codex 协议兼容性检测(PRD 8.6)
|
|
406
|
+
async function checkCodexCompatStep() {
|
|
407
|
+
writeLine("正在检测 Claude360 是否支持 Codex 所需协议...");
|
|
408
|
+
const compat = await codexCompat(api);
|
|
409
|
+
if (compat.supported) {
|
|
410
|
+
writeLine("✓ Claude360 已支持 Codex 所需协议");
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
writeLine("当前 Claude360 网关暂不支持 Codex 所需协议。");
|
|
414
|
+
writeLine("你仍可使用 Claude Code,或稍后更新 Claude360 CLI。");
|
|
415
|
+
const next = await promptSelect("请选择:", [
|
|
416
|
+
{ label: "返回", value: "back" },
|
|
417
|
+
{ label: "打开 Claude360 控制台", value: "console" },
|
|
418
|
+
]);
|
|
419
|
+
if (next === "console") {
|
|
420
|
+
await openPage("/console", "Claude360 控制台");
|
|
421
|
+
}
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async function testConnectionStep() {
|
|
426
|
+
const me = await fetchMe();
|
|
427
|
+
writeLine(me ? "✓ Claude360 连接测试通过" : "! Claude360 连接测试失败,可稍后在诊断菜单排查");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// ──────────────────────────────────────────────
|
|
431
|
+
// 完整初始化(PRD 4 / 5 / 7 章)
|
|
432
|
+
// ──────────────────────────────────────────────
|
|
433
|
+
|
|
434
|
+
function buildClaudeFullInitDeps({ noticeApproved = false } = {}) {
|
|
435
|
+
const claudeMemoryPath = path.join(claudeDir, "CLAUDE.md");
|
|
436
|
+
return {
|
|
437
|
+
showNotice: () => (noticeApproved ? true : confirmNotice()),
|
|
438
|
+
ensureLogin,
|
|
439
|
+
showBalance: showBalanceAndUsage,
|
|
440
|
+
ensureApiKey: async () => {
|
|
441
|
+
await ensureApiKey();
|
|
442
|
+
writeLine(`✓ 当前 Key:${config.tokenName || "-"}`);
|
|
443
|
+
},
|
|
444
|
+
installTool: () => checkInstallOrUpdateTool("claude", "Claude Code", "claude"),
|
|
445
|
+
configureApi: async () => {
|
|
446
|
+
await ensureApiKey();
|
|
447
|
+
await markConfigured("claudeCode");
|
|
448
|
+
writeLine("✓ Claude Code 将在启动时注入 Claude360 配置(不修改 shell profile):");
|
|
449
|
+
writeLine(` ANTHROPIC_BASE_URL=${baseUrl}`);
|
|
450
|
+
writeLine(" ANTHROPIC_AUTH_TOKEN=<当前 API Key>");
|
|
451
|
+
},
|
|
452
|
+
configureLanguage: () => configureLanguage({ baseDir: claudeDir, filePath: claudeMemoryPath, promptSelect, writeLine }),
|
|
453
|
+
configureStyle: () => configureStyle({ baseDir: claudeDir, filePath: claudeMemoryPath, promptSelect, writeLine }),
|
|
454
|
+
installWorkflows: () => installClaudeWfs({ claudeDir, multiSelect, confirm, writeLine }),
|
|
455
|
+
installMcps: () => installMcps({ multiSelect, confirm, writeLine }),
|
|
456
|
+
configureModel: () => configureClaudeModel({ api, claudeDir, promptSelect, writeLine }),
|
|
457
|
+
importEnvPermissions: () => importEnvPermissions({ claudeDir, confirm, writeLine }),
|
|
458
|
+
testConnection: testConnectionStep,
|
|
459
|
+
askLaunch: async () => {
|
|
460
|
+
if (await confirm("初始化完成。是否立即启动 Claude Code?")) {
|
|
461
|
+
await doLaunchClaude();
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function buildCodexFullInitDeps({ noticeApproved = false } = {}) {
|
|
468
|
+
const agentsPath = path.join(codexDir, "AGENTS.md");
|
|
469
|
+
return {
|
|
470
|
+
showNotice: () => (noticeApproved ? true : confirmNotice()),
|
|
471
|
+
ensureLogin,
|
|
472
|
+
showBalance: showBalanceAndUsage,
|
|
473
|
+
ensureApiKey: async () => {
|
|
474
|
+
await ensureApiKey();
|
|
475
|
+
writeLine(`✓ 当前 Key:${config.tokenName || "-"}`);
|
|
476
|
+
},
|
|
477
|
+
installTool: () => checkInstallOrUpdateTool("codex", "Codex", "codex"),
|
|
478
|
+
configureLanguage: () => configureLanguage({ baseDir: codexDir, filePath: agentsPath, promptSelect, writeLine }),
|
|
479
|
+
configureStyle: () => configureStyle({ baseDir: codexDir, filePath: agentsPath, promptSelect, writeLine }),
|
|
480
|
+
installAgents: () => installAgents({ confirm, writeLine }),
|
|
481
|
+
installWorkflows: () => installCodexWfs({ codexDir, multiSelect, confirm, writeLine }),
|
|
482
|
+
configureProvider: async () => {
|
|
483
|
+
await ensureApiKey();
|
|
484
|
+
await configureCodex({ config, confirmConflict: confirm, writeLine });
|
|
485
|
+
await markConfigured("codex");
|
|
486
|
+
writeLine("✓ 已写入 Codex claude360 provider/profile(~/.codex/config.toml)");
|
|
487
|
+
},
|
|
488
|
+
checkCompat: checkCodexCompatStep,
|
|
489
|
+
installMcps: () => installCodexMcpServers({ codexDir, multiSelect, confirm, writeLine }),
|
|
490
|
+
testConnection: testConnectionStep,
|
|
491
|
+
askLaunch: async () => {
|
|
492
|
+
if (await confirm("初始化完成。是否立即启动 Codex?")) {
|
|
493
|
+
await doLaunchCodex();
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async function runClaudeFullInitFlow({ noticeApproved = false } = {}) {
|
|
500
|
+
const result = await runFullInit({
|
|
501
|
+
title: "Claude Code 完整初始化",
|
|
502
|
+
steps: buildClaudeInitSteps(buildClaudeFullInitDeps({ noticeApproved })),
|
|
503
|
+
writeLine,
|
|
504
|
+
});
|
|
505
|
+
return result.completed;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async function runCodexFullInitFlow({ noticeApproved = false } = {}) {
|
|
509
|
+
const result = await runFullInit({
|
|
510
|
+
title: "Codex 完整初始化",
|
|
511
|
+
steps: buildCodexInitSteps(buildCodexFullInitDeps({ noticeApproved })),
|
|
512
|
+
writeLine,
|
|
513
|
+
});
|
|
514
|
+
return result.completed;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// 一键完整初始化菜单(PRD 第 4 章)
|
|
518
|
+
async function runFullInitMenu() {
|
|
519
|
+
while (true) {
|
|
520
|
+
const action = await promptSelect("一键完整初始化\n\n请选择要配置的工具:", [
|
|
521
|
+
{ label: "完整初始化 Claude Code", value: "claude" },
|
|
522
|
+
{ label: "完整初始化 Codex", value: "codex" },
|
|
523
|
+
{ label: "同时初始化 Claude Code + Codex", value: "both" },
|
|
524
|
+
{ label: "返回", value: "back" },
|
|
525
|
+
]);
|
|
526
|
+
switch (action) {
|
|
527
|
+
case "claude":
|
|
528
|
+
await runClaudeFullInitFlow();
|
|
529
|
+
break;
|
|
530
|
+
case "codex":
|
|
531
|
+
await runCodexFullInitFlow();
|
|
532
|
+
break;
|
|
533
|
+
case "both": {
|
|
534
|
+
// 声明只展示一次,两个流程共用
|
|
535
|
+
if (!(await confirmNotice())) {
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
if (await runClaudeFullInitFlow({ noticeApproved: true })) {
|
|
539
|
+
await runCodexFullInitFlow({ noticeApproved: true });
|
|
540
|
+
}
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
default:
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
209
549
|
async function ensureToolInstalled(target, toolName, command) {
|
|
210
550
|
const check = await commandVersion(execCommand, command, ["--version"]);
|
|
211
551
|
if (check.ok) {
|
|
@@ -440,35 +780,49 @@ export async function runCli({
|
|
|
440
780
|
return token;
|
|
441
781
|
}
|
|
442
782
|
|
|
783
|
+
// Claude Code 配置子菜单(PRD 5.1)
|
|
443
784
|
async function runClaudeCodeMenu() {
|
|
444
785
|
while (true) {
|
|
445
|
-
const action = await promptSelect("Claude Code", [
|
|
446
|
-
{ label: "
|
|
447
|
-
{ label: "
|
|
448
|
-
{ label: "
|
|
449
|
-
{ label: "
|
|
450
|
-
{ label: "
|
|
786
|
+
const action = await promptSelect("Claude Code 配置", [
|
|
787
|
+
{ label: "完整初始化", value: "full" },
|
|
788
|
+
{ label: "导入推荐工作流", value: "workflows" },
|
|
789
|
+
{ label: "配置 Claude360 API", value: "api" },
|
|
790
|
+
{ label: "配置推荐 MCP 服务", value: "mcp" },
|
|
791
|
+
{ label: "配置默认模型", value: "model" },
|
|
792
|
+
{ label: "配置 Claude 全局记忆", value: "memory" },
|
|
793
|
+
{ label: "导入推荐环境变量和权限配置", value: "env" },
|
|
794
|
+
{ label: "安装 / 更新 Claude Code", value: "install" },
|
|
451
795
|
{ label: "启动 Claude Code", value: "launch" },
|
|
452
796
|
{ label: "返回", value: "back" },
|
|
453
797
|
]);
|
|
454
798
|
switch (action) {
|
|
455
|
-
case "
|
|
456
|
-
|
|
457
|
-
await installOrUpdateTools({ targets: ["claude"], confirm });
|
|
799
|
+
case "full":
|
|
800
|
+
await runClaudeFullInitFlow();
|
|
458
801
|
break;
|
|
459
|
-
case "
|
|
460
|
-
await
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
await
|
|
802
|
+
case "workflows":
|
|
803
|
+
if (await confirmNotice()) {
|
|
804
|
+
await installClaudeWfs({ claudeDir, multiSelect, confirm, writeLine });
|
|
805
|
+
}
|
|
806
|
+
break;
|
|
807
|
+
case "api":
|
|
808
|
+
await runClaudeApiConfigMenu();
|
|
466
809
|
break;
|
|
467
810
|
case "mcp":
|
|
468
|
-
await
|
|
811
|
+
if (await confirmNotice()) {
|
|
812
|
+
await installMcps({ multiSelect, confirm, writeLine });
|
|
813
|
+
}
|
|
469
814
|
break;
|
|
470
|
-
case "
|
|
471
|
-
await
|
|
815
|
+
case "model":
|
|
816
|
+
await configureClaudeModel({ api, claudeDir, promptSelect, writeLine });
|
|
817
|
+
break;
|
|
818
|
+
case "memory":
|
|
819
|
+
await runClaudeMemoryMenu();
|
|
820
|
+
break;
|
|
821
|
+
case "env":
|
|
822
|
+
await importEnvPermissions({ claudeDir, confirm, writeLine });
|
|
823
|
+
break;
|
|
824
|
+
case "install":
|
|
825
|
+
await checkInstallOrUpdateTool("claude", "Claude Code", "claude");
|
|
472
826
|
break;
|
|
473
827
|
case "launch":
|
|
474
828
|
if (await doLaunchClaude()) {
|
|
@@ -481,26 +835,45 @@ export async function runCli({
|
|
|
481
835
|
}
|
|
482
836
|
}
|
|
483
837
|
|
|
838
|
+
// Codex 配置子菜单(PRD 7.1)
|
|
484
839
|
async function runCodexMenu() {
|
|
485
840
|
while (true) {
|
|
486
|
-
const action = await promptSelect("Codex", [
|
|
487
|
-
{ label: "
|
|
488
|
-
{ label: "
|
|
489
|
-
{ label: "
|
|
490
|
-
{ label: "
|
|
841
|
+
const action = await promptSelect("Codex 配置", [
|
|
842
|
+
{ label: "完整初始化", value: "full" },
|
|
843
|
+
{ label: "导入推荐工作流", value: "workflows" },
|
|
844
|
+
{ label: "配置 Claude360 API Provider", value: "provider" },
|
|
845
|
+
{ label: "配置推荐 MCP 服务", value: "mcp" },
|
|
846
|
+
{ label: "配置默认模型", value: "model" },
|
|
847
|
+
{ label: "配置 Codex 全局记忆", value: "memory" },
|
|
848
|
+
{ label: "安装 / 更新 Codex", value: "install" },
|
|
491
849
|
{ label: "启动 Codex", value: "launch" },
|
|
492
850
|
{ label: "返回", value: "back" },
|
|
493
851
|
]);
|
|
494
852
|
switch (action) {
|
|
495
|
-
case "
|
|
496
|
-
|
|
497
|
-
await installOrUpdateTools({ targets: ["codex"], confirm });
|
|
853
|
+
case "full":
|
|
854
|
+
await runCodexFullInitFlow();
|
|
498
855
|
break;
|
|
499
|
-
case "
|
|
500
|
-
await
|
|
856
|
+
case "workflows":
|
|
857
|
+
if (await confirmNotice()) {
|
|
858
|
+
await installCodexWfs({ codexDir, multiSelect, confirm, writeLine });
|
|
859
|
+
}
|
|
501
860
|
break;
|
|
502
|
-
case "
|
|
503
|
-
await
|
|
861
|
+
case "provider":
|
|
862
|
+
await runCodexProviderMenu();
|
|
863
|
+
break;
|
|
864
|
+
case "mcp":
|
|
865
|
+
if (await confirmNotice()) {
|
|
866
|
+
await installCodexMcpServers({ codexDir, multiSelect, confirm, writeLine });
|
|
867
|
+
}
|
|
868
|
+
break;
|
|
869
|
+
case "model":
|
|
870
|
+
await configureCodexModel({ api, codexDir, promptSelect, writeLine });
|
|
871
|
+
break;
|
|
872
|
+
case "memory":
|
|
873
|
+
await runCodexMemoryMenu();
|
|
874
|
+
break;
|
|
875
|
+
case "install":
|
|
876
|
+
await checkInstallOrUpdateTool("codex", "Codex", "codex");
|
|
504
877
|
break;
|
|
505
878
|
case "launch":
|
|
506
879
|
if (await doLaunchCodex()) {
|
|
@@ -513,24 +886,43 @@ export async function runCli({
|
|
|
513
886
|
}
|
|
514
887
|
}
|
|
515
888
|
|
|
889
|
+
// 推荐 MCP / Skill 独立菜单(PRD 第 9 章):进入时展示开源参考声明
|
|
516
890
|
async function runMcpSkillMenu() {
|
|
891
|
+
if (!(await confirmNotice())) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
517
894
|
while (true) {
|
|
518
895
|
const action = await promptSelect("推荐 MCP / Skill", [
|
|
519
|
-
{ label: "为 Claude Code 安装推荐 MCP", value: "
|
|
520
|
-
{ label: "为 Claude Code 安装推荐工作流 / Skill", value: "
|
|
521
|
-
{ label: "为 Codex 安装推荐
|
|
896
|
+
{ label: "为 Claude Code 安装推荐 MCP", value: "claude_mcp" },
|
|
897
|
+
{ label: "为 Claude Code 安装推荐工作流 / Skill", value: "claude_skill" },
|
|
898
|
+
{ label: "为 Codex 安装推荐 MCP", value: "codex_mcp" },
|
|
899
|
+
{ label: "为 Codex 安装推荐 AGENTS / prompts", value: "codex_agents" },
|
|
522
900
|
{ label: "查看已安装增强配置", value: "list" },
|
|
523
901
|
{ label: "返回", value: "back" },
|
|
524
902
|
]);
|
|
525
903
|
switch (action) {
|
|
526
|
-
case "
|
|
527
|
-
await installMcps({
|
|
904
|
+
case "claude_mcp":
|
|
905
|
+
await installMcps({ multiSelect, confirm, writeLine });
|
|
528
906
|
break;
|
|
529
|
-
case "
|
|
530
|
-
await
|
|
907
|
+
case "claude_skill": {
|
|
908
|
+
const kind = await promptSelect("请选择要安装的内容:", [
|
|
909
|
+
{ label: "推荐工作流(commands)", value: "workflows" },
|
|
910
|
+
{ label: "推荐 Skill / 全局记忆规则", value: "skills" },
|
|
911
|
+
{ label: "返回", value: "back" },
|
|
912
|
+
]);
|
|
913
|
+
if (kind === "workflows") {
|
|
914
|
+
await installClaudeWfs({ claudeDir, multiSelect, confirm, writeLine });
|
|
915
|
+
} else if (kind === "skills") {
|
|
916
|
+
await installSkills({ promptSelect, confirm, writeLine });
|
|
917
|
+
}
|
|
531
918
|
break;
|
|
532
|
-
|
|
919
|
+
}
|
|
920
|
+
case "codex_mcp":
|
|
921
|
+
await installCodexMcpServers({ codexDir, multiSelect, confirm, writeLine });
|
|
922
|
+
break;
|
|
923
|
+
case "codex_agents":
|
|
533
924
|
await installAgents({ confirm, writeLine });
|
|
925
|
+
await installCodexWfs({ codexDir, multiSelect, confirm, writeLine });
|
|
534
926
|
break;
|
|
535
927
|
case "list":
|
|
536
928
|
writeLine(await listEnhancements());
|
|
@@ -554,7 +946,7 @@ export async function runCli({
|
|
|
554
946
|
switch (action) {
|
|
555
947
|
case "diagnose": {
|
|
556
948
|
const report = await runDiagnostics({ config, api, execCommand });
|
|
557
|
-
writeLine(formatDiagnosticsSummary(report));
|
|
949
|
+
writeLine(formatDiagnosticsSummary(report, { width: outputWidth() }));
|
|
558
950
|
break;
|
|
559
951
|
}
|
|
560
952
|
case "fix_claude":
|
|
@@ -567,7 +959,7 @@ export async function runCli({
|
|
|
567
959
|
await doConfigureCodex();
|
|
568
960
|
break;
|
|
569
961
|
case "rekey": {
|
|
570
|
-
const token = await chooseToken({ api, promptSelect, promptInput });
|
|
962
|
+
const token = await chooseToken({ api, promptSelect, promptInput, writeLine });
|
|
571
963
|
await saveConfig({
|
|
572
964
|
apiKey: token.apiKey,
|
|
573
965
|
selectedTokenId: token.tokenId,
|
|
@@ -593,6 +985,10 @@ export async function runCli({
|
|
|
593
985
|
// ──────────────────────────────────────────────
|
|
594
986
|
|
|
595
987
|
async function runFirstSetup(targets) {
|
|
988
|
+
// PRD 2.1:一键配置 Claude Code / Codex 属于借鉴 ZCF 的初始化流程,先展示声明
|
|
989
|
+
if (!(await confirmNotice())) {
|
|
990
|
+
return false;
|
|
991
|
+
}
|
|
596
992
|
if (!(await ensureLogin())) {
|
|
597
993
|
return false;
|
|
598
994
|
}
|
|
@@ -728,7 +1124,7 @@ export async function runCli({
|
|
|
728
1124
|
async function runDailyFlow() {
|
|
729
1125
|
while (true) {
|
|
730
1126
|
const status = await loadAccountStatus({ api, config });
|
|
731
|
-
writeLine(formatAccountStatus(status));
|
|
1127
|
+
writeLine(formatAccountStatus({ ...status, width: outputWidth() }));
|
|
732
1128
|
writeLine("");
|
|
733
1129
|
const action = await promptMenu({ menu: buildDailyMenu(), promptInput, writeLine });
|
|
734
1130
|
switch (action) {
|
|
@@ -761,6 +1157,9 @@ export async function runCli({
|
|
|
761
1157
|
return action;
|
|
762
1158
|
}
|
|
763
1159
|
break;
|
|
1160
|
+
case "full_init":
|
|
1161
|
+
await runFullInitMenu();
|
|
1162
|
+
break;
|
|
764
1163
|
case "mcp_skill":
|
|
765
1164
|
await runMcpSkillMenu();
|
|
766
1165
|
break;
|
|
@@ -811,7 +1210,7 @@ export async function runCli({
|
|
|
811
1210
|
return "cc_switch";
|
|
812
1211
|
case "doctor": {
|
|
813
1212
|
const report = await runDiagnostics({ config, api, execCommand });
|
|
814
|
-
writeLine(formatDiagnosticsSummary(report));
|
|
1213
|
+
writeLine(formatDiagnosticsSummary(report, { width: outputWidth() }));
|
|
815
1214
|
return "doctor";
|
|
816
1215
|
}
|
|
817
1216
|
case "login":
|