aico-cli 0.1.8 → 0.1.9

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.
@@ -2,7 +2,7 @@ import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
3
  import { exec } from 'tinyexec';
4
4
  import { platform, homedir } from 'node:os';
5
- import { existsSync, copyFileSync, mkdirSync, readdirSync, rmSync, unlinkSync, readFileSync, writeFileSync, statSync } from 'node:fs';
5
+ import { existsSync, copyFileSync, mkdirSync, readdirSync, rmSync, unlinkSync, readFileSync, writeFileSync, statSync, renameSync } from 'node:fs';
6
6
  import { exec as exec$2 } from 'node:child_process';
7
7
  import { promisify as promisify$1 } from 'node:util';
8
8
  import { exec as exec$1 } from 'child_process';
@@ -10,10 +10,10 @@ import { promisify } from 'util';
10
10
  import ora from 'ora';
11
11
  import 'dayjs';
12
12
  import { join as join$1 } from 'node:path';
13
- import { join, dirname } from 'pathe';
13
+ import { join, dirname, basename } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
 
16
- const version = "0.1.8";
16
+ const version = "0.1.9";
17
17
 
18
18
  function displayBanner(subtitle) {
19
19
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
@@ -4919,7 +4919,38 @@ class ConfigInstaller extends AbstractInstaller {
4919
4919
  copyFile(src, dest);
4920
4920
  }
4921
4921
  }
4922
- await this.copyAgentsAndCommandsDirectories(sourceDir);
4922
+ }
4923
+ /**
4924
+ * 安装工作流文件
4925
+ * 复制 agents 和 commands 目录
4926
+ */
4927
+ async installWorkflows() {
4928
+ try {
4929
+ this.log("\u5F00\u59CB\u5B89\u88C5\u5DE5\u4F5C\u6D41\u6587\u4EF6...", "info");
4930
+ const sourceDir = join(getPackageRoot(), "templates");
4931
+ const agentsDir = join(sourceDir, "agents");
4932
+ if (exists(agentsDir) && isDirectory(agentsDir)) {
4933
+ const destAgentsDir = join(CLAUDE_DIR, "agents");
4934
+ copyDir(agentsDir, destAgentsDir, { overwrite: true });
4935
+ this.log("\u5DF2\u590D\u5236: agents/ \u76EE\u5F55", "info");
4936
+ }
4937
+ const commandsDir = join(sourceDir, "commands");
4938
+ if (exists(commandsDir) && isDirectory(commandsDir)) {
4939
+ const destCommandsDir = join(CLAUDE_DIR, "commands");
4940
+ copyDir(commandsDir, destCommandsDir, { overwrite: true });
4941
+ this.log("\u5DF2\u590D\u5236: commands/ \u76EE\u5F55", "info");
4942
+ }
4943
+ this.log("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5\u5B8C\u6210", "success");
4944
+ return this.createSuccessResult("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5\u5B8C\u6210");
4945
+ } catch (error) {
4946
+ return this.handleError(error, "\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5");
4947
+ }
4948
+ }
4949
+ /**
4950
+ * 安装所有工作流
4951
+ */
4952
+ async installAllWorkflows() {
4953
+ return await this.installWorkflows();
4923
4954
  }
4924
4955
  /**
4925
4956
  * 复制 agents 和 commands 目录
@@ -4952,26 +4983,72 @@ class ConfigInstaller extends AbstractInstaller {
4952
4983
  this.log(`\u5DF2\u5907\u4EFD ${dirName} \u76EE\u5F55\u5230: ${backupDir}`, "info");
4953
4984
  }
4954
4985
  /**
4955
- * 清空目录内容
4986
+ * 清空目录内容(Windows兼容版本)
4956
4987
  */
