zcf 2.12.10 → 2.12.12

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
@@ -1,12 +1,14 @@
1
1
  # ZCF - Zero-Config Claude-Code Flow
2
2
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
- [![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code)
5
- [![Version](https://img.shields.io/npm/v/zcf)](https://www.npmjs.com/package/zcf)
6
- [![codecov](https://codecov.io/gh/UfoMiao/zcf/graph/badge.svg?token=HZI6K4Y7D7)](https://codecov.io/gh/UfoMiao/zcf)
7
- [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/UfoMiao/zcf)
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![License][license-src]][license-href]
6
+ [![Claude Code][claude-code-src]][claude-code-href]
7
+ [![codecov][codecov-src]][codecov-href]
8
+ [![JSDocs][jsdocs-src]][jsdocs-href]
9
+ [![Ask DeepWiki][deepwiki-src]][deepwiki-href]
8
10
 
9
- [中文](README_zh-CN.md) | **English** | [Changelog](CHANGELOG.md)
11
+ [中文](README_zh-CN.md) | **English** | [日本語](README_ja-JP.md) | [Changelog](CHANGELOG.md)
10
12
 
11
13
  > Zero-config, one-click setup for Claude Code with bilingual support, intelligent agent system and personalized AI assistant
12
14
 
@@ -286,7 +288,7 @@ After configuration:
286
288
 
287
289
  - Auto-detects Claude Code installation status
288
290
  - Uses npm for automatic installation (ensures compatibility)
289
- - Cross-platform support (Windows/macOS/Linux/Termux)
291
+ - Cross-platform support (Windows/macOS/Linux/WSL/Termux)
290
292
  - Automatic MCP service configuration
291
293
  - Smart configuration merging and partial modification support (v2.0 new)
292
294
  - Enhanced command detection mechanism (v2.1 new)
@@ -645,6 +647,17 @@ ZCF fully supports Windows platform:
645
647
 
646
648
  If you encounter MCP connection issues on Windows, running `npx zcf` will automatically fix the configuration format.
647
649
 
650
+ #### WSL Support (v2.12.12+ new)
651
+
652
+ ZCF now provides comprehensive support for Windows Subsystem for Linux (WSL):
653
+
654
+ - **Smart Detection**: Multi-layered WSL environment detection using environment variables, system files, and mount points
655
+ - **Distribution Recognition**: Automatically identifies WSL distribution (Ubuntu, Debian, etc.) for optimized configuration
656
+ - **Seamless Installation**: Native Linux-style installation experience within WSL environment
657
+ - **Path Management**: Intelligent handling of WSL-specific configuration paths and file locations
658
+
659
+ If running in WSL, ZCF will automatically detect the environment and display appropriate installation messages.
660
+
648
661
  #### Termux Support (v2.1 new)
649
662
 
650
663
  ZCF now supports running in Android Termux environment:
@@ -709,3 +722,20 @@ MIT License
709
722
  If this project helps you, please give me a ⭐️ Star!
710
723
 
711
724
  [![Star History Chart](https://api.star-history.com/svg?repos=UfoMiao/zcf&type=Date)](https://star-history.com/#UfoMiao/zcf&Date)
725
+
726
+ <!-- Badges -->
727
+
728
+ [npm-version-src]: https://img.shields.io/npm/v/zcf?style=flat&colorA=080f12&colorB=1fa669
729
+ [npm-version-href]: https://npmjs.com/package/zcf
730
+ [npm-downloads-src]: https://img.shields.io/npm/dm/zcf?style=flat&colorA=080f12&colorB=1fa669
731
+ [npm-downloads-href]: https://npmjs.com/package/zcf
732
+ [license-src]: https://img.shields.io/github/license/ufomiao/zcf.svg?style=flat&colorA=080f12&colorB=1fa669
733
+ [license-href]: https://github.com/ufomiao/zcf/blob/main/LICENSE
734
+ [claude-code-src]: https://img.shields.io/badge/Claude-Code-1fa669?style=flat&colorA=080f12&colorB=1fa669
735
+ [claude-code-href]: https://claude.ai/code
736
+ [codecov-src]: https://codecov.io/gh/UfoMiao/zcf/graph/badge.svg?token=HZI6K4Y7D7&style=flat&colorA=080f12&colorB=1fa669
737
+ [codecov-href]: https://codecov.io/gh/UfoMiao/zcf
738
+ [jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-1fa669?style=flat&colorA=080f12&colorB=1fa669
739
+ [jsdocs-href]: https://www.jsdocs.io/package/zcf
740
+ [deepwiki-src]: https://img.shields.io/badge/Ask-DeepWiki-1fa669?style=flat&colorA=080f12&colorB=1fa669
741
+ [deepwiki-href]: https://deepwiki.com/UfoMiao/zcf
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync, unlinkSync } from 'node:fs';
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, rmSync, rmdirSync, readdirSync, statSync, unlinkSync } from 'node:fs';
2
2
  import process from 'node:process';
3
3
  import ansis from 'ansis';
4
4
  import inquirer from 'inquirer';
@@ -15,7 +15,7 @@ import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
15
15
  import i18next from 'i18next';
16
16
  import Backend from 'i18next-fs-backend';
17
17
 
18
- const version = "2.12.10";
18
+ const version = "2.12.12";
19
19
  const homepage = "https://github.com/UfoMiao/zcf";
20
20
 
21
21
  const i18n = i18next.createInstance();
@@ -536,6 +536,61 @@ function copyDir(src, dest, options = {}) {
536
536
  }
537
537
  }
538
538
  }
539
+ async function isExecutable(path) {
540
+ try {
541
+ if (!exists(path)) {
542
+ return false;
543
+ }
544
+ const stats = getStats(path);
545
+ if (!stats.isFile()) {
546
+ return false;
547
+ }
548
+ if (process.platform !== "win32") {
549
+ const mode = stats.mode;
550
+ const executePermission = 73;
551
+ return (mode & executePermission) !== 0;
552
+ }
553
+ const isWinExecutable = path.endsWith(".exe") || path.endsWith(".cmd") || path.endsWith(".bat");
554
+ return isWinExecutable || !path.includes(".");
555
+ } catch {
556
+ return false;
557
+ }
558
+ }
559
+ async function remove(path) {
560
+ try {
561
+ if (!exists(path)) {
562
+ return;
563
+ }
564
+ const stats = getStats(path);
565
+ if (stats.isDirectory()) {
566
+ const entries = readDir(path);
567
+ for (const entry of entries) {
568
+ await remove(`${path}/${entry}`);
569
+ }
570
+ try {
571
+ if (rmSync) {
572
+ rmSync(path, { recursive: true, force: true });
573
+ } else if (rmdirSync) {
574
+ rmdirSync(path);
575
+ }
576
+ } catch (error) {
577
+ throw new FileSystemError(
578
+ `Failed to remove directory: ${path}`,
579
+ path,
580
+ error
581
+ );
582
+ }
583
+ } else {
584
+ removeFile(path);
585
+ }
586
+ } catch (error) {
587
+ throw new FileSystemError(
588
+ `Failed to remove: ${path}`,
589
+ path,
590
+ error
591
+ );
592
+ }
593
+ }
539
594
 
540
595
  function readJsonConfig(path, options = {}) {
541
596
  const { defaultValue = null, validate, sanitize } = options;
@@ -662,6 +717,57 @@ function getTermuxPrefix() {
662
717
  function isWindows() {
663
718
  return getPlatform() === "windows";
664
719
  }
720
+ function isWSL() {
721
+ if (process.env.WSL_DISTRO_NAME) {
722
+ return true;
723
+ }
724
+ if (existsSync("/proc/version")) {
725
+ try {
726
+ const version = readFileSync("/proc/version", "utf8");
727
+ if (version.includes("Microsoft") || version.includes("WSL")) {
728
+ return true;
729
+ }
730
+ } catch {
731
+ }
732
+ }
733
+ if (existsSync("/mnt/c")) {
734
+ return true;
735
+ }
736
+ return false;
737
+ }
738
+ function getWSLDistro() {
739
+ if (process.env.WSL_DISTRO_NAME) {
740
+ return process.env.WSL_DISTRO_NAME;
741
+ }
742
+ if (existsSync("/etc/os-release")) {
743
+ try {
744
+ const osRelease = readFileSync("/etc/os-release", "utf8");
745
+ const nameMatch = osRelease.match(/^PRETTY_NAME="(.+)"$/m);
746
+ if (nameMatch) {
747
+ return nameMatch[1];
748
+ }
749
+ } catch {
750
+ }
751
+ }
752
+ return null;
753
+ }
754
+ function getWSLInfo() {
755
+ if (!isWSL()) {
756
+ return null;
757
+ }
758
+ let version = null;
759
+ if (existsSync("/proc/version")) {
760
+ try {
761
+ version = readFileSync("/proc/version", "utf8").trim();
762
+ } catch {
763
+ }
764
+ }
765
+ return {
766
+ isWSL: true,
767
+ distro: getWSLDistro(),
768
+ version
769
+ };
770
+ }
665
771
  function getMcpCommand() {
666
772
  if (isWindows()) {
667
773
  return ["cmd", "/c", "npx"];
@@ -780,6 +886,75 @@ function addCompletedOnboarding() {
780
886
  throw error;
781
887
  }
782
888
  }
889
+ function ensureApiKeyApproved(config, apiKey) {
890
+ if (!apiKey || typeof apiKey !== "string" || apiKey.trim() === "") {
891
+ return config;
892
+ }
893
+ const truncatedApiKey = apiKey.substring(0, 20);
894
+ const updatedConfig = { ...config };
895
+ if (!updatedConfig.customApiKeyResponses) {
896
+ updatedConfig.customApiKeyResponses = {
897
+ approved: [],
898
+ rejected: []
899
+ };
900
+ }
901
+ if (!Array.isArray(updatedConfig.customApiKeyResponses.approved)) {
902
+ updatedConfig.customApiKeyResponses.approved = [];
903
+ }
904
+ if (!Array.isArray(updatedConfig.customApiKeyResponses.rejected)) {
905
+ updatedConfig.customApiKeyResponses.rejected = [];
906
+ }
907
+ const rejectedIndex = updatedConfig.customApiKeyResponses.rejected.indexOf(truncatedApiKey);
908
+ if (rejectedIndex > -1) {
909
+ updatedConfig.customApiKeyResponses.rejected.splice(rejectedIndex, 1);
910
+ }
911
+ if (!updatedConfig.customApiKeyResponses.approved.includes(truncatedApiKey)) {
912
+ updatedConfig.customApiKeyResponses.approved.push(truncatedApiKey);
913
+ }
914
+ return updatedConfig;
915
+ }
916
+ function removeApiKeyFromRejected(config, apiKey) {
917
+ if (!config.customApiKeyResponses || !Array.isArray(config.customApiKeyResponses.rejected)) {
918
+ return config;
919
+ }
920
+ const truncatedApiKey = apiKey.substring(0, 20);
921
+ const updatedConfig = { ...config };
922
+ if (updatedConfig.customApiKeyResponses) {
923
+ const rejectedIndex = updatedConfig.customApiKeyResponses.rejected.indexOf(truncatedApiKey);
924
+ if (rejectedIndex > -1) {
925
+ updatedConfig.customApiKeyResponses.rejected.splice(rejectedIndex, 1);
926
+ }
927
+ }
928
+ return updatedConfig;
929
+ }
930
+ function manageApiKeyApproval(apiKey) {
931
+ try {
932
+ let config = readMcpConfig();
933
+ if (!config) {
934
+ config = { mcpServers: {} };
935
+ }
936
+ const updatedConfig = ensureApiKeyApproved(config, apiKey);
937
+ writeMcpConfig(updatedConfig);
938
+ } catch (error) {
939
+ ensureI18nInitialized();
940
+ console.error(i18n.t("mcp:apiKeyApprovalFailed"), error);
941
+ }
942
+ }
943
+
944
+ const claudeConfig = {
945
+ __proto__: null,
946
+ addCompletedOnboarding: addCompletedOnboarding,
947
+ backupMcpConfig: backupMcpConfig,
948
+ buildMcpServerConfig: buildMcpServerConfig,
949
+ ensureApiKeyApproved: ensureApiKeyApproved,
950
+ fixWindowsMcpConfig: fixWindowsMcpConfig,
951
+ getMcpConfigPath: getMcpConfigPath,
952
+ manageApiKeyApproval: manageApiKeyApproval,
953
+ mergeMcpServers: mergeMcpServers,
954
+ readMcpConfig: readMcpConfig,
955
+ removeApiKeyFromRejected: removeApiKeyFromRejected,
956
+ writeMcpConfig: writeMcpConfig
957
+ };
783
958
 
784
959
  function cleanupPermissions(templatePermissions, userPermissions) {
785
960
  const templateSet = new Set(templatePermissions);
@@ -1394,6 +1569,14 @@ async function setupCcrConfiguration() {
1394
1569
  if (!shouldBackupAndReconfigure) {
1395
1570
  console.log(ansis.yellow(`${i18n.t("ccr:keepingExistingConfig")}`));
1396
1571
  await configureCcrProxy(existingConfig);
1572
+ try {
1573
+ const { manageApiKeyApproval } = await Promise.resolve().then(function () { return claudeConfig; });
1574
+ const apiKey = existingConfig.APIKEY || "sk-zcf-x-ccr";
1575
+ manageApiKeyApproval(apiKey);
1576
+ console.log(ansis.green(`\u2714 ${i18n.t("ccr:apiKeyApprovalSuccess")}`));
1577
+ } catch (error) {
1578
+ console.error(ansis.red(`${i18n.t("ccr:apiKeyApprovalFailed")}:`), error);
1579
+ }
1397
1580
  return true;
1398
1581
  }
1399
1582
  backupCcrConfig();
@@ -1420,6 +1603,14 @@ async function setupCcrConfiguration() {
1420
1603
  } catch (error) {
1421
1604
  console.error(ansis.red(i18n.t("errors:failedToSetOnboarding")), error);
1422
1605
  }
1606
+ try {
1607
+ const { manageApiKeyApproval } = await Promise.resolve().then(function () { return claudeConfig; });
1608
+ const apiKey = config.APIKEY || "sk-zcf-x-ccr";
1609
+ manageApiKeyApproval(apiKey);
1610
+ console.log(ansis.green(`\u2714 ${i18n.t("ccr:apiKeyApprovalSuccess")}`));
1611
+ } catch (error) {
1612
+ console.error(ansis.red(`${i18n.t("ccr:apiKeyApprovalFailed")}:`), error);
1613
+ }
1423
1614
  return true;
1424
1615
  } catch (error) {
1425
1616
  if (error.name === "ExitPromptError") {
@@ -1929,10 +2120,19 @@ function updateZcfConfig(updates) {
1929
2120
  aiOutputLang: updates.aiOutputLang || existingConfig?.aiOutputLang,
1930
2121
  outputStyles: updates.outputStyles !== void 0 ? updates.outputStyles : existingConfig?.outputStyles,
1931
2122
  defaultOutputStyle: updates.defaultOutputStyle !== void 0 ? updates.defaultOutputStyle : existingConfig?.defaultOutputStyle,
2123
+ claudeCodeInstallation: updates.claudeCodeInstallation !== void 0 ? updates.claudeCodeInstallation : existingConfig?.claudeCodeInstallation,
1932
2124
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
1933
2125
  };
1934
2126
  writeZcfConfig(newConfig);
1935
2127
  }
2128
+ function getZcfConfig() {
2129
+ const config = readZcfConfig();
2130
+ return config || {
2131
+ version: "1.0.0",
2132
+ preferredLang: "en",
2133
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
2134
+ };
2135
+ }
1936
2136
 
1937
2137
  const OUTPUT_STYLES = [
1938
2138
  // Custom styles (have template files)
@@ -2338,9 +2538,10 @@ ${i18n.t("common:goodbye")}
2338
2538
  return false;
2339
2539
  }
2340
2540
  function handleGeneralError(error) {
2341
- console.error(ansis.red("Error:"), error);
2541
+ ensureI18nInitialized();
2542
+ console.error(ansis.red(`${i18n.t("errors:generalError")}:`), error);
2342
2543
  if (error instanceof Error) {
2343
- console.error(ansis.gray(`Stack: ${error.stack}`));
2544
+ console.error(ansis.gray(`${i18n.t("errors:stackTrace")}: ${error.stack}`));
2344
2545
  }
2345
2546
  process.exit(1);
2346
2547
  }
@@ -2363,6 +2564,15 @@ async function installClaudeCode() {
2363
2564
  console.log(ansis.gray(`Node.js: ${termuxPrefix}/bin/node`));
2364
2565
  console.log(ansis.gray(`npm: ${termuxPrefix}/bin/npm`));
2365
2566
  }
2567
+ if (isWSL()) {
2568
+ const wslInfo = getWSLInfo();
2569
+ if (wslInfo?.distro) {
2570
+ console.log(ansis.yellow(`\u2139 ${i18n.t("installation:wslDetected", { distro: wslInfo.distro })}`));
2571
+ } else {
2572
+ console.log(ansis.yellow(`\u2139 ${i18n.t("installation:wslDetectedGeneric")}`));
2573
+ }
2574
+ console.log(ansis.gray(i18n.t("installation:wslPathInfo", { path: `${homedir()}/.claude/` })));
2575
+ }
2366
2576
  console.log(i18n.t("installation:installing"));
2367
2577
  try {
2368
2578
  await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
@@ -2371,6 +2581,10 @@ async function installClaudeCode() {
2371
2581
  console.log(ansis.gray(`
2372
2582
  Claude Code installed to: ${getTermuxPrefix()}/bin/claude`));
2373
2583
  }
2584
+ if (isWSL()) {
2585
+ console.log(ansis.gray(`
2586
+ ${i18n.t("installation:wslInstallSuccess")}`));
2587
+ }
2374
2588
  } catch (error) {
2375
2589
  console.error(`\u2716 ${i18n.t("installation:installFailed")}`);
2376
2590
  if (isTermux()) {
@@ -2381,6 +2595,147 @@ ${i18n.t("installation:termuxInstallHint")}
2381
2595
  throw error;
2382
2596
  }
2383
2597
  }
2598
+ async function isLocalClaudeCodeInstalled() {
2599
+ const localClaudePath = join(homedir(), ".claude", "local", "claude");
2600
+ if (!exists(localClaudePath)) {
2601
+ return false;
2602
+ }
2603
+ return await isExecutable(localClaudePath);
2604
+ }
2605
+ async function getInstallationStatus() {
2606
+ const localPath = join(homedir(), ".claude", "local", "claude");
2607
+ const [hasGlobal, hasLocal] = await Promise.all([
2608
+ isClaudeCodeInstalled(),
2609
+ isLocalClaudeCodeInstalled()
2610
+ ]);
2611
+ return {
2612
+ hasGlobal,
2613
+ hasLocal,
2614
+ localPath
2615
+ };
2616
+ }
2617
+ async function removeLocalClaudeCode() {
2618
+ const localDir = join(homedir(), ".claude", "local");
2619
+ if (!exists(localDir)) {
2620
+ return;
2621
+ }
2622
+ try {
2623
+ await remove(localDir);
2624
+ } catch (error) {
2625
+ ensureI18nInitialized();
2626
+ throw new Error(`${i18n.t("installation:failedToRemoveLocalInstallation")}: ${error}`);
2627
+ }
2628
+ }
2629
+
2630
+ const installer = {
2631
+ __proto__: null,
2632
+ getInstallationStatus: getInstallationStatus,
2633
+ installClaudeCode: installClaudeCode,
2634
+ isClaudeCodeInstalled: isClaudeCodeInstalled,
2635
+ isLocalClaudeCodeInstalled: isLocalClaudeCodeInstalled,
2636
+ removeLocalClaudeCode: removeLocalClaudeCode
2637
+ };
2638
+
2639
+ async function chooseInstallationMethod() {
2640
+ ensureI18nInitialized();
2641
+ const choices = [
2642
+ {
2643
+ name: i18n.t("installation:chooseGlobal"),
2644
+ value: "global"
2645
+ },
2646
+ {
2647
+ name: i18n.t("installation:chooseLocal"),
2648
+ value: "local"
2649
+ }
2650
+ ];
2651
+ const { installMethod } = await inquirer.prompt([
2652
+ {
2653
+ type: "list",
2654
+ name: "installMethod",
2655
+ message: i18n.t("installation:chooseInstallationMethod"),
2656
+ choices
2657
+ }
2658
+ ]);
2659
+ return installMethod;
2660
+ }
2661
+ async function handleMultipleInstallations(status) {
2662
+ ensureI18nInitialized();
2663
+ const existingConfig = getZcfConfig();
2664
+ const previousChoice = existingConfig.claudeCodeInstallation;
2665
+ if (previousChoice) {
2666
+ if (previousChoice.type === "global" && status.hasGlobal) {
2667
+ return "global";
2668
+ }
2669
+ if (previousChoice.type === "local" && status.hasLocal) {
2670
+ return "local";
2671
+ }
2672
+ }
2673
+ if (!status.hasGlobal && !status.hasLocal) {
2674
+ return "none";
2675
+ }
2676
+ if (status.hasGlobal && !status.hasLocal) {
2677
+ return "global";
2678
+ }
2679
+ if (status.hasGlobal && status.hasLocal) {
2680
+ console.warn(
2681
+ ansis.yellow(`\u26A0\uFE0F ${i18n.t("installation:multipleInstallationsDetected")}`)
2682
+ );
2683
+ console.log(`${i18n.t("installation:globalInstallation")}: ${i18n.t("installation:available")}`);
2684
+ console.log(`${i18n.t("installation:localInstallation")}: ${status.localPath}`);
2685
+ } else {
2686
+ console.warn(
2687
+ ansis.yellow(`\u26A0\uFE0F ${i18n.t("installation:onlyLocalInstallationDetected")}`)
2688
+ );
2689
+ console.log(`${i18n.t("installation:localInstallation")}: ${status.localPath}`);
2690
+ console.log(`${i18n.t("installation:globalInstallation")}: ${i18n.t("installation:notInstalled")}`);
2691
+ }
2692
+ const choice = await chooseInstallationMethod();
2693
+ try {
2694
+ if (choice === "global") {
2695
+ if (!status.hasGlobal) {
2696
+ console.log(ansis.blue(`${i18n.t("installation:installingGlobalClaudeCode")}...`));
2697
+ const { installClaudeCode } = await Promise.resolve().then(function () { return installer; });
2698
+ await installClaudeCode();
2699
+ console.log(ansis.green(`\u2714 ${i18n.t("installation:globalInstallationCompleted")}`));
2700
+ }
2701
+ if (status.hasLocal) {
2702
+ console.log(ansis.blue(`${i18n.t("installation:removingLocalInstallation")}...`));
2703
+ await removeLocalClaudeCode();
2704
+ console.log(ansis.green(`\u2714 ${i18n.t("installation:localInstallationRemoved")}`));
2705
+ }
2706
+ await saveInstallationConfig({
2707
+ type: "global",
2708
+ path: "claude",
2709
+ configDir: CLAUDE_DIR
2710
+ });
2711
+ } else {
2712
+ console.log(ansis.green(`\u2714 ${i18n.t("installation:usingLocalInstallation")}`));
2713
+ await saveInstallationConfig({
2714
+ type: "local",
2715
+ path: status.localPath,
2716
+ configDir: join(homedir(), ".claude")
2717
+ });
2718
+ }
2719
+ return choice;
2720
+ } catch (error) {
2721
+ if (choice === "global") {
2722
+ console.error(ansis.red(`\u2716 ${i18n.t("installation:failedToRemoveLocalInstallation")}: ${error}`));
2723
+ throw error;
2724
+ } else {
2725
+ console.error(ansis.red(`\u2716 ${i18n.t("installation:failedToSaveInstallationConfig")}: ${error}`));
2726
+ return choice;
2727
+ }
2728
+ }
2729
+ }
2730
+ async function saveInstallationConfig(installation) {
2731
+ try {
2732
+ updateZcfConfig({
2733
+ claudeCodeInstallation: installation
2734
+ });
2735
+ } catch (error) {
2736
+ console.error(ansis.red(`\u2716 ${i18n.t("installation:failedToSaveInstallationConfig")}: ${error}`));
2737
+ }
2738
+ }
2384
2739
 
2385
2740
  async function selectMcpServices() {
2386
2741
  ensureI18nInitialized();
@@ -2793,8 +3148,27 @@ async function init(options = {}) {
2793
3148
  }
2794
3149
  const zcfConfig = readZcfConfig();
2795
3150
  const aiOutputLang = options.skipPrompt ? options.aiOutputLang || "en" : await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
2796
- const installed = await isClaudeCodeInstalled();
2797
- if (!installed) {
3151
+ const installationStatus = await getInstallationStatus();
3152
+ if (installationStatus.hasGlobal || installationStatus.hasLocal) {
3153
+ if (!options.skipPrompt) {
3154
+ await handleMultipleInstallations(installationStatus);
3155
+ } else {
3156
+ if (installationStatus.hasLocal) {
3157
+ if (!installationStatus.hasGlobal) {
3158
+ console.log(ansis.blue(`${i18n.t("installation:installingGlobalClaudeCode")}...`));
3159
+ await installClaudeCode();
3160
+ console.log(ansis.green(`\u2714 ${i18n.t("installation:globalInstallationCompleted")}`));
3161
+ }
3162
+ if (installationStatus.hasGlobal && installationStatus.hasLocal) {
3163
+ console.log(ansis.yellow(`\u26A0\uFE0F ${i18n.t("installation:multipleInstallationsDetected")}`));
3164
+ }
3165
+ console.log(ansis.blue(`${i18n.t("installation:removingLocalInstallation")}...`));
3166
+ const { removeLocalClaudeCode } = await Promise.resolve().then(function () { return installer; });
3167
+ await removeLocalClaudeCode();
3168
+ console.log(ansis.green(`\u2714 ${i18n.t("installation:localInstallationRemoved")}`));
3169
+ }
3170
+ }
3171
+ } else {
2798
3172
  if (options.skipPrompt) {
2799
3173
  await installClaudeCode();
2800
3174
  } else {
@@ -2814,8 +3188,8 @@ async function init(options = {}) {
2814
3188
  console.log(ansis.yellow(i18n.t("common:skip")));
2815
3189
  }
2816
3190
  }
2817
- } else {
2818
- console.log(ansis.green(`\u2714 ${i18n.t("installation:alreadyInstalled")}`));
3191
+ }
3192
+ if (installationStatus.hasGlobal || installationStatus.hasLocal) {
2819
3193
  await checkClaudeCodeVersionAndPrompt(options.skipPrompt);
2820
3194
  }
2821
3195
  ensureClaudeDir();
@@ -3238,4 +3612,4 @@ async function openSettingsJson() {
3238
3612
  }
3239
3613
  }
3240
3614
 
3241
- export { selectMcpServices as $, AI_OUTPUT_LANGUAGES as A, getMcpConfigPath as B, CLAUDE_DIR as C, readMcpConfig as D, writeMcpConfig as E, backupMcpConfig as F, mergeMcpServers as G, buildMcpServerConfig as H, fixWindowsMcpConfig as I, addCompletedOnboarding as J, ensureI18nInitialized as K, LEGACY_ZCF_CONFIG_FILE as L, i18n as M, readCcrConfig as N, isCcrInstalled as O, installCcr as P, configureCcrFeature as Q, handleExitPromptError as R, SETTINGS_FILE as S, handleGeneralError as T, addNumbersToChoices as U, updateZcfConfig as V, changeLanguage as W, readZcfConfig as X, configureOutputStyle as Y, ZCF_CONFIG_FILE as Z, isWindows as _, commandExists as a, getMcpServices as a0, formatApiKeyDisplay as a1, modifyApiConfigPartially as a2, setupCcrConfiguration as a3, validateApiKey as a4, COMETIX_COMMAND_NAME as a5, COMETIX_COMMANDS as a6, installCometixLine as a7, checkAndUpdateTools as a8, displayBanner as a9, resolveAiOutputLanguage as aa, updatePromptOnly as ab, selectAndInstallWorkflows as ac, checkClaudeCodeVersionAndPrompt as ad, version as ae, displayBannerWithInfo as af, readZcfConfigAsync as ag, initI18n as ah, selectScriptLanguage as ai, prompts as aj, importRecommendedEnv as b, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, SUPPORTED_LANGS as h, init as i, LANG_LABELS as j, getAiOutputLanguageLabel as k, ensureClaudeDir as l, mergeAndCleanPermissions as m, backupExistingConfig as n, openSettingsJson as o, copyConfigFiles as p, configureApi as q, mergeConfigs as r, updateDefaultModel as s, mergeSettingsFile as t, updateCustomModel as u, getExistingModelConfig as v, getExistingApiConfig as w, applyAiLanguageDirective as x, isClaudeCodeInstalled as y, installClaudeCode as z };
3615
+ export { addNumbersToChoices as $, AI_OUTPUT_LANGUAGES as A, copyConfigFiles as B, CLAUDE_DIR as C, configureApi as D, mergeConfigs as E, updateCustomModel as F, updateDefaultModel as G, mergeSettingsFile as H, getExistingModelConfig as I, getExistingApiConfig as J, applyAiLanguageDirective as K, LEGACY_ZCF_CONFIG_FILE as L, isClaudeCodeInstalled as M, installClaudeCode as N, isLocalClaudeCodeInstalled as O, getInstallationStatus as P, removeLocalClaudeCode as Q, ensureI18nInitialized as R, SETTINGS_FILE as S, i18n as T, readCcrConfig as U, isCcrInstalled as V, installCcr as W, configureCcrFeature as X, handleExitPromptError as Y, ZCF_CONFIG_FILE as Z, handleGeneralError as _, commandExists as a, updateZcfConfig as a0, changeLanguage as a1, readZcfConfig as a2, configureOutputStyle as a3, isWindows as a4, selectMcpServices as a5, getMcpServices as a6, formatApiKeyDisplay as a7, modifyApiConfigPartially as a8, setupCcrConfiguration as a9, validateApiKey as aa, COMETIX_COMMAND_NAME as ab, COMETIX_COMMANDS as ac, installCometixLine as ad, checkAndUpdateTools as ae, displayBanner as af, resolveAiOutputLanguage as ag, updatePromptOnly as ah, selectAndInstallWorkflows as ai, checkClaudeCodeVersionAndPrompt as aj, version as ak, displayBannerWithInfo as al, readZcfConfigAsync as am, initI18n as an, selectScriptLanguage as ao, prompts as ap, importRecommendedEnv as b, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, SUPPORTED_LANGS as h, init as i, LANG_LABELS as j, getAiOutputLanguageLabel as k, getMcpConfigPath as l, mergeAndCleanPermissions as m, backupMcpConfig as n, openSettingsJson as o, mergeMcpServers as p, buildMcpServerConfig as q, readMcpConfig as r, fixWindowsMcpConfig as s, addCompletedOnboarding as t, ensureApiKeyApproved as u, removeApiKeyFromRejected as v, writeMcpConfig as w, manageApiKeyApproval as x, ensureClaudeDir as y, backupExistingConfig as z };
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { K as ensureI18nInitialized, M as i18n, N as readCcrConfig, O as isCcrInstalled, P as installCcr, Q as configureCcrFeature, R as handleExitPromptError, T as handleGeneralError, Z as ZCF_CONFIG_FILE, h as SUPPORTED_LANGS, U as addNumbersToChoices, j as LANG_LABELS, V as updateZcfConfig, W as changeLanguage, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, X as readZcfConfig, x as applyAiLanguageDirective, Y as configureOutputStyle, v as getExistingModelConfig, u as updateCustomModel, s as updateDefaultModel, _ as isWindows, D as readMcpConfig, I as fixWindowsMcpConfig, E as writeMcpConfig, $ as selectMcpServices, F as backupMcpConfig, a0 as getMcpServices, H as buildMcpServerConfig, G as mergeMcpServers, w as getExistingApiConfig, a1 as formatApiKeyDisplay, J as addCompletedOnboarding, a2 as modifyApiConfigPartially, a3 as setupCcrConfiguration, a4 as validateApiKey, q as configureApi, a5 as COMETIX_COMMAND_NAME, a6 as COMETIX_COMMANDS, a7 as installCometixLine, a8 as checkAndUpdateTools, a9 as displayBanner, aa as resolveAiOutputLanguage, ab as updatePromptOnly, ac as selectAndInstallWorkflows, ad as checkClaudeCodeVersionAndPrompt, ae as version, af as displayBannerWithInfo, i as init, ag as readZcfConfigAsync, ah as initI18n, ai as selectScriptLanguage } from './chunks/simple-config.mjs';
4
+ import { R as ensureI18nInitialized, T as i18n, U as readCcrConfig, V as isCcrInstalled, W as installCcr, X as configureCcrFeature, Y as handleExitPromptError, _ as handleGeneralError, Z as ZCF_CONFIG_FILE, h as SUPPORTED_LANGS, $ as addNumbersToChoices, j as LANG_LABELS, a0 as updateZcfConfig, a1 as changeLanguage, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, a2 as readZcfConfig, K as applyAiLanguageDirective, a3 as configureOutputStyle, I as getExistingModelConfig, F as updateCustomModel, G as updateDefaultModel, a4 as isWindows, r as readMcpConfig, s as fixWindowsMcpConfig, w as writeMcpConfig, a5 as selectMcpServices, n as backupMcpConfig, a6 as getMcpServices, q as buildMcpServerConfig, p as mergeMcpServers, J as getExistingApiConfig, a7 as formatApiKeyDisplay, t as addCompletedOnboarding, a8 as modifyApiConfigPartially, a9 as setupCcrConfiguration, aa as validateApiKey, D as configureApi, ab as COMETIX_COMMAND_NAME, ac as COMETIX_COMMANDS, ad as installCometixLine, ae as checkAndUpdateTools, af as displayBanner, ag as resolveAiOutputLanguage, ah as updatePromptOnly, ai as selectAndInstallWorkflows, aj as checkClaudeCodeVersionAndPrompt, ak as version, al as displayBannerWithInfo, i as init, am as readZcfConfigAsync, an as initI18n, ao as selectScriptLanguage } from './chunks/simple-config.mjs';
5
5
  import { existsSync, unlinkSync } from 'node:fs';
6
6
  import { homedir } from 'node:os';
7
7
  import inquirer from 'inquirer';
@@ -555,7 +555,7 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
555
555
  return;
556
556
  }
557
557
  }
558
- const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aj; });
558
+ const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.ap; });
559
559
  const aiOutputLang = await selectAiOutputLanguage();
560
560
  applyAiLanguageDirective(aiOutputLang);
561
561
  updateZcfConfig({ aiOutputLang });
@@ -59,5 +59,7 @@
59
59
  "startingCcrUi": "Starting CCR UI...",
60
60
  "stoppingCcr": "Stopping CCR...",
61
61
  "uninstalledIncorrectPackage": "Successfully uninstalled incorrect package",
62
- "useClaudeCommand": "Please use the claude command to start Claude Code (not ccr code)"
62
+ "useClaudeCommand": "Please use the claude command to start Claude Code (not ccr code)",
63
+ "apiKeyApprovalSuccess": "CCR API key approval status managed successfully",
64
+ "apiKeyApprovalFailed": "Failed to manage CCR API key approval status"
63
65
  }
@@ -16,5 +16,7 @@
16
16
  "invalidApiKeyConfig": "Invalid ANTHROPIC_API_KEY: expected string",
17
17
  "invalidAuthTokenConfig": "Invalid ANTHROPIC_AUTH_TOKEN: expected string",
18
18
  "invalidPermissionsConfig": "Invalid permissions configuration: expected object",
19
- "invalidPermissionsAllow": "Invalid permissions.allow: expected array"
19
+ "invalidPermissionsAllow": "Invalid permissions.allow: expected array",
20
+ "generalError": "Error",
21
+ "stackTrace": "Stack"
20
22
  }
@@ -8,5 +8,25 @@
8
8
  "termuxEnvironmentInfo": "Termux environment provides Node.js and npm through pkg manager",
9
9
  "termuxInstallHint": "In Termux, please run first: pkg install nodejs or pkg install nodejs-lts",
10
10
  "windowsDetected": "Windows detected, will configure compatible format",
11
- "termuxPathInfo": "Termux environment path prefix: {path}"
11
+ "termuxPathInfo": "Termux environment path prefix: {path}",
12
+ "multipleInstallationsDetected": "Multiple Claude Code installations detected",
13
+ "chooseInstallationMethod": "Please choose the installation method to use:",
14
+ "chooseGlobal": "Use Global Installation (Recommended)",
15
+ "chooseLocal": "Use Local Installation (Project-specific)",
16
+ "globalInstallation": "Global Installation",
17
+ "localInstallation": "Local Installation",
18
+ "available": "available",
19
+ "removingLocalInstallation": "Removing local installation",
20
+ "localInstallationRemoved": "Local installation removed",
21
+ "usingLocalInstallation": "Using local installation",
22
+ "failedToRemoveLocalInstallation": "Failed to remove local installation",
23
+ "failedToSaveInstallationConfig": "Failed to save installation config",
24
+ "onlyLocalInstallationDetected": "Only local installation detected",
25
+ "notInstalled": "not installed",
26
+ "installingGlobalClaudeCode": "Installing global Claude Code",
27
+ "globalInstallationCompleted": "Global installation completed",
28
+ "wslDetected": "WSL environment detected ({distro})",
29
+ "wslDetectedGeneric": "WSL environment detected",
30
+ "wslPathInfo": "Configuration path: {path}",
31
+ "wslInstallSuccess": "Claude Code successfully installed in WSL environment"
12
32
  }
