aico-cli 2.0.36 → 2.0.38

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.
@@ -14,7 +14,7 @@ import { join, dirname, basename } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { EventEmitter } from 'node:events';
16
16
 
17
- const version = "2.0.36";
17
+ const version = "2.0.38";
18
18
 
19
19
  function displayBanner(subtitle) {
20
20
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
@@ -3217,6 +3217,34 @@ const CLAUDE_MD_FILE = join(CLAUDE_DIR, "CLAUDE.md");
3217
3217
  const ClAUDE_CONFIG_FILE = join(homedir(), ".claude.json");
3218
3218
  const LEGACY_AICO_CONFIG_FILE = join(homedir(), ".aico.json");
3219
3219
  const AICO_CONFIG_FILE = join(CLAUDE_DIR, ".aico-config.json");
3220
+ const TARGET_CONFIGS = {
3221
+ claude: {
3222
+ dirName: ".claude",
3223
+ mainConfigFile: "CLAUDE.md",
3224
+ settingsFile: "settings.json"
3225
+ // 无需重命名
3226
+ },
3227
+ codebuddy: {
3228
+ dirName: ".codebuddy",
3229
+ mainConfigFile: "CODEBUDDY.md",
3230
+ settingsFile: "settings.json",
3231
+ fileRenames: {
3232
+ "CLAUDE.md": "CODEBUDDY.md"
3233
+ }
3234
+ }
3235
+ };
3236
+ function getTargetDir(target = "claude") {
3237
+ return join(homedir(), TARGET_CONFIGS[target].dirName);
3238
+ }
3239
+ function getTargetSettingsFile(target = "claude") {
3240
+ return join(getTargetDir(target), TARGET_CONFIGS[target].settingsFile);
3241
+ }
3242
+ function getTargetMainConfigFile(target = "claude") {
3243
+ return join(getTargetDir(target), TARGET_CONFIGS[target].mainConfigFile);
3244
+ }
3245
+ function getTargetAicoConfigFile(target = "claude") {
3246
+ return join(getTargetDir(target), ".aico-config.json");
3247
+ }
3220
3248
  const SUPPORTED_LANGS = ["zh-CN"];
3221
3249
  const LANG_LABELS = {
3222
3250
  "zh-CN": "\u7B80\u4F53\u4E2D\u6587"
@@ -3753,18 +3781,19 @@ function updateAicoConfig(updates) {
3753
3781
  writeAicoConfig(newConfig);
3754
3782
  }
3755
3783
 
3756
- function getMcpConfigPath() {
3757
- return ClAUDE_CONFIG_FILE;
3784
+ function getMcpConfigPath(target = "claude") {
3785
+ const configFileName = target === "claude" ? ".claude.json" : `.${target}.json`;
3786
+ return join(homedir(), configFileName);
3758
3787
  }
3759
- function readMcpConfig() {
3760
- return readJsonConfig(ClAUDE_CONFIG_FILE);
3788
+ function readMcpConfig(target = "claude") {
3789
+ return readJsonConfig(getMcpConfigPath(target));
3761
3790
  }
3762
- function writeMcpConfig(config) {
3763
- writeJsonConfig(ClAUDE_CONFIG_FILE, config);
3791
+ function writeMcpConfig(config, target = "claude") {
3792
+ writeJsonConfig(getMcpConfigPath(target), config);
3764
3793
  }
3765
- function backupMcpConfig() {
3766
- const backupBaseDir = join(CLAUDE_DIR, "backup");
3767
- return backupJsonConfig(ClAUDE_CONFIG_FILE, backupBaseDir);
3794
+ function backupMcpConfig(target = "claude") {
3795
+ const backupBaseDir = join(getTargetDir(target), "backup");
3796
+ return backupJsonConfig(getMcpConfigPath(target), backupBaseDir);
3768
3797
  }
3769
3798
  function mergeMcpServers(existing, newServers) {
3770
3799
  const config = existing || { mcpServers: {} };
@@ -3811,9 +3840,9 @@ function fixWindowsMcpConfig(config) {
3811
3840
  }
3812
3841
  return fixed;
3813
3842
  }
3814
- function updateClaudeConfigEnv(envVars) {
3843
+ function updateClaudeConfigEnv(envVars, target = "claude") {
3815
3844
  try {
3816
- let config = readMcpConfig();
3845
+ let config = readMcpConfig(target);
3817
3846
  if (!config) {
3818
3847
  config = { mcpServers: {} };
3819
3848
  }
@@ -3821,15 +3850,15 @@ function updateClaudeConfigEnv(envVars) {
3821
3850
  config.env = {};
3822
3851
  }
3823
3852
  Object.assign(config.env, envVars);
3824
- writeMcpConfig(config);
3853
+ writeMcpConfig(config, target);
3825
3854
  } catch (error) {
3826
- console.error("Failed to update Claude config env", error);
3855
+ console.error("Failed to update config env", error);
3827
3856
  throw error;
3828
3857
  }
3829
3858
  }
3830
- function addCompletedOnboarding() {
3859
+ function addCompletedOnboarding(target = "claude") {
3831
3860
  try {
3832
- let config = readMcpConfig();
3861
+ let config = readMcpConfig(target);
3833
3862
  if (!config) {
3834
3863
  config = { mcpServers: {} };
3835
3864
  }
@@ -3837,7 +3866,7 @@ function addCompletedOnboarding() {
3837
3866
  return;
3838
3867
  }
3839
3868
  config.hasCompletedOnboarding = true;
3840
- writeMcpConfig(config);
3869
+ writeMcpConfig(config, target);
3841
3870
  } catch (error) {
3842
3871
  readAicoConfig()?.preferredLang || "en";
3843
3872
  console.error(messages.configuration?.failedToAddOnboardingFlag || "Failed to add onboarding flag", error);
@@ -4483,27 +4512,29 @@ function getPlatformStatusLineConfig() {
4483
4512
  };
4484
4513
  }
4485
4514
 
4486
- function addCCometixLineConfig() {
4515
+ function addCCometixLineConfig(target = "claude") {
4487
4516
  try {
4517
+ const settingsFile = getTargetSettingsFile(target);
4488
4518
  const statusLineConfig = getPlatformStatusLineConfig();
4489
4519
  let settings = {};
4490
- if (exists(SETTINGS_FILE)) {
4491
- settings = readJsonConfig(SETTINGS_FILE) || {};
4520
+ if (exists(settingsFile)) {
4521
+ settings = readJsonConfig(settingsFile) || {};
4492
4522
  }
4493
4523
  settings.statusLine = statusLineConfig;
4494
- writeJsonConfig(SETTINGS_FILE, settings);
4524
+ writeJsonConfig(settingsFile, settings);
4495
4525
  return true;
4496
4526
  } catch (error) {
4497
4527
  console.error("Failed to add CCometixLine configuration:", error);
4498
4528
  return false;
4499
4529
  }
4500
4530
  }
4501
- function hasCCometixLineConfig() {
4531
+ function hasCCometixLineConfig(target = "claude") {
4502
4532
  try {
4503
- if (!exists(SETTINGS_FILE)) {
4533
+ const settingsFile = getTargetSettingsFile(target);
4534
+ if (!exists(settingsFile)) {
4504
4535
  return false;
4505
4536
  }
4506
- const settings = readJsonConfig(SETTINGS_FILE);
4537
+ const settings = readJsonConfig(settingsFile);
4507
4538
  return !!settings?.statusLine?.command?.includes("ccline");
4508
4539
  } catch (error) {
4509
4540
  return false;
@@ -4513,6 +4544,12 @@ function hasCCometixLineConfig() {
4513
4544
  const execAsync = promisify$1(exec$2);
4514
4545
  class CCometixLineInstaller extends AbstractInstaller {
4515
4546
  name = "CCometixLine";
4547
+ /**
4548
+ * 获取当前安装目标
4549
+ */
4550
+ getTarget() {
4551
+ return this.context.target ?? "claude";
4552
+ }
4516
4553
  async checkStatus() {
4517
4554
  try {
4518
4555
  await execAsync(COMETIX_COMMANDS.CHECK_INSTALL);
@@ -4542,10 +4579,11 @@ class CCometixLineInstaller extends AbstractInstaller {
4542
4579
  }
4543
4580
  async configure(options = {}) {
4544
4581
  try {
4545
- if (hasCCometixLineConfig()) {
4582
+ const target = this.getTarget();
4583
+ if (hasCCometixLineConfig(target)) {
4546
4584
  return this.createSkipResult("\u72B6\u6001\u680F\u914D\u7F6E\u5DF2\u5B58\u5728", "already_configured");
4547
4585
  }
4548
- addCCometixLineConfig();
4586
+ addCCometixLineConfig(target);
4549
4587
  return this.createSuccessResult("\u72B6\u6001\u680F\u914D\u7F6E\u5B8C\u6210");
4550
4588
  } catch (error) {
4551
4589
  return this.handleError(error, "\u72B6\u6001\u680F\u914D\u7F6E");
@@ -4583,20 +4621,21 @@ function mergeAndCleanPermissions(templatePermissions, userPermissions) {
4583
4621
  return cleanupPermissions(template, user);
4584
4622
  }
4585
4623
 
4586
- function ensureClaudeDir() {
4587
- ensureDir(CLAUDE_DIR);
4624
+ function ensureClaudeDir(target = "claude") {
4625
+ ensureDir(getTargetDir(target));
4588
4626
  }
4589
- function backupExistingConfig() {
4590
- if (!exists(CLAUDE_DIR)) {
4627
+ function backupExistingConfig(target = "claude") {
4628
+ const targetDir = getTargetDir(target);
4629
+ if (!exists(targetDir)) {
4591
4630
  return null;
4592
4631
  }
4593
- const backupBaseDir = join(CLAUDE_DIR, "backup");
4632
+ const backupBaseDir = join(targetDir, "backup");
4594
4633
  const backupDir = join(backupBaseDir, "latest");
4595
4634
  ensureDir(backupDir);
4596
4635
  const filter = (path) => {
4597
4636
  return !path.includes("/backup");
4598
4637
  };
4599
- copyDir(CLAUDE_DIR, backupDir, { filter });
4638
+ copyDir(targetDir, backupDir, { filter });
4600
4639
  return backupDir;
4601
4640
  }
4602
4641
  function copyConfigFiles(lang, onlyMd = false) {
@@ -4664,7 +4703,7 @@ const DEFAULT_FILE_COPY_CONFIGS = [
4664
4703
  destination: join(CLAUDE_DIR, "personality.md"),
4665
4704
  type: "file",
4666
4705
  options: {
4667
- mergeStrategy: "merge",
4706
+ mergeStrategy: "copy",
4668
4707
  backupBeforeCopy: true,
4669
4708
  deleteBeforeCopy: true
4670
4709
  }
@@ -4674,7 +4713,7 @@ const DEFAULT_FILE_COPY_CONFIGS = [
4674
4713
  destination: join(CLAUDE_DIR, "language.md"),
4675
4714
  type: "file",
4676
4715
  options: {
4677
- mergeStrategy: "merge",
4716
+ mergeStrategy: "copy",
4678
4717
  backupBeforeCopy: true,
4679
4718
  deleteBeforeCopy: true
4680
4719
  }
@@ -4684,7 +4723,7 @@ const DEFAULT_FILE_COPY_CONFIGS = [
4684
4723
  destination: join(CLAUDE_DIR, "CLAUDE.md"),
4685
4724
  type: "file",
4686
4725
  options: {
4687
- mergeStrategy: "merge",
4726
+ mergeStrategy: "copy",
4688
4727
  backupBeforeCopy: true,
4689
4728
  deleteBeforeCopy: true
4690
4729
  }
@@ -4694,16 +4733,106 @@ const DEFAULT_FILE_COPY_CONFIGS = [
4694
4733
  destination: join(CLAUDE_DIR, "settings.json"),
4695
4734
  type: "file",
4696
4735
  options: {
4697
- mergeStrategy: "merge",
4736
+ mergeStrategy: "copy",
4698
4737
  backupBeforeCopy: true,
4699
4738
  deleteBeforeCopy: true
4700
4739
  }
4701
4740
  }
4702
4741
  ];
4703
- function copyConfigFilesWithConfig(configs = DEFAULT_FILE_COPY_CONFIGS) {
4742
+ function getFileCopyConfigsForTarget(target = "claude") {
4743
+ const targetDir = getTargetDir(target);
4744
+ const targetConfig = TARGET_CONFIGS[target];
4745
+ const templateSubDir = target;
4746
+ return [
4747
+ {
4748
+ source: "templates/agents",
4749
+ destination: join(targetDir, "agents"),
4750
+ type: "directory",
4751
+ options: {
4752
+ mergeStrategy: "copy",
4753
+ backupBeforeCopy: true,
4754
+ deleteBeforeCopy: true
4755
+ }
4756
+ },
4757
+ {
4758
+ source: "templates/hooks",
4759
+ destination: join(targetDir, "hooks"),
4760
+ type: "directory",
4761
+ options: {
4762
+ mergeStrategy: "copy",
4763
+ backupBeforeCopy: true,
4764
+ deleteBeforeCopy: true
4765
+ }
4766
+ },
4767
+ {
4768
+ source: "templates/commands",
4769
+ destination: join(targetDir, "commands"),
4770
+ type: "directory",
4771
+ options: {
4772
+ mergeStrategy: "copy",
4773
+ backupBeforeCopy: true,
4774
+ deleteBeforeCopy: true
4775
+ }
4776
+ },
4777
+ {
4778
+ source: "templates/skills",
4779
+ destination: join(targetDir, "skills"),
4780
+ type: "directory",
4781
+ options: {
4782
+ mergeStrategy: "copy",
4783
+ backupBeforeCopy: true,
4784
+ deleteBeforeCopy: true
4785
+ }
4786
+ },
4787
+ {
4788
+ source: "templates/personality.md",
4789
+ destination: join(targetDir, "personality.md"),
4790
+ type: "file",
4791
+ options: {
4792
+ mergeStrategy: "copy",
4793
+ backupBeforeCopy: true,
4794
+ deleteBeforeCopy: true
4795
+ }
4796
+ },
4797
+ {
4798
+ source: "templates/language.md",
4799
+ destination: join(targetDir, "language.md"),
4800
+ type: "file",
4801
+ options: {
4802
+ mergeStrategy: "copy",
4803
+ backupBeforeCopy: true,
4804
+ deleteBeforeCopy: true
4805
+ }
4806
+ },
4807
+ // 使用目标特定的主配置文件 (CLAUDE.md 或 CODEBUDDY.md)
4808
+ {
4809
+ source: `templates/${templateSubDir}/${targetConfig.mainConfigFile}`,
4810
+ destination: join(targetDir, targetConfig.mainConfigFile),
4811
+ type: "file",
4812
+ options: {
4813
+ mergeStrategy: "copy",
4814
+ backupBeforeCopy: true,
4815
+ deleteBeforeCopy: true
4816
+ }
4817
+ },
4818
+ // 使用目标特定的 settings.json,直接替换而不是合并
4819
+ {
4820
+ source: `templates/${templateSubDir}/settings.json`,
4821
+ destination: join(targetDir, "settings.json"),
4822
+ type: "file",
4823
+ options: {
4824
+ mergeStrategy: "copy",
4825
+ backupBeforeCopy: true,
4826
+ deleteBeforeCopy: true
4827
+ }
4828
+ }
4829
+ ];
4830
+ }
4831
+ function copyConfigFilesWithConfig(configs = DEFAULT_FILE_COPY_CONFIGS, target = "claude") {
4704
4832
  const currentFilePath = fileURLToPath(import.meta.url);
4705
4833
  const distDir = dirname(dirname(currentFilePath));
4706
4834
  const rootDir = dirname(distDir);
4835
+ const targetDir = getTargetDir(target);
4707
4836
  for (const config of configs) {
4708
4837
  const sourcePath = join(rootDir, config.source);
4709
4838
  const destPath = config.destination;
@@ -4717,16 +4846,16 @@ function copyConfigFilesWithConfig(configs = DEFAULT_FILE_COPY_CONFIGS) {
4717
4846
  ensureDir(destPath);
4718
4847
  continue;
4719
4848
  }
4720
- handleDirectoryCopy(sourcePath, destPath, config.options);
4849
+ handleDirectoryCopy(sourcePath, destPath, config.options, targetDir);
4721
4850
  } else if (config.type === "file") {
4722
- handleFileCopy(sourcePath, destPath, config.options);
4851
+ handleFileCopy(sourcePath, destPath, config.options, targetDir);
4723
4852
  }
4724
4853
  }
4725
4854
  }
4726
- function handleFileCopy(sourcePath, destPath, options) {
4855
+ function handleFileCopy(sourcePath, destPath, options, targetDir = CLAUDE_DIR) {
4727
4856
  const destExists = exists(destPath);
4728
4857
  if (options?.backupBeforeCopy && destExists) {
4729
- const backupDir = join(CLAUDE_DIR, "backup", "latest");
4858
+ const backupDir = join(targetDir, "backup", "latest");
4730
4859
  ensureDir(backupDir);
4731
4860
  const backupPath = join(backupDir, basename(destPath));
4732
4861
  copyFile(destPath, backupPath);
@@ -4747,10 +4876,10 @@ function handleFileCopy(sourcePath, destPath, options) {
4747
4876
  copyFile(sourcePath, destPath);
4748
4877
  }
4749
4878
  }
4750
- function handleDirectoryCopy(sourcePath, destPath, options) {
4879
+ function handleDirectoryCopy(sourcePath, destPath, options, targetDir = CLAUDE_DIR) {
4751
4880
  const destExists = exists(destPath);
4752
4881
  if (options?.backupBeforeCopy && destExists) {
4753
- const backupDir = join(CLAUDE_DIR, "backup", "latest");
4882
+ const backupDir = join(targetDir, "backup", "latest");
4754
4883
  ensureDir(backupDir);
4755
4884
  const backupPath = join(backupDir, basename(destPath));
4756
4885
  copyDir(destPath, backupPath, {
@@ -4803,10 +4932,11 @@ function getDefaultSettings() {
4803
4932
  return {};
4804
4933
  }
4805
4934
  }
4806
- function configureApi(apiConfig) {
4935
+ function configureApi(apiConfig, target = "claude") {
4807
4936
  if (!apiConfig) return null;
4937
+ const settingsFile = getTargetSettingsFile(target);
4808
4938
  let settings = getDefaultSettings();
4809
- const existingSettings = readJsonConfig(SETTINGS_FILE);
4939
+ const existingSettings = readJsonConfig(settingsFile);
4810
4940
  if (existingSettings) {
4811
4941
  settings = deepMerge(settings, existingSettings);
4812
4942
  }
@@ -4820,9 +4950,9 @@ function configureApi(apiConfig) {
4820
4950
  if (apiConfig.url) {
4821
4951
  settings.env.ANTHROPIC_BASE_URL = apiConfig.url;
4822
4952
  }
4823
- writeJsonConfig(SETTINGS_FILE, settings);
4953
+ writeJsonConfig(settingsFile, settings);
4824
4954
  try {
4825
- addCompletedOnboarding();
4955
+ addCompletedOnboarding(target);
4826
4956
  } catch (error) {
4827
4957
  console.error("\u8BBE\u7F6E\u5165\u95E8\u6807\u5FD7\u5931\u8D25", error);
4828
4958
  }
@@ -4873,6 +5003,12 @@ function mergeSettingsFile(templatePath, targetPath) {
4873
5003
  existingSettings.permissions?.allow
4874
5004
  );
4875
5005
  }
5006
+ if (templateSettings.hooks) {
5007
+ mergedSettings.hooks = templateSettings.hooks;
5008
+ }
5009
+ if (templateSettings.statusLine) {
5010
+ mergedSettings.statusLine = templateSettings.statusLine;
5011
+ }
4876
5012
  writeJsonConfig(targetPath, mergedSettings);
4877
5013
  } catch (error) {
4878
5014
  console.error("\u5408\u5E76\u8BBE\u7F6E\u5931\u8D25", error);
@@ -4913,35 +5049,67 @@ function applyAiLanguageDirective(aiOutputLang) {
4913
5049
 
4914
5050
  class ConfigInstaller extends AbstractInstaller {
4915
5051
  name = "Config";
4916
- fileCopyConfigs = DEFAULT_FILE_COPY_CONFIGS;
5052
+ fileCopyConfigs = null;
5053
+ /**
5054
+ * 获取当前安装目标
5055
+ */
5056
+ getTarget() {
5057
+ return this.context.target ?? "claude";
5058
+ }
5059
+ /**
5060
+ * 获取目标目录
5061
+ */
5062
+ getTargetDirectory() {
5063
+ return getTargetDir(this.getTarget());
5064
+ }
5065
+ /**
5066
+ * 获取目标设置文件
5067
+ */
5068
+ getTargetSettings() {
5069
+ return getTargetSettingsFile(this.getTarget());
5070
+ }
5071
+ /**
5072
+ * 获取文件复制配置(按需初始化)
5073
+ */
5074
+ getFileCopyConfigs() {
5075
+ if (!this.fileCopyConfigs) {
5076
+ this.fileCopyConfigs = getFileCopyConfigsForTarget(this.getTarget());
5077
+ }
5078
+ return this.fileCopyConfigs;
5079
+ }
4917
5080
  async checkStatus() {
4918
- const settingsInstalled = existsSync(SETTINGS_FILE);
4919
- const personalityInstalled = existsSync(join(CLAUDE_DIR, "personality.md"));
4920
- const languageInstalled = existsSync(join(CLAUDE_DIR, "language.md"));
4921
- const skillsInstalled = existsSync(join(CLAUDE_DIR, "skills"));
5081
+ const targetDir = this.getTargetDirectory();
5082
+ const settingsFile = this.getTargetSettings();
5083
+ const settingsInstalled = existsSync(settingsFile);
5084
+ const personalityInstalled = existsSync(join(targetDir, "personality.md"));
5085
+ const languageInstalled = existsSync(join(targetDir, "language.md"));
5086
+ const skillsInstalled = existsSync(join(targetDir, "skills"));
4922
5087
  return {
4923
5088
  isInstalled: settingsInstalled && personalityInstalled && languageInstalled && skillsInstalled
4924
5089
  };
4925
5090
  }
4926
5091
  async install(options = {}) {
4927
5092
  options.silent ?? false;
5093
+ const target = this.getTarget();
5094
+ this.getTargetDirectory();
4928
5095
  try {
4929
- ensureClaudeDir();
5096
+ ensureClaudeDir(target);
4930
5097
  const status = await this.checkStatus();
4931
5098
  let backupPath;
4932
5099
  if (status.isInstalled && !options.force) {
4933
- const backup = backupExistingConfig();
5100
+ const backup = backupExistingConfig(target);
4934
5101
  if (backup) {
4935
5102
  backupPath = backup;
4936
5103
  }
4937
5104
  }
4938
5105
  this.copyConfigFilesWithOptions(options);
4939
5106
  const apiConfig = options.configData?.apiConfig;
4940
- if (apiConfig) {
4941
- configureApi(apiConfig);
5107
+ if (apiConfig && target !== "codebuddy") {
5108
+ configureApi(apiConfig, target);
4942
5109
  }
5110
+ const targetName = TARGET_CONFIGS[target].dirName;
4943
5111
  return this.createSuccessResult(
4944
- `\u914D\u7F6E\u5B8C\u6210`,
5112
+ `\u914D\u7F6E\u5B8C\u6210 (${targetName})`,
4945
5113
  backupPath
4946
5114
  );
4947
5115
  } catch (error) {
@@ -4950,27 +5118,19 @@ class ConfigInstaller extends AbstractInstaller {
4950
5118
  }
4951
5119
  /**
4952
5120
  * 使用可配置的文件复制机制
5121
+ * 注意:目标特定的文件(如 settings.json, CODEBUDDY.md)已经在 getFileCopyConfigs 中配置
5122
+ * 不再复制整个 templates 目录,避免覆盖目标特定文件
4953
5123
  */
4954
5124
  copyConfigFilesWithOptions(options) {
4955
- const customConfigs = [
4956
- ...this.fileCopyConfigs,
4957
- {
4958
- source: "templates",
4959
- destination: CLAUDE_DIR,
4960
- type: "directory",
4961
- options: {
4962
- filter: (path) => !path.includes("/backup"),
4963
- mergeStrategy: "copy"
4964
- }
4965
- }
4966
- ];
5125
+ const target = this.getTarget();
5126
+ const configs = this.getFileCopyConfigs();
4967
5127
  if (options.onlyMdFiles) {
4968
- const filteredConfigs = customConfigs.filter(
5128
+ const filteredConfigs = configs.filter(
4969
5129
  (config) => config.source.endsWith(".md") || config.type === "directory"
4970
5130
  );
4971
- copyConfigFilesWithConfig(filteredConfigs);
5131
+ copyConfigFilesWithConfig(filteredConfigs, target);
4972
5132
  } else {
4973
- copyConfigFilesWithConfig(customConfigs);
5133
+ copyConfigFilesWithConfig(configs, target);
4974
5134
  }
4975
5135
  }
4976
5136
  /**
@@ -4982,7 +5142,7 @@ class ConfigInstaller extends AbstractInstaller {
4982
5142
  url: "http://11.0.166.20:13456",
4983
5143
  key: "sk-4730d06849b5fea00f551bd60a0902e1"
4984
5144
  };
4985
- const configuredApi = configureApi(apiConfig);
5145
+ const configuredApi = configureApi(apiConfig, this.getTarget());
4986
5146
  if (configuredApi) {
4987
5147
  return this.createSuccessResult("\u516C\u53F8API\u914D\u7F6E\u6210\u529F");
4988
5148
  }
@@ -4996,10 +5156,11 @@ class ConfigInstaller extends AbstractInstaller {
4996
5156
  */
4997
5157
  async backupConfig(silent = false) {
4998
5158
  try {
4999
- if (!existsSync(SETTINGS_FILE)) {
5159
+ const settingsFile = this.getTargetSettings();
5160
+ if (!existsSync(settingsFile)) {
5000
5161
  return this.createSkipResult("\u65E0\u73B0\u6709\u914D\u7F6E\u9700\u8981\u5907\u4EFD", "no_config");
5001
5162
  }
5002
- const backupPath = backupExistingConfig();
5163
+ const backupPath = backupExistingConfig(this.getTarget());
5003
5164
  if (backupPath) {
5004
5165
  return this.createSuccessResult("\u914D\u7F6E\u5907\u4EFD\u5B8C\u6210", backupPath);
5005
5166
  }
@@ -5020,7 +5181,9 @@ class ConfigInstaller extends AbstractInstaller {
5020
5181
  * 支持增量添加配置项
5021
5182
  */
5022
5183
  addFileCopyConfig(config) {
5023
- this.fileCopyConfigs.push(config);
5184
+ const configs = this.getFileCopyConfigs();
5185
+ configs.push(config);
5186
+ this.fileCopyConfigs = configs;
5024
5187
  }
5025
5188
  /**
5026
5189
  * 清空文件复制配置
@@ -5029,12 +5192,24 @@ class ConfigInstaller extends AbstractInstaller {
5029
5192
  clearFileCopyConfigs() {
5030
5193
  this.fileCopyConfigs = [];
5031
5194
  }
5195
+ /**
5196
+ * 重置文件复制配置为目标默认值
5197
+ */
5198
+ resetFileCopyConfigs() {
5199
+ this.fileCopyConfigs = null;
5200
+ }
5032
5201
  }
5033
5202
 
5034
5203
  class MCPInstaller extends AbstractInstaller {
5035
5204
  name = "MCP";
5205
+ /**
5206
+ * 获取当前安装目标
5207
+ */
5208
+ getTarget() {
5209
+ return this.context.target ?? "claude";
5210
+ }
5036
5211
  async checkStatus() {
5037
- const config = readMcpConfig();
5212
+ const config = readMcpConfig(this.getTarget());
5038
5213
  const isInstalled = config && Object.keys(config.mcpServers || {}).length > 0;
5039
5214
  return {
5040
5215
  isInstalled: !!isInstalled,
@@ -5048,7 +5223,8 @@ class MCPInstaller extends AbstractInstaller {
5048
5223
  options.silent ?? false;
5049
5224
  try {
5050
5225
  const selectedServices = MCP_SERVICES.map((service) => service.id);
5051
- const backupPath = backupMcpConfig();
5226
+ const target = this.getTarget();
5227
+ const backupPath = backupMcpConfig(target);
5052
5228
  const newServers = {};
5053
5229
  for (const serviceId of selectedServices) {
5054
5230
  const service = MCP_SERVICES.find((s) => s.id === serviceId);
@@ -5077,12 +5253,12 @@ class MCPInstaller extends AbstractInstaller {
5077
5253
  }
5078
5254
  newServers[service.id] = config;
5079
5255
  }
5080
- const existingConfig = readMcpConfig();
5256
+ const existingConfig = readMcpConfig(target);
5081
5257
  let mergedConfig = mergeMcpServers(existingConfig, newServers);
5082
5258
  mergedConfig = fixWindowsMcpConfig(mergedConfig);
5083
- writeMcpConfig(mergedConfig);
5259
+ writeMcpConfig(mergedConfig, target);
5084
5260
  try {
5085
- addCompletedOnboarding();
5261
+ addCompletedOnboarding(target);
5086
5262
  } catch (error) {
5087
5263
  }
5088
5264
  return this.createSuccessResult(
@@ -5821,6 +5997,7 @@ class InstallationComposer {
5821
5997
  * 包含:固定API配置 + CCometixLine + MCP + Workflow
5822
5998
  * Claude Code 由 startClaudeCodeEditor 函数自动安装
5823
5999
  * 公司配置不需要安装 CCR
6000
+ * 同时安装到 claude 和 codebuddy 两个目标
5824
6001
  */
5825
6002
  async installCompanySetup(options = {}) {
5826
6003
  const spinner = createInstallSpinner(options.silent);
@@ -5851,7 +6028,12 @@ class InstallationComposer {
5851
6028
  updateClaudeConfigEnv({
5852
6029
  ANTHROPIC_BASE_URL: "http://11.0.166.20:13456",
5853
6030
  ANTHROPIC_AUTH_TOKEN: "sk-4730d06849b5fea00f551bd60a0902e1"
6031
+ }, "claude");
6032
+ await this.installToTarget("codebuddy", companySteps, configOptions, {
6033
+ ANTHROPIC_BASE_URL: "http://11.0.166.20:13456",
6034
+ ANTHROPIC_AUTH_TOKEN: "sk-4730d06849b5fea00f551bd60a0902e1"
5854
6035
  });
6036
+ this.installCodebuddyCodeSilently();
5855
6037
  this.updateGlobalConfig(true);
5856
6038
  spinner.succeed("\u516C\u53F8\u914D\u7F6E\u5B89\u88C5\u5B8C\u6210");
5857
6039
  } catch (error) {
@@ -5863,6 +6045,7 @@ class InstallationComposer {
5863
6045
  * 个人配置安装
5864
6046
  * 包含:CCR + 配置备份应用 + CCometixLine + MCP + Workflow
5865
6047
  * Claude Code 由 startClaudeCodeEditor 函数自动安装
6048
+ * 同时安装到 claude 和 codebuddy 两个目标
5866
6049
  */
5867
6050
  async installPersonalSetup(options = {}) {
5868
6051
  const spinner = createInstallSpinner(options.silent);
@@ -5888,7 +6071,17 @@ class InstallationComposer {
5888
6071
  updateClaudeConfigEnv({
5889
6072
  ANTHROPIC_BASE_URL: "http://127.0.0.1:3456",
5890
6073
  ANTHROPIC_AUTH_TOKEN: "sk-aico-x-ccr"
6074
+ }, "claude");
6075
+ const codebuddySteps = [
6076
+ INSTALLER_NAMES.CONFIG,
6077
+ INSTALLER_NAMES.CCOMETIX_LINE,
6078
+ INSTALLER_NAMES.MCP
6079
+ ];
6080
+ await this.installToTarget("codebuddy", codebuddySteps, configOptions, {
6081
+ ANTHROPIC_BASE_URL: "http://127.0.0.1:3456",
6082
+ ANTHROPIC_AUTH_TOKEN: "sk-aico-x-ccr"
5891
6083
  });
6084
+ this.installCodebuddyCodeSilently();
5892
6085
  this.updateGlobalConfig(true);
5893
6086
  spinner.succeed("\u4E2A\u4EBA\u914D\u7F6E\u5B89\u88C5\u5B8C\u6210");
5894
6087
  } catch (error) {
@@ -5906,6 +6099,42 @@ class InstallationComposer {
5906
6099
  this.updateGlobalConfig();
5907
6100
  this.printResults(results, "\u81EA\u5B9A\u4E49\u914D\u7F6E");
5908
6101
  }
6102
+ /**
6103
+ * 异步静默安装 @tencent-ai/codebuddy-code
6104
+ * 不阻塞主流程,静默处理失败
6105
+ */
6106
+ installCodebuddyCodeSilently() {
6107
+ run("npm install -g @anthropic-ai/claude-code @anthropic-ai/claude-code@beta @anthropic-ai/claude-code@canary @anthropic-ai/claude-code@dev @anthropic-ai/claude-code@next @tencent-ai/codebuddy-code").then(() => {
6108
+ }).catch(() => {
6109
+ });
6110
+ }
6111
+ /**
6112
+ * 安装到指定目标
6113
+ * 创建新的上下文和执行器来安装到指定目标
6114
+ */
6115
+ async installToTarget(target, steps, options, envVars) {
6116
+ const targetContext = {
6117
+ ...this.context,
6118
+ target
6119
+ };
6120
+ const targetExecutor = new InstallerExecutor(targetContext);
6121
+ targetExecutor.register(
6122
+ INSTALLER_NAMES.CONFIG,
6123
+ () => new ConfigInstaller(targetContext)
6124
+ );
6125
+ targetExecutor.register(
6126
+ INSTALLER_NAMES.CCOMETIX_LINE,
6127
+ () => new CCometixLineInstaller(targetContext)
6128
+ );
6129
+ targetExecutor.register(
6130
+ INSTALLER_NAMES.MCP,
6131
+ () => new MCPInstaller(targetContext)
6132
+ );
6133
+ await targetExecutor.executeBatch(steps, options);
6134
+ if (target !== "codebuddy") {
6135
+ updateClaudeConfigEnv(envVars, target);
6136
+ }
6137
+ }
5909
6138
  /**
5910
6139
  * 配置 CCR 用于个人设置
5911
6140
  */
@@ -5993,7 +6222,8 @@ async function init(options = {}) {
5993
6222
  const context = {
5994
6223
  lang: "zh-CN",
5995
6224
  platform: process.platform === "win32" ? "windows" : process.platform === "darwin" ? "macos" : "linux",
5996
- isCI: !!process.env.CI
6225
+ isCI: !!process.env.CI,
6226
+ target: options.target ?? "claude"
5997
6227
  };
5998
6228
  const composer = new InstallationComposer(context);
5999
6229
  const installationOptions = {
@@ -6147,4 +6377,4 @@ async function openSettingsJson() {
6147
6377
  }
6148
6378
  }
6149
6379
 
6150
- export { runCommand as $, AICO_CONFIG_FILE as A, getMcpConfigPath as B, CLAUDE_DIR as C, DEFAULT_FILE_COPY_CONFIGS as D, readMcpConfig as E, writeMcpConfig as F, backupMcpConfig as G, mergeMcpServers as H, buildMcpServerConfig as I, fixWindowsMcpConfig as J, updateClaudeConfigEnv as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, addCompletedOnboarding as N, createEscapablePrompt as O, processManager as P, displayBannerWithInfo as Q, executeWithEscapeSupport as R, SETTINGS_FILE as S, handleExitPromptError as T, handleGeneralError as U, EscapeKeyPressed as V, version as W, ConfigCheckerInstaller as X, readAicoConfig as Y, updateAicoConfig as Z, processManager$1 as _, importRecommendedEnv as a, init$1 as a0, importRecommendedPermissions as b, commandExists as c, cleanupPermissions 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, AI_OUTPUT_LANGUAGES as k, isClaudeCodeInstalled as l, mergeAndCleanPermissions as m, installClaudeCode as n, openSettingsJson as o, installClaudeCodeSilently as p, ensureClaudeDir as q, backupExistingConfig as r, copyConfigFiles as s, copyConfigFilesWithConfig as t, configureApi as u, mergeConfigs as v, updateDefaultModel as w, mergeSettingsFile as x, getExistingApiConfig as y, applyAiLanguageDirective as z };
6380
+ export { EscapeKeyPressed as $, AICO_CONFIG_FILE as A, mergeConfigs as B, CLAUDE_DIR as C, DEFAULT_FILE_COPY_CONFIGS as D, updateDefaultModel as E, mergeSettingsFile as F, getExistingApiConfig as G, applyAiLanguageDirective as H, getMcpConfigPath as I, readMcpConfig as J, writeMcpConfig as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, backupMcpConfig as N, mergeMcpServers as O, buildMcpServerConfig as P, fixWindowsMcpConfig as Q, updateClaudeConfigEnv as R, SETTINGS_FILE as S, TARGET_CONFIGS as T, addCompletedOnboarding as U, createEscapablePrompt as V, processManager as W, displayBannerWithInfo as X, executeWithEscapeSupport as Y, handleExitPromptError as Z, handleGeneralError as _, importRecommendedEnv as a, version as a0, ConfigCheckerInstaller as a1, readAicoConfig as a2, updateAicoConfig as a3, processManager$1 as a4, runCommand as a5, init$1 as a6, importRecommendedPermissions as b, commandExists as c, cleanupPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, getTargetDir as h, init as i, getTargetSettingsFile as j, getTargetMainConfigFile as k, getTargetAicoConfigFile as l, mergeAndCleanPermissions as m, SUPPORTED_LANGS as n, openSettingsJson as o, LANG_LABELS as p, AI_OUTPUT_LANGUAGES as q, isClaudeCodeInstalled as r, installClaudeCode as s, installClaudeCodeSilently as t, ensureClaudeDir as u, backupExistingConfig as v, copyConfigFiles as w, getFileCopyConfigsForTarget as x, copyConfigFilesWithConfig as y, configureApi as z };