4957
4988
  async cleanDirectory(dirPath) {
4958
4989
  if (!exists(dirPath)) {
4959
4990
  ensureDir(dirPath);
4960
4991
  return;
4961
4992
  }
4962
- const files = readDir(dirPath);
4963
- if (files && files.length > 0) {
4964
- for (const file of files) {
4965
- const filePath = join(dirPath, file);
4966
- if (isDirectory(filePath)) {
4967
- await this.cleanDirectory(filePath);
4968
- removeDir(filePath);
4969
- } else {
4970
- removeFile(filePath);
4993
+ try {
4994
+ const tempBackupDir = join(CLAUDE_DIR, ".temp-clean");
4995
+ const tempDir = join(tempBackupDir, `clean-${Date.now()}`);
4996
+ ensureDir(tempDir);
4997
+ const files = readDir(dirPath);
4998
+ if (files && files.length > 0) {
4999
+ for (const file of files) {
5000
+ const filePath = join(dirPath, file);
5001
+ try {
5002
+ if (isDirectory(filePath)) {
5003
+ removeDir(filePath);
5004
+ } else {
5005
+ removeFile(filePath);
5006
+ }
5007
+ } catch (error) {
5008
+ if (process.platform === "win32") {
5009
+ const tempFile = join(tempDir, file);
5010
+ try {
5011
+ renameSync(filePath, tempFile);
5012
+ this.log(`Windows\u517C\u5BB9\u5904\u7406: \u5DF2\u79FB\u52A8\u6587\u4EF6 ${file}`, "info");
5013
+ } catch (renameError) {
5014
+ this.log(`\u65E0\u6CD5\u79FB\u52A8\u6587\u4EF6 ${file}: ${renameError}`, "warning");
5015
+ }
5016
+ }
5017
+ }
5018
+ }
5019
+ }
5020
+ if (exists(tempDir)) {
5021
+ try {
5022
+ removeDir(tempDir);
5023
+ } catch (tempError) {
5024
+ this.log(`\u65E0\u6CD5\u6E05\u7406\u4E34\u65F6\u6587\u4EF6: ${tempError}`, "warning");
5025
+ }
5026
+ }
5027
+ this.log(`\u5DF2\u6E05\u7A7A ${dirPath} \u76EE\u5F55`, "info");
5028
+ } catch (error) {
5029
+ this.log(`\u6E05\u7A7A\u76EE\u5F55\u5931\u8D25: ${error}`, "warning");
5030
+ if (process.platform === "win32") {
5031
+ try {
5032
+ const dirName = basename(dirPath);
5033
+ const parentDir = dirname(dirPath);
5034
+ const backupDir = join(parentDir, `${dirName}.backup.${Date.now()}`);
5035
+ if (exists(dirPath)) {
5036
+ renameSync(dirPath, backupDir);
5037
+ ensureDir(dirPath);
5038
+ setTimeout(() => {
5039
+ try {
5040
+ removeDir(backupDir);
5041
+ } catch (backupError) {
5042
+ this.log(`\u65E0\u6CD5\u5220\u9664\u5907\u4EFD\u76EE\u5F55: ${backupError}`, "warning");
5043
+ }
5044
+ }, 1e3);
5045
+ this.log(`\u4F7F\u7528Windows\u5907\u9009\u65B9\u6848\u6E05\u7A7A\u76EE\u5F55: ${dirPath}`, "info");
5046
+ }
5047
+ } catch (fallbackError) {
5048
+ this.log(`Windows\u5907\u9009\u65B9\u6848\u4E5F\u5931\u8D25: ${fallbackError}`, "error");
4971
5049
  }
4972
5050
  }
4973
5051
  }
4974
- this.log(`\u5DF2\u6E05\u7A7A ${dirPath} \u76EE\u5F55`, "info");
4975
5052
  }
4976
5053
  }
4977
5054
 
@@ -5065,175 +5142,6 @@ class MCPInstaller extends AbstractInstaller {
5065
5142
  }
5066
5143
  }
5067
5144
 
5068
- async function createBackup(sourceDir, backupDir, options = {}) {
5069
- const { include, exclude = [], recursive = true } = options;
5070
- if (!exists(sourceDir)) {
5071
- return void 0;
5072
- }
5073
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5074
- const timestampedBackupDir = join(backupDir, `backup-${timestamp}`);
5075
- ensureDir(timestampedBackupDir);
5076
- if (include && include.length > 0) {
5077
- for (const fileName of include) {
5078
- const srcPath = join(sourceDir, fileName);
5079
- const destPath = join(timestampedBackupDir, fileName);
5080
- if (exists(srcPath)) {
5081
- if (isDirectory(srcPath)) {
5082
- copyDir(srcPath, destPath, { overwrite: true });
5083
- } else {
5084
- copyFile(srcPath, destPath);
5085
- }
5086
- }
5087
- }
5088
- } else {
5089
- const entries = readDir(sourceDir);
5090
- for (const entry of entries) {
5091
- if (exclude.includes(entry)) {
5092
- continue;
5093
- }
5094
- const srcPath = join(sourceDir, entry);
5095
- const destPath = join(timestampedBackupDir, entry);
5096
- if (isDirectory(srcPath) && recursive) {
5097
- copyDir(srcPath, destPath, { overwrite: true });
5098
- } else if (isFile(srcPath)) {
5099
- copyFile(srcPath, destPath);
5100
- }
5101
- }
5102
- }
5103
- return timestampedBackupDir;
5104
- }
5105
- async function restoreFromBackup(backupDir, targetDir) {
5106
- if (!exists(backupDir)) {
5107
- return false;
5108
- }
5109
- const latestBackup = await getLatestBackup(backupDir);
5110
- if (!latestBackup) {
5111
- return false;
5112
- }
5113
- copyDir(latestBackup, targetDir, { overwrite: true });
5114
- return true;
5115
- }
5116
- async function getLatestBackup(backupBaseDir) {
5117
- if (!exists(backupBaseDir)) {
5118
- return void 0;
5119
- }
5120
- const entries = readDir(backupBaseDir);
5121
- const backupDirs = entries.filter((entry) => {
5122
- const fullPath = join(backupBaseDir, entry);
5123
- return isDirectory(fullPath) && entry.startsWith("backup-");
5124
- }).sort().reverse();
5125
- return backupDirs.length > 0 ? join(backupBaseDir, backupDirs[0]) : void 0;
5126
- }
5127
-
5128
- class WorkflowInstaller extends AbstractInstaller {
5129
- name = "Workflow";
5130
- sourceDir;
5131
- targetDir;
5132
- backupDir;
5133
- constructor(context) {
5134
- super(context);
5135
- this.sourceDir = join(getPackageRoot(), "templates");
5136
- this.targetDir = CLAUDE_DIR;
5137
- this.backupDir = join(CLAUDE_DIR, ".backups", "workflow");
5138
- }
5139
- async checkStatus() {
5140
- try {
5141
- const commandsDir = join(this.targetDir, "commands");
5142
- const isInstalled = exists(commandsDir) && isDirectory(commandsDir);
5143
- return { isInstalled };
5144
- } catch (error) {
5145
- this.log(`\u72B6\u6001\u68C0\u67E5\u5931\u8D25: ${error}`, "error");
5146
- return { isInstalled: false };
5147
- }
5148
- }
5149
- requiresInteraction(options) {
5150
- return false;
5151
- }
5152
- async install(options = {}) {
5153
- try {
5154
- this.log("\u5F00\u59CB\u5B89\u88C5\u5DE5\u4F5C\u6D41\u6587\u4EF6...", "info");
5155
- if (!exists(this.sourceDir)) {
5156
- return this.createFailureResult(`\u6E90\u76EE\u5F55\u4E0D\u5B58\u5728: ${this.sourceDir}`);
5157
- }
5158
- ensureDir(this.targetDir);
5159
- const backupPath = await this.createBackupIfNeeded(options);
5160
- await this.copyWorkflowFiles();
5161
- if (this.context?.lang) {
5162
- applyAiLanguageDirective(this.context.lang);
5163
- this.log("\u8BED\u8A00\u6307\u4EE4\u5E94\u7528\u6210\u529F", "success");
5164
- }
5165
- this.log("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5\u5B8C\u6210", "success");
5166
- return this.createSuccessResult("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5\u5B8C\u6210", backupPath);
5167
- } catch (error) {
5168
- return this.handleError(error, "\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5");
5169
- }
5170
- }
5171
- /**
5172
- * 卸载工作流文件,恢复备份
5173
- */
5174
- async uninstall() {
5175
- try {
5176
- this.log("\u5F00\u59CB\u5378\u8F7D\u5DE5\u4F5C\u6D41\u6587\u4EF6...", "info");
5177
- const restored = await restoreFromBackup(this.backupDir, this.targetDir);
5178
- if (restored) {
5179
- this.log("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5DF2\u6062\u590D\u5230\u4E4B\u524D\u7684\u72B6\u6001", "success");
5180
- return this.createSuccessResult("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5DF2\u6062\u590D\u5230\u4E4B\u524D\u7684\u72B6\u6001");
5181
- } else {
5182
- this.log("\u672A\u627E\u5230\u5907\u4EFD\u6587\u4EF6\uFF0C\u8DF3\u8FC7\u6062\u590D", "warning");
5183
- return this.createSkipResult("\u672A\u627E\u5230\u5907\u4EFD\u6587\u4EF6", "no_backup");
5184
- }
5185
- } catch (error) {
5186
- return this.handleError(error, "\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5378\u8F7D");
5187
- }
5188
- }
5189
- /**
5190
- * 创建备份(如果需要)
5191
- */
5192
- async createBackupIfNeeded(options) {
5193
- if (options.force) {
5194
- return void 0;
5195
- }
5196
- const status = await this.checkStatus();
5197
- if (status.isInstalled) {
5198
- this.log("\u68C0\u6D4B\u5230\u5DF2\u5B58\u5728\u7684\u5DE5\u4F5C\u6D41\u6587\u4EF6\uFF0C\u521B\u5EFA\u5907\u4EFD...", "info");
5199
- return await createBackup(this.targetDir, this.backupDir, {
5200
- include: ["commands"]
5201
- });
5202
- }
5203
- return void 0;
5204
- }
5205
- /**
5206
- * 复制工作流相关文件
5207
- * 遵循 SOLID 原则的单一职责原则
5208
- */
5209
- async copyWorkflowFiles() {
5210
- const agentsDir = join(this.sourceDir, "agents");
5211
- if (exists(agentsDir) && isDirectory(agentsDir)) {
5212
- const destAgentsDir = join(this.targetDir, "agents");
5213
- copyDir(agentsDir, destAgentsDir, { overwrite: true });
5214
- this.log("\u5DF2\u590D\u5236: agents/ \u76EE\u5F55", "info");
5215
- }
5216
- const commandsDir = join(this.sourceDir, "commands");
5217
- if (exists(commandsDir) && isDirectory(commandsDir)) {
5218
- const destCommandsDir = join(this.targetDir, "commands");
5219
- copyDir(commandsDir, destCommandsDir, { overwrite: true });
5220
- this.log("\u5DF2\u590D\u5236: commands/ \u76EE\u5F55", "info");
5221
- }
5222
- }
5223
- /**
5224
- * 安装指定的工作流
5225
- */
5226
- async installSpecificWorkflows(workflowIds) {
5227
- return await this.install({ skipPrompt: true });
5228
- }
5229
- /**
5230
- * 安装所有工作流
5231
- */
5232
- async installAllWorkflows() {
5233
- return await this.install({ skipPrompt: true });
5234
- }
5235
- }
5236
-
5237
5145
  class ConfigCheckerInstaller extends AbstractInstaller {
5238
5146
  name = "Config Checker";
5239
5147
  async checkStatus() {
@@ -5302,7 +5210,6 @@ const INSTALLER_NAMES = {
5302
5210
  CCOMETIX_LINE: "ccometix-line",
5303
5211
  CONFIG: "config",
5304
5212
  MCP: "mcp",
5305
- WORKFLOW: "workflow",
5306
5213
  CONFIG_CHECKER: "config-checker"
5307
5214
  };
5308
5215
 
@@ -5339,10 +5246,6 @@ class InstallationComposer {
5339
5246
  INSTALLER_NAMES.MCP,
5340
5247
  () => new MCPInstaller(this.context)
5341
5248
  );
5342
- this.executor.register(
5343
- INSTALLER_NAMES.WORKFLOW,
5344
- () => new WorkflowInstaller(this.context)
5345
- );
5346
5249
  this.executor.register(
5347
5250
  INSTALLER_NAMES.CONFIG_CHECKER,
5348
5251
  () => new ConfigCheckerInstaller(this.context)
@@ -5379,8 +5282,7 @@ class InstallationComposer {
5379
5282
  INSTALLER_NAMES.CLAUDE_CODE,
5380
5283
  INSTALLER_NAMES.CONFIG,
5381
5284
  INSTALLER_NAMES.CCOMETIX_LINE,
5382
- INSTALLER_NAMES.MCP,
5383
- INSTALLER_NAMES.WORKFLOW
5285
+ INSTALLER_NAMES.MCP
5384
5286
  ];
5385
5287
  const companyResults = await this.executor.executeBatch(companySteps, configOptions);
5386
5288
  const configInstaller = new ConfigInstaller(this.context);
@@ -5393,8 +5295,7 @@ class InstallationComposer {
5393
5295
  INSTALLER_NAMES.CLAUDE_CODE,
5394
5296
  INSTALLER_NAMES.CONFIG,
5395
5297
  INSTALLER_NAMES.CCOMETIX_LINE,
5396
- INSTALLER_NAMES.MCP,
5397
- INSTALLER_NAMES.WORKFLOW
5298
+ INSTALLER_NAMES.MCP
5398
5299
  ];
5399
5300
  const companyResults = await this.executor.executeBatch(companySteps, configOptions);
5400
5301
  const configInstaller = new ConfigInstaller(this.context);
@@ -5414,8 +5315,7 @@ class InstallationComposer {
5414
5315
  INSTALLER_NAMES.CCR,
5415
5316
  INSTALLER_NAMES.CONFIG,
5416
5317
  INSTALLER_NAMES.CCOMETIX_LINE,
5417
- INSTALLER_NAMES.MCP,
5418
- INSTALLER_NAMES.WORKFLOW
5318
+ INSTALLER_NAMES.MCP
5419
5319
  ];
5420
5320
  const configOptions = {
5421
5321
  ...options,
@@ -5529,8 +5429,7 @@ class InstallationComposer {
5529
5429
  [INSTALLER_NAMES.CCR]: "CCR \u8DEF\u7531\u5668",
5530
5430
  [INSTALLER_NAMES.CCOMETIX_LINE]: "CCometixLine \u72B6\u6001\u680F",
5531
5431
  [INSTALLER_NAMES.CONFIG]: "\u914D\u7F6E\u6587\u4EF6",
5532
- [INSTALLER_NAMES.MCP]: "MCP \u670D\u52A1",
5533
- [INSTALLER_NAMES.WORKFLOW]: "\u5DE5\u4F5C\u6D41"
5432
+ [INSTALLER_NAMES.MCP]: "MCP \u670D\u52A1"
5534
5433
  };
5535
5434
  return nameMap[name] || name;
5536
5435
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aico-cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "packageManager": "pnpm@9.15.9",
5
5
  "description": "AI CLI",
6
6
  "repository": {