zcf 3.4.0 → 3.4.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/README.md CHANGED
@@ -68,6 +68,12 @@ More usage, options, and workflows: see documentation.
68
68
 
69
69
  - https://zcf.ufomiao.com/
70
70
 
71
+ ## 💬 Community
72
+
73
+ Join our Telegram group for support, discussions, and updates:
74
+
75
+ [![Telegram](https://img.shields.io/badge/Telegram-Join%20Chat-blue?style=flat&logo=telegram)](https://t.me/ufomiao_zcf)
76
+
71
77
  ## 🙏 Acknowledgments
72
78
 
73
79
  This project is inspired by and incorporates work from:
@@ -18,7 +18,7 @@ import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
18
18
  import i18next from 'i18next';
19
19
  import Backend from 'i18next-fs-backend';
20
20
 
21
- const version = "3.4.0";
21
+ const version = "3.4.1";
22
22
  const homepage = "https://github.com/UfoMiao/zcf";
23
23
 
24
24
  const i18n = i18next.createInstance();
@@ -2150,7 +2150,7 @@ async function updateClaudeCode(force = false, skipPrompt = false) {
2150
2150
  }
2151
2151
  const updateSpinner = ora(format(i18n.t("updater:updating"), { tool: "Claude Code" })).start();
2152
2152
  try {
2153
- await execAsync$2("npm update -g @anthropic-ai/claude-code");
2153
+ await execAsync$2("claude update");
2154
2154
  updateSpinner.succeed(format(i18n.t("updater:updateSuccess"), { tool: "Claude Code" }));
2155
2155
  return true;
2156
2156
  } catch (error) {
@@ -3007,15 +3007,52 @@ function getRootDir$1() {
3007
3007
  }
3008
3008
  return dirname(currentFilePath);
3009
3009
  }
3010
+ async function detectCodexInstallMethod() {
3011
+ try {
3012
+ const brewResult = await x("brew", ["list", "--cask", "codex"], { throwOnError: false });
3013
+ if (brewResult.exitCode === 0) {
3014
+ return "homebrew";
3015
+ }
3016
+ } catch {
3017
+ }
3018
+ try {
3019
+ const npmResult = await x("npm", ["list", "-g", "@openai/codex"], { throwOnError: false });
3020
+ if (npmResult.exitCode === 0 && npmResult.stdout.includes("@openai/codex")) {
3021
+ return "npm";
3022
+ }
3023
+ } catch {
3024
+ }
3025
+ return "unknown";
3026
+ }
3010
3027
  async function executeCodexInstallation(isUpdate, skipMethodSelection = false) {
3011
3028
  if (isUpdate) {
3012
3029
  console.log(ansis.cyan(i18n.t("codex:updatingCli")));
3013
- const { command, args, usedSudo } = wrapCommandWithSudo("npm", ["install", "-g", "@openai/codex@latest"]);
3014
- if (usedSudo)
3015
- console.log(ansis.yellow(i18n.t("codex:usingSudo")));
3016
- const result = await x(command, args);
3017
- if (result.exitCode !== 0) {
3018
- throw new Error(`Failed to update codex CLI: exit code ${result.exitCode}`);
3030
+ const installMethod = await detectCodexInstallMethod();
3031
+ if (installMethod === "homebrew") {
3032
+ console.log(ansis.gray(i18n.t("codex:detectedHomebrew")));
3033
+ const result = await x("brew", ["upgrade", "--cask", "codex"]);
3034
+ if (result.exitCode !== 0) {
3035
+ throw new Error(`Failed to update codex via Homebrew: exit code ${result.exitCode}`);
3036
+ }
3037
+ } else if (installMethod === "npm") {
3038
+ console.log(ansis.gray(i18n.t("codex:detectedNpm")));
3039
+ const { command, args, usedSudo } = wrapCommandWithSudo("npm", ["install", "-g", "@openai/codex@latest"]);
3040
+ if (usedSudo)
3041
+ console.log(ansis.yellow(i18n.t("codex:usingSudo")));
3042
+ const result = await x(command, args);
3043
+ if (result.exitCode !== 0) {
3044
+ throw new Error(`Failed to update codex CLI: exit code ${result.exitCode}`);
3045
+ }
3046
+ } else {
3047
+ console.log(ansis.yellow(i18n.t("codex:unknownInstallMethod")));
3048
+ console.log(ansis.gray(i18n.t("codex:fallingBackToNpm")));
3049
+ const { command, args, usedSudo } = wrapCommandWithSudo("npm", ["install", "-g", "@openai/codex@latest"]);
3050
+ if (usedSudo)
3051
+ console.log(ansis.yellow(i18n.t("codex:usingSudo")));
3052
+ const result = await x(command, args);
3053
+ if (result.exitCode !== 0) {
3054
+ throw new Error(`Failed to update codex CLI: exit code ${result.exitCode}`);
3055
+ }
3019
3056
  }
3020
3057
  console.log(ansis.green(i18n.t("codex:updateSuccess")));
3021
3058
  } else {
@@ -3144,14 +3181,23 @@ function parseCodexConfig(content) {
3144
3181
  }
3145
3182
  const mcpServices = [];
3146
3183
  if (tomlData.mcp_servers) {
3184
+ const KNOWN_MCP_FIELDS = /* @__PURE__ */ new Set(["command", "args", "env", "startup_timeout_ms"]);
3147
3185
  for (const [id, mcpData] of Object.entries(tomlData.mcp_servers)) {
3148
3186
  const mcp = mcpData;
3187
+ const extraFields = {};
3188
+ for (const [key, value] of Object.entries(mcp)) {
3189
+ if (!KNOWN_MCP_FIELDS.has(key)) {
3190
+ extraFields[key] = value;
3191
+ }
3192
+ }
3149
3193
  mcpServices.push({
3150
3194
  id,
3151
3195
  command: mcp.command || id,
3152
3196
  args: mcp.args || [],
3153
3197
  env: Object.keys(mcp.env || {}).length > 0 ? mcp.env : void 0,
3154
- startup_timeout_ms: mcp.startup_timeout_ms
3198
+ startup_timeout_ms: mcp.startup_timeout_ms,
3199
+ // Only add extraFields if there are any extra fields
3200
+ extraFields: Object.keys(extraFields).length > 0 ? extraFields : void 0
3155
3201
  });
3156
3202
  }
3157
3203
  }
@@ -3250,6 +3296,70 @@ function parseCodexConfig(content) {
3250
3296
  };
3251
3297
  }
3252
3298
  }
3299
+ function formatInlineTableValue(value) {
3300
+ if (value === null || value === void 0) {
3301
+ return "";
3302
+ }
3303
+ if (typeof value === "string") {
3304
+ const normalized = normalizeTomlPath(value);
3305
+ return `'${normalized}'`;
3306
+ }
3307
+ if (typeof value === "number" || typeof value === "boolean") {
3308
+ return String(value);
3309
+ }
3310
+ if (Array.isArray(value)) {
3311
+ const items = value.map((item) => {
3312
+ if (typeof item === "string") {
3313
+ const normalized = normalizeTomlPath(item);
3314
+ return `'${normalized}'`;
3315
+ }
3316
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
3317
+ return formatInlineTable(item);
3318
+ }
3319
+ return String(item);
3320
+ }).join(", ");
3321
+ return `[${items}]`;
3322
+ }
3323
+ if (typeof value === "object") {
3324
+ return formatInlineTable(value);
3325
+ }
3326
+ return String(value);
3327
+ }
3328
+ function formatInlineTable(obj) {
3329
+ const entries = Object.entries(obj).filter(([_, v]) => v !== null && v !== void 0).map(([k, v]) => `${k} = ${formatInlineTableValue(v)}`).join(", ");
3330
+ return `{${entries}}`;
3331
+ }
3332
+ function formatTomlField(key, value) {
3333
+ if (value === null || value === void 0) {
3334
+ return "";
3335
+ }
3336
+ if (typeof value === "string") {
3337
+ const normalized = normalizeTomlPath(value);
3338
+ const escaped = normalized.replace(/"/g, '\\"');
3339
+ return `${key} = "${escaped}"`;
3340
+ }
3341
+ if (typeof value === "number" || typeof value === "boolean") {
3342
+ return `${key} = ${value}`;
3343
+ }
3344
+ if (Array.isArray(value)) {
3345
+ const items = value.map((item) => {
3346
+ if (typeof item === "string") {
3347
+ const normalized = normalizeTomlPath(item);
3348
+ const escaped = normalized.replace(/"/g, '\\"');
3349
+ return `"${escaped}"`;
3350
+ }
3351
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
3352
+ return formatInlineTable(item);
3353
+ }
3354
+ return String(item);
3355
+ }).join(", ");
3356
+ return `${key} = [${items}]`;
3357
+ }
3358
+ if (typeof value === "object") {
3359
+ return `${key} = ${formatInlineTable(value)}`;
3360
+ }
3361
+ return "";
3362
+ }
3253
3363
  function readCodexConfig() {
3254
3364
  if (!exists(CODEX_CONFIG_FILE))
3255
3365
  return null;
@@ -3329,6 +3439,14 @@ function renderCodexConfig(data) {
3329
3439
  if (service.startup_timeout_ms) {
3330
3440
  lines.push(`startup_timeout_ms = ${service.startup_timeout_ms}`);
3331
3441
  }
3442
+ if (service.extraFields) {
3443
+ for (const [key, value] of Object.entries(service.extraFields)) {
3444
+ const formatted = formatTomlField(key, value);
3445
+ if (formatted) {
3446
+ lines.push(formatted);
3447
+ }
3448
+ }
3449
+ }
3332
3450
  lines.push("");
3333
3451
  }
3334
3452
  if (lines[lines.length - 1] === "") {
@@ -3353,26 +3471,46 @@ function writeAuthFile(newEntries) {
3353
3471
  }
3354
3472
  async function isCodexInstalled$1() {
3355
3473
  try {
3356
- const result = await x("npm", ["list", "-g", "--depth=0"]);
3357
- if (result.exitCode !== 0) {
3358
- return false;
3474
+ const npmResult = await x("npm", ["list", "-g", "--depth=0"]);
3475
+ if (npmResult.exitCode === 0 && npmResult.stdout.includes("@openai/codex@")) {
3476
+ return true;
3359
3477
  }
3360
- return result.stdout.includes("@openai/codex@");
3361
3478
  } catch {
3362
- return false;
3363
3479
  }
3480
+ try {
3481
+ const brewResult = await x("brew", ["list", "--cask", "codex"], { throwOnError: false });
3482
+ if (brewResult.exitCode === 0) {
3483
+ return true;
3484
+ }
3485
+ } catch {
3486
+ }
3487
+ return false;
3364
3488
  }
3365
3489
  async function getCodexVersion() {
3366
3490
  try {
3367
- const result = await x("npm", ["list", "-g", "--depth=0"]);
3368
- if (result.exitCode !== 0) {
3369
- return null;
3491
+ const npmResult = await x("npm", ["list", "-g", "--depth=0"]);
3492
+ if (npmResult.exitCode === 0) {
3493
+ const match = npmResult.stdout.match(/@openai\/codex@(\S+)/);
3494
+ if (match) {
3495
+ return match[1];
3496
+ }
3370
3497
  }
3371
- const match = result.stdout.match(/@openai\/codex@(\S+)/);
3372
- return match ? match[1] : null;
3373
3498
  } catch {
3374
- return null;
3375
3499
  }
3500
+ try {
3501
+ const brewResult = await x("brew", ["info", "--cask", "codex", "--json=v2"], { throwOnError: false });
3502
+ if (brewResult.exitCode === 0) {
3503
+ const info = JSON.parse(brewResult.stdout);
3504
+ if (info.casks && Array.isArray(info.casks) && info.casks.length > 0) {
3505
+ const cask = info.casks[0];
3506
+ if (cask.installed && typeof cask.installed === "string") {
3507
+ return cask.installed;
3508
+ }
3509
+ }
3510
+ }
3511
+ } catch {
3512
+ }
3513
+ return null;
3376
3514
  }
3377
3515
  async function checkCodexUpdate() {
3378
3516
  try {
@@ -5052,7 +5190,8 @@ async function uninstallCodeTool(codeType) {
5052
5190
  const spinner = ora(i18n.t("installation:uninstallingWith", { method, codeType: codeTypeName })).start();
5053
5191
  try {
5054
5192
  switch (method) {
5055
- case "npm": {
5193
+ case "npm":
5194
+ case "npm-global": {
5056
5195
  const packageName = codeType === "claude-code" ? "@anthropic-ai/claude-code" : "@openai/codex";
5057
5196
  const { command, args, usedSudo } = wrapCommandWithSudo("npm", ["uninstall", "-g", packageName]);
5058
5197
  if (usedSudo) {
@@ -5110,7 +5249,7 @@ async function uninstallCodeTool(codeType) {
5110
5249
  return false;
5111
5250
  }
5112
5251
  }
5113
- async function setInstallMethod(method = "npm", codeType = "claude-code") {
5252
+ async function setInstallMethod(method, codeType = "claude-code") {
5114
5253
  try {
5115
5254
  if (codeType === "claude-code") {
5116
5255
  const { readMcpConfig, writeMcpConfig } = await Promise.resolve().then(function () { return claudeConfig; });
@@ -5118,7 +5257,7 @@ async function setInstallMethod(method = "npm", codeType = "claude-code") {
5118
5257
  if (!config) {
5119
5258
  config = { mcpServers: {} };
5120
5259
  }
5121
- config.installMethod = method === "npm" ? "npm" : "native";
5260
+ config.installMethod = method === "npm" ? "npm-global" : method;
5122
5261
  writeMcpConfig(config);
5123
5262
  }
5124
5263
  } catch (error) {
@@ -5940,18 +6079,21 @@ async function init(options = {}) {
5940
6079
  options.apiModel = options.apiModel || preset.claudeCode.defaultModels[0];
5941
6080
  options.apiFastModel = options.apiFastModel || preset.claudeCode.defaultModels[1];
5942
6081
  }
6082
+ await saveSingleConfigToToml(apiConfig, options.provider, options);
5943
6083
  } else if (options.apiType === "auth_token" && options.apiKey) {
5944
6084
  apiConfig = {
5945
6085
  authType: "auth_token",
5946
6086
  key: options.apiKey,
5947
6087
  url: options.apiUrl || API_DEFAULT_URL
5948
6088
  };
6089
+ await saveSingleConfigToToml(apiConfig, void 0, options);
5949
6090
  } else if (options.apiType === "api_key" && options.apiKey) {
5950
6091
  apiConfig = {
5951
6092
  authType: "api_key",
5952
6093
  key: options.apiKey,
5953
6094
  url: options.apiUrl || API_DEFAULT_URL
5954
6095
  };
6096
+ await saveSingleConfigToToml(apiConfig, void 0, options);
5955
6097
  } else if (options.apiType === "ccr_proxy") {
5956
6098
  const ccrStatus = await isCcrInstalled();
5957
6099
  if (!ccrStatus.hasCorrectPackage) {
@@ -6321,6 +6463,55 @@ async function handleCodexConfigs(configs) {
6321
6463
  console.log(ansis.green(`\u2714 ${i18n.t("multi-config:defaultProviderSet", { name: defaultConfig.name })}`));
6322
6464
  }
6323
6465
  }
6466
+ async function saveSingleConfigToToml(apiConfig, provider, options) {
6467
+ try {
6468
+ const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
6469
+ const profile = await convertSingleConfigToProfile(apiConfig, provider, options);
6470
+ const result = await ClaudeCodeConfigManager.addProfile(profile);
6471
+ if (result.success) {
6472
+ const savedProfile = result.addedProfile || ClaudeCodeConfigManager.getProfileByName(profile.name) || profile;
6473
+ if (savedProfile.id) {
6474
+ await ClaudeCodeConfigManager.switchProfile(savedProfile.id);
6475
+ await ClaudeCodeConfigManager.applyProfileSettings(savedProfile);
6476
+ }
6477
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:singleConfigSaved", { name: profile.name })}`));
6478
+ } else {
6479
+ console.warn(ansis.yellow(`${i18n.t("configuration:singleConfigSaveFailed")}: ${result.error}`));
6480
+ }
6481
+ } catch (error) {
6482
+ console.warn(ansis.yellow(`${i18n.t("configuration:singleConfigSaveFailed")}: ${error instanceof Error ? error.message : String(error)}`));
6483
+ }
6484
+ }
6485
+ async function convertSingleConfigToProfile(apiConfig, provider, options) {
6486
+ const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
6487
+ const configName = provider && provider !== "custom" ? provider : "custom-config";
6488
+ let baseUrl = apiConfig.url || API_DEFAULT_URL;
6489
+ let primaryModel = options?.apiModel;
6490
+ let fastModel = options?.apiFastModel;
6491
+ let authType = apiConfig.authType;
6492
+ if (provider && provider !== "custom") {
6493
+ const { getProviderPreset } = await import('./api-providers.mjs');
6494
+ const preset = getProviderPreset(provider);
6495
+ if (preset?.claudeCode) {
6496
+ baseUrl = apiConfig.url || preset.claudeCode.baseUrl;
6497
+ authType = preset.claudeCode.authType;
6498
+ if (preset.claudeCode.defaultModels && preset.claudeCode.defaultModels.length >= 2) {
6499
+ primaryModel = primaryModel || preset.claudeCode.defaultModels[0];
6500
+ fastModel = fastModel || preset.claudeCode.defaultModels[1];
6501
+ }
6502
+ }
6503
+ }
6504
+ const profile = {
6505
+ name: configName,
6506
+ authType,
6507
+ apiKey: apiConfig.key,
6508
+ baseUrl,
6509
+ primaryModel,
6510
+ fastModel,
6511
+ id: ClaudeCodeConfigManager.generateProfileId(configName)
6512
+ };
6513
+ return profile;
6514
+ }
6324
6515
  async function convertToClaudeCodeProfile(config) {
6325
6516
  const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
6326
6517
  let baseUrl = config.url;
@@ -3,6 +3,10 @@
3
3
  "alreadyInstalled": "⚠️ Codex CLI already installed, skipping installation",
4
4
  "updatingCli": "🔄 Updating Codex CLI...",
5
5
  "updateSuccess": "✔ Codex CLI updated",
6
+ "detectedHomebrew": "Detected Codex installed via Homebrew, will update using Homebrew",
7
+ "detectedNpm": "Detected Codex installed via npm, will update using npm",
8
+ "unknownInstallMethod": "⚠️ Unable to detect Codex installation method",
9
+ "fallingBackToNpm": "Falling back to npm update method",
6
10
  "workflowInstall": "✔ Codex workflow templates installed",
7
11
  "backupSuccess": "✔ Backup created at {{path}}",
8
12
  "apiModePrompt": "Select API configuration mode",
@@ -62,6 +62,8 @@
62
62
  "selectMemoryOption": "Select configuration option",
63
63
  "selectOutputStyles": "Select output styles to install",
64
64
  "selectedStyles": "Selected styles",
65
+ "singleConfigSaved": "Configuration {{name}} saved",
66
+ "singleConfigSaveFailed": "Failed to save configuration",
65
67
  "updateDocsOnly": "Update workflow-related md files only with backup",
66
68
  "updatingPrompts": "Updating Claude Code memory documents...",
67
69
  "enterCustomModel": "Enter custom model name",
@@ -3,6 +3,10 @@
3
3
  "alreadyInstalled": "⚠️ Codex CLI 已安装,跳过安装步骤",
4
4
  "updatingCli": "🔄 正在更新 Codex CLI...",
5
5
  "updateSuccess": "✔ Codex CLI 更新完成",
6
+ "detectedHomebrew": "检测到 Codex 通过 Homebrew 安装,将使用 Homebrew 更新",
7
+ "detectedNpm": "检测到 Codex 通过 npm 安装,将使用 npm 更新",
8
+ "unknownInstallMethod": "⚠️ 无法检测 Codex 安装方式",
9
+ "fallingBackToNpm": "回退到 npm 更新方式",
6
10
  "workflowInstall": "✔ 已安装 Codex 工作流模板",
7
11
  "backupSuccess": "✔ 已创建备份 {{path}}",
8
12
  "apiModePrompt": "请选择 API 配置模式",
@@ -62,6 +62,8 @@
62
62
  "selectMemoryOption": "选择配置选项",
63
63
  "selectOutputStyles": "选择要安装的输出风格",
64
64
  "selectedStyles": "已选择风格",
65
+ "singleConfigSaved": "配置 {{name}} 已保存",
66
+ "singleConfigSaveFailed": "配置保存失败",
65
67
  "updateDocsOnly": "仅更新工作流相关md并备份旧配置",
66
68
  "updatingPrompts": "正在更新 Claude Code 记忆文档...",
67
69
  "enterCustomModel": "请输入自定义模型名称",
package/dist/index.d.mts CHANGED
@@ -65,6 +65,15 @@ interface InitOptions {
65
65
  }
66
66
  declare function init(options?: InitOptions): Promise<void>;
67
67
 
68
+ declare function getPlatform(): 'windows' | 'macos' | 'linux';
69
+ declare function commandExists(command: string): Promise<boolean>;
70
+ /**
71
+ * Get recommended install methods for a code tool based on current platform
72
+ * Returns methods in priority order (most recommended first)
73
+ */
74
+ type CodeType = 'claude-code' | 'codex';
75
+ type InstallMethod$1 = 'npm' | 'homebrew' | 'curl' | 'powershell' | 'cmd' | 'npm-global' | 'native';
76
+
68
77
  interface McpService {
69
78
  id: string;
70
79
  name: string;
@@ -92,7 +101,7 @@ interface ClaudeConfiguration {
92
101
  };
93
102
  env?: Record<string, string>;
94
103
  primaryApiKey?: string;
95
- installMethod?: 'npm' | 'native';
104
+ installMethod?: InstallMethod$1;
96
105
  }
97
106
 
98
107
  declare function getMcpConfigPath(): string;
@@ -185,14 +194,6 @@ declare function switchToOfficialLogin(): boolean;
185
194
  */
186
195
  declare function promptApiConfigurationAction(): Promise<'modify-partial' | 'modify-all' | 'keep-existing' | null>;
187
196
 
188
- declare function getPlatform(): 'windows' | 'macos' | 'linux';
189
- declare function commandExists(command: string): Promise<boolean>;
190
- /**
191
- * Get recommended install methods for a code tool based on current platform
192
- * Returns methods in priority order (most recommended first)
193
- */
194
- type CodeType = 'claude-code' | 'codex';
195
-
196
197
  declare function isClaudeCodeInstalled(): Promise<boolean>;
197
198
  /**
198
199
  * Install Claude Code with method selection support
@@ -235,7 +236,7 @@ declare function uninstallCodeTool(codeType: CodeType): Promise<boolean>;
235
236
  * Set installMethod in both ~/.claude.json and zcf-config
236
237
  * This ensures Claude Code knows it was installed via npm for proper auto-updates
237
238
  */
238
- declare function setInstallMethod(method?: InstallMethod | 'native', codeType?: CodeType): Promise<void>;
239
+ declare function setInstallMethod(method: InstallMethod, codeType?: CodeType): Promise<void>;
239
240
  /**
240
241
  * Detect installed version of a code tool
241
242
  * Returns version string or null if not installed
package/dist/index.d.ts CHANGED
@@ -65,6 +65,15 @@ interface InitOptions {
65
65
  }
66
66
  declare function init(options?: InitOptions): Promise<void>;
67
67
 
68
+ declare function getPlatform(): 'windows' | 'macos' | 'linux';
69
+ declare function commandExists(command: string): Promise<boolean>;
70
+ /**
71
+ * Get recommended install methods for a code tool based on current platform
72
+ * Returns methods in priority order (most recommended first)
73
+ */
74
+ type CodeType = 'claude-code' | 'codex';
75
+ type InstallMethod$1 = 'npm' | 'homebrew' | 'curl' | 'powershell' | 'cmd' | 'npm-global' | 'native';
76
+
68
77
  interface McpService {
69
78
  id: string;
70
79
  name: string;
@@ -92,7 +101,7 @@ interface ClaudeConfiguration {
92
101
  };
93
102
  env?: Record<string, string>;
94
103
  primaryApiKey?: string;
95
- installMethod?: 'npm' | 'native';
104
+ installMethod?: InstallMethod$1;
96
105
  }
97
106
 
98
107
  declare function getMcpConfigPath(): string;
@@ -185,14 +194,6 @@ declare function switchToOfficialLogin(): boolean;
185
194
  */
186
195
  declare function promptApiConfigurationAction(): Promise<'modify-partial' | 'modify-all' | 'keep-existing' | null>;
187
196
 
188
- declare function getPlatform(): 'windows' | 'macos' | 'linux';
189
- declare function commandExists(command: string): Promise<boolean>;
190
- /**
191
- * Get recommended install methods for a code tool based on current platform
192
- * Returns methods in priority order (most recommended first)
193
- */
194
- type CodeType = 'claude-code' | 'codex';
195
-
196
197
  declare function isClaudeCodeInstalled(): Promise<boolean>;
197
198
  /**
198
199
  * Install Claude Code with method selection support
@@ -235,7 +236,7 @@ declare function uninstallCodeTool(codeType: CodeType): Promise<boolean>;
235
236
  * Set installMethod in both ~/.claude.json and zcf-config
236
237
  * This ensures Claude Code knows it was installed via npm for proper auto-updates
237
238
  */
238
- declare function setInstallMethod(method?: InstallMethod | 'native', codeType?: CodeType): Promise<void>;
239
+ declare function setInstallMethod(method: InstallMethod, codeType?: CodeType): Promise<void>;
239
240
  /**
240
241
  * Detect installed version of a code tool
241
242
  * Returns version string or null if not installed
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zcf",
3
3
  "type": "module",
4
- "version": "3.4.0",
4
+ "version": "3.4.1",
5
5
  "description": "Zero-Config Code Flow - One-click configuration tool for Code Cli",
6
6
  "author": {
7
7
  "name": "Miao Da",