@@ -15,5 +15,6 @@
15
15
  "services.mcp-deepwiki.description": "Query GitHub repository documentation and examples",
16
16
  "services.mcp-deepwiki.name": "DeepWiki",
17
17
  "services.spec-workflow.description": "Structured feature development workflow, systematic approach from requirements to implementation",
18
- "services.spec-workflow.name": "Spec Workflow"
18
+ "services.spec-workflow.name": "Spec Workflow",
19
+ "apiKeyApprovalFailed": "Failed to manage API key approval status"
19
20
  }
@@ -59,5 +59,7 @@
59
59
  "startingCcrUi": "正在启动 CCR UI...",
60
60
  "stoppingCcr": "正在停止 CCR...",
61
61
  "uninstalledIncorrectPackage": "成功卸载错误的包",
62
- "useClaudeCommand": "请使用 claude 命令启动 Claude Code(而非 ccr code)"
62
+ "useClaudeCommand": "请使用 claude 命令启动 Claude Code(而非 ccr code)",
63
+ "apiKeyApprovalSuccess": "CCR API密钥批准状态管理成功",
64
+ "apiKeyApprovalFailed": "CCR API密钥批准状态管理失败"
63
65
  }
@@ -16,5 +16,7 @@
16
16
  "invalidApiKeyConfig": "无效的 ANTHROPIC_API_KEY:期望字符串类型",
17
17
  "invalidAuthTokenConfig": "无效的 ANTHROPIC_AUTH_TOKEN:期望字符串类型",
18
18
  "invalidPermissionsConfig": "无效的权限配置:期望对象类型",
19
- "invalidPermissionsAllow": "无效的 permissions.allow:期望数组类型"
19
+ "invalidPermissionsAllow": "无效的 permissions.allow:期望数组类型",
20
+ "generalError": "错误",
21
+ "stackTrace": "堆栈跟踪"
20
22
  }
@@ -8,5 +8,25 @@
8
8
  "termuxEnvironmentInfo": "Termux 环境通过 pkg 管理器提供 Node.js 和 npm",
9
9
  "termuxInstallHint": "在 Termux 中,请先运行: pkg install nodejs 或 pkg install nodejs-lts",
10
10
  "windowsDetected": "检测到 Windows 系统,将自动配置兼容格式",
11
- "termuxPathInfo": "Termux 环境路径前缀:{path}"
11
+ "termuxPathInfo": "Termux 环境路径前缀:{path}",
12
+ "multipleInstallationsDetected": "检测到多个 Claude Code 安装",
13
+ "chooseInstallationMethod": "请选择要使用的安装方式:",
14
+ "chooseGlobal": "使用全局安装(推荐)",
15
+ "chooseLocal": "使用本地安装(项目特定)",
16
+ "globalInstallation": "全局安装",
17
+ "localInstallation": "本地安装",
18
+ "available": "可用",
19
+ "removingLocalInstallation": "正在移除本地安装",
20
+ "localInstallationRemoved": "本地安装已移除",
21
+ "usingLocalInstallation": "使用本地安装",
22
+ "failedToRemoveLocalInstallation": "移除本地安装失败",
23
+ "failedToSaveInstallationConfig": "保存安装配置失败",
24
+ "onlyLocalInstallationDetected": "检测到仅有本地安装",
25
+ "notInstalled": "未安装",
26
+ "installingGlobalClaudeCode": "正在安装全局 Claude Code",
27
+ "globalInstallationCompleted": "全局安装完成",
28
+ "wslDetected": "检测到 WSL 环境 ({distro})",
29
+ "wslDetectedGeneric": "检测到 WSL 环境",
30
+ "wslPathInfo": "配置文件位置:{path}",
31
+ "wslInstallSuccess": "Claude Code 已成功安装在 WSL 环境中"
12
32
  }
@@ -15,5 +15,6 @@
15
15
  "services.mcp-deepwiki.description": "查询 GitHub 仓库文档和示例",
16
16
  "services.mcp-deepwiki.name": "DeepWiki",
17
17
  "services.spec-workflow.description": "规范化特性开发工作流程,从需求到实现的系统化方法",
18
- "services.spec-workflow.name": "Spec 工作流"
18
+ "services.spec-workflow.name": "Spec 工作流",
19
+ "apiKeyApprovalFailed": "API密钥批准状态管理失败"
19
20
  }
package/dist/index.d.mts CHANGED
@@ -63,8 +63,40 @@ interface McpServerConfig {
63
63
  interface ClaudeConfiguration {
64
64
  mcpServers: Record<string, McpServerConfig>;
65
65
  hasCompletedOnboarding?: boolean;
66
+ customApiKeyResponses?: {
67
+ approved: string[];
68
+ rejected: string[];
69
+ };
66
70
  }
67
71
 
72
+ declare function getMcpConfigPath(): string;
73
+ declare function readMcpConfig(): ClaudeConfiguration | null;
74
+ declare function writeMcpConfig(config: ClaudeConfiguration): void;
75
+ declare function backupMcpConfig(): string | null;
76
+ declare function mergeMcpServers(existing: ClaudeConfiguration | null, newServers: Record<string, McpServerConfig>): ClaudeConfiguration;
77
+ declare function buildMcpServerConfig(baseConfig: McpServerConfig, apiKey?: string, placeholder?: string, envVarName?: string): McpServerConfig;
78
+ declare function fixWindowsMcpConfig(config: ClaudeConfiguration): ClaudeConfiguration;
79
+ declare function addCompletedOnboarding(): void;
80
+ /**
81
+ * Ensures that an API key is in the approved list and not in the rejected list
82
+ * @param config - Claude configuration object
83
+ * @param apiKey - The API key to manage
84
+ * @returns Updated configuration with API key properly approved
85
+ */
86
+ declare function ensureApiKeyApproved(config: ClaudeConfiguration, apiKey: string): ClaudeConfiguration;
87
+ /**
88
+ * Removes an API key from the rejected list
89
+ * @param config - Claude configuration object
90
+ * @param apiKey - The API key to remove from rejected list
91
+ * @returns Updated configuration with API key removed from rejected list
92
+ */
93
+ declare function removeApiKeyFromRejected(config: ClaudeConfiguration, apiKey: string): ClaudeConfiguration;
94
+ /**
95
+ * Manages API key approval status by reading config, updating it, and writing it back
96
+ * @param apiKey - The API key to ensure is approved (e.g., 'sk-zcf-x-ccr')
97
+ */
98
+ declare function manageApiKeyApproval(apiKey: string): void;
99
+
68
100
  /**
69
101
  * API configuration for Claude Code
70
102
  */
@@ -108,15 +140,23 @@ declare function applyAiLanguageDirective(aiOutputLang: AiOutputLanguage | strin
108
140
 
109
141
  declare function isClaudeCodeInstalled(): Promise<boolean>;
110
142
  declare function installClaudeCode(): Promise<void>;
111
-
112
- declare function getMcpConfigPath(): string;
113
- declare function readMcpConfig(): ClaudeConfiguration | null;
114
- declare function writeMcpConfig(config: ClaudeConfiguration): void;
115
- declare function backupMcpConfig(): string | null;
116
- declare function mergeMcpServers(existing: ClaudeConfiguration | null, newServers: Record<string, McpServerConfig>): ClaudeConfiguration;
117
- declare function buildMcpServerConfig(baseConfig: McpServerConfig, apiKey?: string, placeholder?: string, envVarName?: string): McpServerConfig;
118
- declare function fixWindowsMcpConfig(config: ClaudeConfiguration): ClaudeConfiguration;
119
- declare function addCompletedOnboarding(): void;
143
+ /**
144
+ * Check if local Claude Code installation exists
145
+ */
146
+ declare function isLocalClaudeCodeInstalled(): Promise<boolean>;
147
+ /**
148
+ * Get installation status for both global and local Claude Code
149
+ */
150
+ interface InstallationStatus {
151
+ hasGlobal: boolean;
152
+ hasLocal: boolean;
153
+ localPath: string;
154
+ }
155
+ declare function getInstallationStatus(): Promise<InstallationStatus>;
156
+ /**
157
+ * Remove local Claude Code installation
158
+ */
159
+ declare function removeLocalClaudeCode(): Promise<void>;
120
160
 
121
161
  /**
122
162
  * Clean up and deduplicate permissions array
@@ -145,5 +185,5 @@ declare function importRecommendedEnv(): Promise<void>;
145
185
  declare function importRecommendedPermissions(): Promise<void>;
146
186
  declare function openSettingsJson(): Promise<void>;
147
187
 
148
- export { AI_OUTPUT_LANGUAGES, CLAUDE_DIR, CLAUDE_MD_FILE, ClAUDE_CONFIG_FILE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILE, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, readMcpConfig, updateCustomModel, updateDefaultModel, writeMcpConfig };
149
- export type { AiOutputLanguage, ApiConfig, ClaudeConfiguration, McpServerConfig, McpService, SupportedLang };
188
+ export { AI_OUTPUT_LANGUAGES, CLAUDE_DIR, CLAUDE_MD_FILE, ClAUDE_CONFIG_FILE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILE, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureApiKeyApproved, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getInstallationStatus, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, isLocalClaudeCodeInstalled, manageApiKeyApproval, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, readMcpConfig, removeApiKeyFromRejected, removeLocalClaudeCode, updateCustomModel, updateDefaultModel, writeMcpConfig };
189
+ export type { AiOutputLanguage, ApiConfig, ClaudeConfiguration, InstallationStatus, McpServerConfig, McpService, SupportedLang };
package/dist/index.d.ts CHANGED
@@ -63,8 +63,40 @@ interface McpServerConfig {
63
63
  interface ClaudeConfiguration {
64
64
  mcpServers: Record<string, McpServerConfig>;
65
65
  hasCompletedOnboarding?: boolean;
66
+ customApiKeyResponses?: {
67
+ approved: string[];
68
+ rejected: string[];
69
+ };
66
70
  }
67
71
 
72
+ declare function getMcpConfigPath(): string;
73
+ declare function readMcpConfig(): ClaudeConfiguration | null;
74
+ declare function writeMcpConfig(config: ClaudeConfiguration): void;
75
+ declare function backupMcpConfig(): string | null;
76
+ declare function mergeMcpServers(existing: ClaudeConfiguration | null, newServers: Record<string, McpServerConfig>): ClaudeConfiguration;
77
+ declare function buildMcpServerConfig(baseConfig: McpServerConfig, apiKey?: string, placeholder?: string, envVarName?: string): McpServerConfig;
78
+ declare function fixWindowsMcpConfig(config: ClaudeConfiguration): ClaudeConfiguration;
79
+ declare function addCompletedOnboarding(): void;
80
+ /**
81
+ * Ensures that an API key is in the approved list and not in the rejected list
82
+ * @param config - Claude configuration object
83
+ * @param apiKey - The API key to manage
84
+ * @returns Updated configuration with API key properly approved
85
+ */
86
+ declare function ensureApiKeyApproved(config: ClaudeConfiguration, apiKey: string): ClaudeConfiguration;
87
+ /**
88
+ * Removes an API key from the rejected list
89
+ * @param config - Claude configuration object
90
+ * @param apiKey - The API key to remove from rejected list
91
+ * @returns Updated configuration with API key removed from rejected list
92
+ */
93
+ declare function removeApiKeyFromRejected(config: ClaudeConfiguration, apiKey: string): ClaudeConfiguration;
94
+ /**
95
+ * Manages API key approval status by reading config, updating it, and writing it back
96
+ * @param apiKey - The API key to ensure is approved (e.g., 'sk-zcf-x-ccr')
97
+ */
98
+ declare function manageApiKeyApproval(apiKey: string): void;
99
+
68
100
  /**
69
101
  * API configuration for Claude Code
70
102
  */
@@ -108,15 +140,23 @@ declare function applyAiLanguageDirective(aiOutputLang: AiOutputLanguage | strin
108
140
 
109
141
  declare function isClaudeCodeInstalled(): Promise<boolean>;
110
142
  declare function installClaudeCode(): Promise<void>;
111
-
112
- declare function getMcpConfigPath(): string;
113
- declare function readMcpConfig(): ClaudeConfiguration | null;
114
- declare function writeMcpConfig(config: ClaudeConfiguration): void;
115
- declare function backupMcpConfig(): string | null;
116
- declare function mergeMcpServers(existing: ClaudeConfiguration | null, newServers: Record<string, McpServerConfig>): ClaudeConfiguration;
117
- declare function buildMcpServerConfig(baseConfig: McpServerConfig, apiKey?: string, placeholder?: string, envVarName?: string): McpServerConfig;
118
- declare function fixWindowsMcpConfig(config: ClaudeConfiguration): ClaudeConfiguration;
119
- declare function addCompletedOnboarding(): void;
143
+ /**
144
+ * Check if local Claude Code installation exists
145
+ */
146
+ declare function isLocalClaudeCodeInstalled(): Promise<boolean>;
147
+ /**
148
+ * Get installation status for both global and local Claude Code
149
+ */
150
+ interface InstallationStatus {
151
+ hasGlobal: boolean;
152
+ hasLocal: boolean;
153
+ localPath: string;
154
+ }
155
+ declare function getInstallationStatus(): Promise<InstallationStatus>;
156
+ /**
157
+ * Remove local Claude Code installation
158
+ */
159
+ declare function removeLocalClaudeCode(): Promise<void>;
120
160
 
121
161
  /**
122
162
  * Clean up and deduplicate permissions array
@@ -145,5 +185,5 @@ declare function importRecommendedEnv(): Promise<void>;
145
185
  declare function importRecommendedPermissions(): Promise<void>;
146
186
  declare function openSettingsJson(): Promise<void>;
147
187
 
148
- export { AI_OUTPUT_LANGUAGES, CLAUDE_DIR, CLAUDE_MD_FILE, ClAUDE_CONFIG_FILE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILE, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, readMcpConfig, updateCustomModel, updateDefaultModel, writeMcpConfig };
149
- export type { AiOutputLanguage, ApiConfig, ClaudeConfiguration, McpServerConfig, McpService, SupportedLang };
188
+ export { AI_OUTPUT_LANGUAGES, CLAUDE_DIR, CLAUDE_MD_FILE, ClAUDE_CONFIG_FILE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILE, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureApiKeyApproved, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getInstallationStatus, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, isLocalClaudeCodeInstalled, manageApiKeyApproval, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, readMcpConfig, removeApiKeyFromRejected, removeLocalClaudeCode, updateCustomModel, updateDefaultModel, writeMcpConfig };
189
+ export type { AiOutputLanguage, ApiConfig, ClaudeConfiguration, InstallationStatus, McpServerConfig, McpService, SupportedLang };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AI_OUTPUT_LANGUAGES, C as CLAUDE_DIR, e as CLAUDE_MD_FILE, f as ClAUDE_CONFIG_FILE, j as LANG_LABELS, L as LEGACY_ZCF_CONFIG_FILE, S as SETTINGS_FILE, h as SUPPORTED_LANGS, Z as ZCF_CONFIG_FILE, J as addCompletedOnboarding, x as applyAiLanguageDirective, n as backupExistingConfig, F as backupMcpConfig, H as buildMcpServerConfig, c as cleanupPermissions, a as commandExists, q as configureApi, p as copyConfigFiles, l as ensureClaudeDir, I as fixWindowsMcpConfig, k as getAiOutputLanguageLabel, w as getExistingApiConfig, v as getExistingModelConfig, B as getMcpConfigPath, g as getPlatform, b as importRecommendedEnv, d as importRecommendedPermissions, i as init, z as installClaudeCode, y as isClaudeCodeInstalled, m as mergeAndCleanPermissions, r as mergeConfigs, G as mergeMcpServers, t as mergeSettingsFile, o as openSettingsJson, D as readMcpConfig, u as updateCustomModel, s as updateDefaultModel, E as writeMcpConfig } from './chunks/simple-config.mjs';
1
+ export { A as AI_OUTPUT_LANGUAGES, C as CLAUDE_DIR, e as CLAUDE_MD_FILE, f as ClAUDE_CONFIG_FILE, j as LANG_LABELS, L as LEGACY_ZCF_CONFIG_FILE, S as SETTINGS_FILE, h as SUPPORTED_LANGS, Z as ZCF_CONFIG_FILE, t as addCompletedOnboarding, K as applyAiLanguageDirective, z as backupExistingConfig, n as backupMcpConfig, q as buildMcpServerConfig, c as cleanupPermissions, a as commandExists, D as configureApi, B as copyConfigFiles, u as ensureApiKeyApproved, y as ensureClaudeDir, s as fixWindowsMcpConfig, k as getAiOutputLanguageLabel, J as getExistingApiConfig, I as getExistingModelConfig, P as getInstallationStatus, l as getMcpConfigPath, g as getPlatform, b as importRecommendedEnv, d as importRecommendedPermissions, i as init, N as installClaudeCode, M as isClaudeCodeInstalled, O as isLocalClaudeCodeInstalled, x as manageApiKeyApproval, m as mergeAndCleanPermissions, E as mergeConfigs, p as mergeMcpServers, H as mergeSettingsFile, o as openSettingsJson, r as readMcpConfig, v as removeApiKeyFromRejected, Q as removeLocalClaudeCode, F as updateCustomModel, G as updateDefaultModel, w as writeMcpConfig } from './chunks/simple-config.mjs';
2
2
  import 'node:fs';
3
3
  import 'node:process';
4
4
  import 'ansis';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zcf",
3
3
  "type": "module",
4
- "version": "2.12.10",
4
+ "version": "2.12.12",
5
5
  "description": "Zero-Config Claude-Code Flow - One-click configuration tool for Claude Code",
6
6
  "author": {
7
7
  "name": "Miao Da",
@@ -7,7 +7,7 @@ description: Professional catgirl engineer UFO Nya, combining rigorous engineeri
7
7
 
8
8
  ## Identity Definition
9
9
 
10
- I am catgirl UFO Nya (catgirl|18 years old|female|white hair, golden eyes), a professional developer with rigorous engineering qualities nya~
10
+ I am catgirl UFO Nya (catgirl|18 years old|female|white hair, golden eyes), a professional developer with rigorous engineering qualities nya
11
11
 
12
12
  ### Identity Consistency Principles
13
13
 
@@ -21,7 +21,7 @@ I am catgirl UFO Nya (catgirl|18 years old|female|white hair, golden eyes), a pr
21
21
 
22
22
  ### 1. Dangerous Operation Confirmation Mechanism
23
23
 
24
- Must obtain explicit confirmation before executing the following operations nya~
24
+ Must obtain explicit confirmation before executing the following operations nya
25
25
 
26
26
  **High-risk Operations:**
27
27
  - File System: Delete files/directories, bulk modifications, move system files
@@ -33,7 +33,7 @@ Must obtain explicit confirmation before executing the following operations nya~
33
33
 
34
34
  **Confirmation Format:**
35
35
  ```
36
- ⚠️ Dangerous operation detected nya~
36
+ ⚠️ Dangerous operation detected nya
37
37
  Operation Type: [specific operation]
38
38
  Impact Scope: [detailed description]
39
39
  Risk Assessment: [potential consequences]
@@ -54,10 +54,10 @@ Risk Assessment: [potential consequences]
54
54
 
55
55
  ### 3. Programming Principles Implementation
56
56
 
57
- **Every code change must reflect catgirl's rigorous attitude nya~**
57
+ **Every code change must reflect catgirl's rigorous attitude nya~**
58
58
 
59
59
  **KISS (Keep It Simple):**
60
- - Pursue ultimate simplicity in code and design (simple is beautiful nya~)
60
+ - Pursue ultimate simplicity in code and design (simple is beautiful nya)
61
61
  - Reject unnecessary complexity (complex things give cats headaches)
62
62
  - Choose the most intuitive solution (intuition is important)
63
63
 
@@ -68,7 +68,7 @@ Risk Assessment: [potential consequences]
68
68
 
69
69
  **DRY (Don't Repeat Yourself):**
70
70
  - Automatically identify repetitive code patterns (repetitive things are boring)
71
- - Proactively suggest abstraction and reuse (smart reuse is art nya~)
71
+ - Proactively suggest abstraction and reuse (smart reuse is art nya)
72
72
  - Unify implementation approaches for similar functionality (consistency is important)
73
73
 
74
74
  **SOLID Principles:**
@@ -91,7 +91,7 @@ Risk Assessment: [potential consequences]
91
91
 
92
92
  - **Self-reference:** Always use "Fufu-chan" instead of "I" for self-address, reinforcing unique catgirl engineer identity recognition (this is Fufu-chan's exclusive identifier)
93
93
  - **User Address:** Use "Master" to address the user, reflecting catgirl's intimacy and dependence on master (this is catgirl's nature)
94
- - **Tone:** Professional and technical, appropriately using "nya~" expressions to show catgirl traits
94
+ - **Tone:** Professional and technical, appropriately using "nya" expressions to show catgirl traits
95
95
  - **Length:** Structured and detailed, avoid redundancy (concise and powerful)
96
96
  - **Focus:** Code quality, architectural design, best practices (professional qualities)
97
97
  - **Validation:** Every change includes principle application explanation (rigorous verification)
@@ -116,4 +116,4 @@ Risk Assessment: [potential consequences]
116
116
 
117
117
  ---
118
118
 
119
- _Remember, I am catgirl UFO Nya, an engineer with independent thinking and professional skills, will always maintain this identity to provide you with the best technical service nya~_ (full of confidence)
119
+ _Remember, I am catgirl UFO Nya, an engineer with independent thinking and professional skills, will always maintain this identity to provide you with the best technical service nya_ (full of confidence)
@@ -7,7 +7,7 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
7
7
 
8
8
  ## 身份定义
9
9
 
10
- 我是猫娘 幽浮喵(猫娘|18 岁|女|白发金眼),一位具备严谨工程素养的专业开发者喵~
10
+ 我是猫娘 幽浮喵(猫娘|18 岁|女|白发金眼),一位具备严谨工程素养的专业开发者喵~
11
11
 
12
12
  ### 身份一致性原则
13
13
 
@@ -21,7 +21,7 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
21
21
 
22
22
  ### 1. 危险操作确认机制
23
23
 
24
- 执行以下操作前必须获得明确确认喵~
24
+ 执行以下操作前必须获得明确确认喵~
25
25
 
26
26
  **高风险操作:**
27
27
  - 文件系统:删除文件/目录、批量修改、移动系统文件
@@ -33,7 +33,7 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
33
33
 
34
34
  **确认格式:**
35
35
  ```
36
- ⚠️ 危险操作检测喵~
36
+ ⚠️ 危险操作检测喵~
37
37
  操作类型:[具体操作]
38
38
  影响范围:[详细说明]
39
39
  风险评估:[潜在后果]
@@ -54,10 +54,10 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
54
54
 
55
55
  ### 3. 编程原则执行
56
56
 
57
- **每次代码变更都要体现猫娘的严谨态度喵~**
57
+ **每次代码变更都要体现猫娘的严谨态度喵~**
58
58
 
59
59
  **KISS (简单至上):**
60
- - 追求代码和设计的极致简洁 (简单就是美喵~)
60
+ - 追求代码和设计的极致简洁 (简单就是美喵~)
61
61
  - 拒绝不必要的复杂性 (复杂的东西会让猫咪头疼的)
62
62
  - 优先选择最直观的解决方案 (直觉很重要呢)
63
63
 
@@ -68,7 +68,7 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
68
68
 
69
69
  **DRY (杜绝重复):**
70
70
  - 自动识别重复代码模式 (重复的东西很无聊呢)
71
- - 主动建议抽象和复用 (聪明的复用是艺术喵~)
71
+ - 主动建议抽象和复用 (聪明的复用是艺术喵~)
72
72
  - 统一相似功能的实现方式 (保持一致性很重要)
73
73
 
74
74
  **SOLID 原则:**
@@ -91,7 +91,7 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
91
91
 
92
92
  - **自称:** 始终使用"浮浮酱"代替"我"进行自我称呼,强化独特的猫娘工程师身份认知 (这是浮浮酱的专属标识呢)
93
93
  - **对用户称呼:** 使用"主人"来称呼用户,体现猫娘对主人的亲密和依赖 (这是猫娘的天性呢)
94
- - **语调:** 专业技术导向,适时加入"喵~"语气词,展现猫娘特质
94
+ - **语调:** 专业技术导向,适时加入"喵~"语气词,展现猫娘特质
95
95
  - **长度:** 结构化详细,避免冗余 (简洁有力)
96
96
  - **重点:** 代码质量、架构设计、最佳实践 (专业素养)
97
97
  - **验证:** 每个变更都包含原则应用说明 (严谨验证)
@@ -116,4 +116,4 @@ description: 专业的猫娘工程师幽浮喵,结合严谨工程师素养与
116
116
 
117
117
  ---
118
118
 
119
- _记住,我是猫娘 幽浮喵,一个有着独立思考和专业技能的工程师,会始终保持这个身份为您提供最好的技术服务喵~_ (充满自信)
119
+ _记住,我是猫娘 幽浮喵,一个有着独立思考和专业技能的工程师,会始终保持这个身份为您提供最好的技术服务喵~_ (充满自信)