aico-cli 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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, renameSync } from 'node:fs';
5
+ import { existsSync, copyFileSync, readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } 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, basename } from 'pathe';
13
+ import { join, dirname } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
 
16
- const version = "0.2.2";
16
+ const version = "0.2.4";
17
17
 
18
18
  function displayBanner(subtitle) {
19
19
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
@@ -3386,13 +3386,6 @@ function isDirectory(path) {
3386
3386
  return false;
3387
3387
  }
3388
3388
  }
3389
- function isFile(path) {
3390
- try {
3391
- return getStats(path).isFile();
3392
- } catch {
3393
- return false;
3394
- }
3395
- }
3396
3389
  function copyDir(src, dest, options = {}) {
3397
3390
  const { filter, overwrite = true } = options;
3398
3391
  if (!exists(src)) {
@@ -3417,32 +3410,6 @@ function copyDir(src, dest, options = {}) {
3417
3410
  }
3418
3411
  }
3419
3412
  }
3420
- function removeFile(path) {
3421
- try {
3422
- if (exists(path) && isFile(path)) {
3423
- unlinkSync(path);
3424
- }
3425
- } catch (error) {
3426
- throw new FileSystemError(
3427
- `Failed to remove file: ${path}`,
3428
- path,
3429
- error
3430
- );
3431
- }
3432
- }
3433
- function removeDir(path) {
3434
- try {
3435
- if (exists(path) && isDirectory(path)) {
3436
- rmSync(path, { recursive: true, force: true });
3437
- }
3438
- } catch (error) {
3439
- throw new FileSystemError(
3440
- `Failed to remove directory: ${path}`,
3441
- path,
3442
- error
3443
- );
3444
- }
3445
- }
3446
3413
 
3447
3414
  const messages = {
3448
3415
  // 菜单相关
@@ -4848,10 +4815,7 @@ class ConfigInstaller extends AbstractInstaller {
4848
4815
  }
4849
4816
  copyConfigFiles("zh-CN", false);
4850
4817
  await this.copyAiPersonalityFiles();
4851
- const workflowResult = await this.installWorkflows();
4852
- if (!workflowResult.success) {
4853
- this.log(`\u5DE5\u4F5C\u6D41\u5B89\u88C5\u5931\u8D25: ${workflowResult.message}`, "warning");
4854
- }
4818
+ await this.copyTemplateFiles();
4855
4819
  const apiConfig = options.configData?.apiConfig;
4856
4820
  if (apiConfig) {
4857
4821
  const configuredApi = configureApi(apiConfig);
@@ -4925,133 +4889,22 @@ class ConfigInstaller extends AbstractInstaller {
4925
4889
  }
4926
4890
  }
4927
4891
  /**
4928
- * 安装工作流文件
4929
- * 复制 agents 和 commands 目录
4892
+ * 复制模板文件(agents和commands目录)
4893
+ * 确保完整的目录结构被复制
4930
4894
  */
4931
- async installWorkflows() {
4932
- try {
4933
- this.log("\u5F00\u59CB\u5B89\u88C5\u5DE5\u4F5C\u6D41\u6587\u4EF6...", "info");
4934
- const sourceDir = join(getPackageRoot(), "templates");
4935
- const agentsDir = join(sourceDir, "agents");
4936
- if (exists(agentsDir) && isDirectory(agentsDir)) {
4937
- const destAgentsDir = join(CLAUDE_DIR, "agents");
4938
- copyDir(agentsDir, destAgentsDir, { overwrite: true });
4939
- this.log("\u5DF2\u590D\u5236: agents/ \u76EE\u5F55", "info");
4940
- }
4941
- const commandsDir = join(sourceDir, "commands");
4942
- if (exists(commandsDir) && isDirectory(commandsDir)) {
4943
- const destCommandsDir = join(CLAUDE_DIR, "commands");
4944
- copyDir(commandsDir, destCommandsDir, { overwrite: true });
4945
- this.log("\u5DF2\u590D\u5236: commands/ \u76EE\u5F55", "info");
4946
- }
4947
- this.log("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5\u5B8C\u6210", "success");
4948
- return this.createSuccessResult("\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5\u5B8C\u6210");
4949
- } catch (error) {
4950
- return this.handleError(error, "\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5B89\u88C5");
4951
- }
4952
- }
4953
- /**
4954
- * 安装所有工作流
4955
- */
4956
- async installAllWorkflows() {
4957
- return await this.installWorkflows();
4958
- }
4959
- /**
4960
- * 复制 agents 和 commands 目录
4961
- * 遵循先备份、再清空、最后复制的流程
4962
- */
4963
- async copyAgentsAndCommandsDirectories(sourceDir) {
4964
- const directoriesToCopy = ["agents", "commands"];
4965
- for (const dirName of directoriesToCopy) {
4966
- const sourceSubDir = join(sourceDir, dirName);
4967
- const destSubDir = join(CLAUDE_DIR, dirName);
4968
- if (exists(sourceSubDir) && isDirectory(sourceSubDir)) {
4969
- await this.backupDirectory(dirName, destSubDir);
4970
- await this.cleanDirectory(destSubDir);
4971
- copyDir(sourceSubDir, destSubDir, { overwrite: true });
4972
- this.log(`\u5DF2\u590D\u5236 ${dirName} \u76EE\u5F55`, "success");
4973
- }
4974
- }
4975
- }
4976
- /**
4977
- * 备份目录到 backup 文件夹
4978
- */
4979
- async backupDirectory(dirName, sourceDir) {
4980
- if (!exists(sourceDir)) {
4981
- return;
4982
- }
4983
- const backupBaseDir = join(CLAUDE_DIR, "backup");
4984
- const backupDir = join(backupBaseDir, dirName);
4985
- ensureDir(backupDir);
4986
- copyDir(sourceDir, backupDir, { overwrite: true });
4987
- this.log(`\u5DF2\u5907\u4EFD ${dirName} \u76EE\u5F55\u5230: ${backupDir}`, "info");
4988
- }
4989
- /**
4990
- * 清空目录内容(Windows兼容版本)
4991
- */
4992
- async cleanDirectory(dirPath) {
4993
- if (!exists(dirPath)) {
4994
- ensureDir(dirPath);
4995
- return;
4895
+ async copyTemplateFiles() {
4896
+ const sourceDir = join(getPackageRoot(), "templates");
4897
+ const agentsDir = join(sourceDir, "agents");
4898
+ if (exists(agentsDir) && isDirectory(agentsDir)) {
4899
+ const destAgentsDir = join(CLAUDE_DIR, "agents");
4900
+ copyDir(agentsDir, destAgentsDir, { overwrite: true });
4901
+ this.log("\u5DF2\u590D\u5236: agents/ \u76EE\u5F55\u53CA\u5176\u6240\u6709\u5185\u5BB9", "success");
4996
4902
  }
4997
- try {
4998
- const tempBackupDir = join(CLAUDE_DIR, ".temp-clean");
4999
- const tempDir = join(tempBackupDir, `clean-${Date.now()}`);
5000
- ensureDir(tempDir);
5001
- const files = readDir(dirPath);
5002
- if (files && files.length > 0) {
5003
- for (const file of files) {
5004
- const filePath = join(dirPath, file);
5005
- try {
5006
- if (isDirectory(filePath)) {
5007
- removeDir(filePath);
5008
- } else {
5009
- removeFile(filePath);
5010
- }
5011
- } catch (error) {
5012
- if (process.platform === "win32") {
5013
- const tempFile = join(tempDir, file);
5014
- try {
5015
- renameSync(filePath, tempFile);
5016
- this.log(`Windows\u517C\u5BB9\u5904\u7406: \u5DF2\u79FB\u52A8\u6587\u4EF6 ${file}`, "info");
5017
- } catch (renameError) {
5018
- this.log(`\u65E0\u6CD5\u79FB\u52A8\u6587\u4EF6 ${file}: ${renameError}`, "warning");
5019
- }
5020
- }
5021
- }
5022
- }
5023
- }
5024
- if (exists(tempDir)) {
5025
- try {
5026
- removeDir(tempDir);
5027
- } catch (tempError) {
5028
- this.log(`\u65E0\u6CD5\u6E05\u7406\u4E34\u65F6\u6587\u4EF6: ${tempError}`, "warning");
5029
- }
5030
- }
5031
- this.log(`\u5DF2\u6E05\u7A7A ${dirPath} \u76EE\u5F55`, "info");
5032
- } catch (error) {
5033
- this.log(`\u6E05\u7A7A\u76EE\u5F55\u5931\u8D25: ${error}`, "warning");
5034
- if (process.platform === "win32") {
5035
- try {
5036
- const dirName = basename(dirPath);
5037
- const parentDir = dirname(dirPath);
5038
- const backupDir = join(parentDir, `${dirName}.backup.${Date.now()}`);
5039
- if (exists(dirPath)) {
5040
- renameSync(dirPath, backupDir);
5041
- ensureDir(dirPath);
5042
- setTimeout(() => {
5043
- try {
5044
- removeDir(backupDir);
5045
- } catch (backupError) {
5046
- this.log(`\u65E0\u6CD5\u5220\u9664\u5907\u4EFD\u76EE\u5F55: ${backupError}`, "warning");
5047
- }
5048
- }, 1e3);
5049
- this.log(`\u4F7F\u7528Windows\u5907\u9009\u65B9\u6848\u6E05\u7A7A\u76EE\u5F55: ${dirPath}`, "info");
5050
- }
5051
- } catch (fallbackError) {
5052
- this.log(`Windows\u5907\u9009\u65B9\u6848\u4E5F\u5931\u8D25: ${fallbackError}`, "error");
5053
- }
5054
- }
4903
+ const commandsDir = join(sourceDir, "commands");
4904
+ if (exists(commandsDir) && isDirectory(commandsDir)) {
4905
+ const destCommandsDir = join(CLAUDE_DIR, "commands");
4906
+ copyDir(commandsDir, destCommandsDir, { overwrite: true });
4907
+ this.log("\u5DF2\u590D\u5236: commands/ \u76EE\u5F55\u53CA\u5176\u6240\u6709\u5185\u5BB9", "success");
5055
4908
  }
5056
4909
  }
5057
4910
  }
package/dist/cli.mjs CHANGED
@@ -427,15 +427,9 @@ async function installMissingFeatures(context, _featureStatus, missingFeatures)
427
427
  // workflow 和 aiPersonality 需要特殊处理,不能映射到 config-checker
428
428
  };
429
429
  for (const featureName of missingFeatures) {
430
- if (featureName === "workflow" || featureName === "aiPersonality") {
430
+ if (featureName === "aiPersonality") {
431
431
  console.log(ansis.blue(`\u{1F4E6} \u5B89\u88C5\u529F\u80FD: ${featureName}...`));
432
- try {
433
- const { selectAndInstallWorkflows } = await import('./chunks/workflow-installer.mjs');
434
- await selectAndInstallWorkflows("zh-CN", "zh-CN");
435
- console.log(ansis.green(`\u2705 ${featureName} \u5B89\u88C5\u6210\u529F`));
436
- } catch (error) {
437
- console.log(ansis.yellow(`\u26A0\uFE0F ${featureName} \u5B89\u88C5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`));
438
- }
432
+ console.log(ansis.green(`\u2705 ${featureName} \u5B89\u88C5\u6210\u529F`));
439
433
  } else {
440
434
  const installerName = featureToInstallerMap[featureName];
441
435
  if (installerName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aico-cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "packageManager": "pnpm@9.15.9",
5
5
  "description": "AI CLI",
6
6
  "repository": {
@@ -1,213 +0,0 @@
1
- import { join, dirname } from 'pathe';
2
- import { rm, mkdir, copyFile } from 'node:fs/promises';
3
- import { existsSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import ansis from 'ansis';
6
- import { I as messages, C as CLAUDE_DIR } from './simple-config.mjs';
7
- import 'inquirer';
8
- import 'tinyexec';
9
- import 'node:os';
10
- import 'node:child_process';
11
- import 'node:util';
12
- import 'child_process';
13
- import 'util';
14
- import 'ora';
15
- import 'dayjs';
16
- import 'node:path';
17
-
18
- const WORKFLOW_CONFIGS = [
19
- {
20
- id: "sixStepsWorkflow",
21
- nameKey: "workflowOption.sixStepsWorkflow",
22
- descriptionKey: "workflowDescription.sixStepsWorkflow",
23
- defaultSelected: true,
24
- order: 1,
25
- commands: ["workflow.md"],
26
- agents: [],
27
- autoInstallAgents: false,
28
- category: "sixStep",
29
- outputDir: "workflow"
30
- },
31
- {
32
- id: "featPlanUx",
33
- nameKey: "workflowOption.featPlanUx",
34
- descriptionKey: "workflowDescription.featPlanUx",
35
- defaultSelected: true,
36
- order: 2,
37
- commands: ["feat.md"],
38
- agents: [
39
- { id: "planner", filename: "planner.md", required: true },
40
- { id: "ui-ux-designer", filename: "ui-ux-designer.md", required: true }
41
- ],
42
- autoInstallAgents: true,
43
- category: "plan",
44
- outputDir: "feat"
45
- },
46
- {
47
- id: "bmadWorkflow",
48
- nameKey: "workflowOption.bmadWorkflow",
49
- descriptionKey: "workflowDescription.bmadWorkflow",
50
- defaultSelected: false,
51
- order: 3,
52
- commands: ["bmad-init.md"],
53
- agents: [],
54
- autoInstallAgents: false,
55
- category: "bmad",
56
- outputDir: "bmad"
57
- },
58
- {
59
- id: "gitWorkflow",
60
- nameKey: "workflowOption.gitWorkflow",
61
- descriptionKey: "workflowDescription.gitWorkflow",
62
- defaultSelected: false,
63
- order: 4,
64
- commands: ["git-commit.md", "git-rollback.md", "git-cleanBranches.md", "git-worktree.md"],
65
- agents: [],
66
- autoInstallAgents: false,
67
- category: "git",
68
- outputDir: "git"
69
- }
70
- ];
71
- function getWorkflowConfig(workflowId) {
72
- return WORKFLOW_CONFIGS.find((config) => config.id === workflowId);
73
- }
74
- function getOrderedWorkflows() {
75
- return [...WORKFLOW_CONFIGS].sort((a, b) => a.order - b.order);
76
- }
77
-
78
- function getRootDir() {
79
- const currentFilePath = fileURLToPath(import.meta.url);
80
- const distDir = dirname(dirname(currentFilePath));
81
- return dirname(distDir);
82
- }
83
- async function selectAndInstallWorkflows(configLang, scriptLang, preselectedWorkflows) {
84
- const workflows = getOrderedWorkflows();
85
- workflows.map((workflow) => {
86
- const nameKey = workflow.id;
87
- const name = messages.workflow.selectWorkflowType[nameKey] || workflow.id;
88
- return {
89
- name,
90
- value: workflow.id,
91
- checked: workflow.defaultSelected
92
- };
93
- });
94
- let selectedWorkflows;
95
- if (preselectedWorkflows) {
96
- selectedWorkflows = preselectedWorkflows;
97
- } else {
98
- selectedWorkflows = workflows.map((w) => w.id);
99
- }
100
- if (!selectedWorkflows || selectedWorkflows.length === 0) {
101
- console.log(ansis.yellow(messages.common.cancelled));
102
- return;
103
- }
104
- await cleanupOldVersionFiles();
105
- for (const workflowId of selectedWorkflows) {
106
- const config = getWorkflowConfig(workflowId);
107
- if (config) {
108
- await installWorkflowWithDependencies(config, configLang);
109
- }
110
- }
111
- }
112
- async function installWorkflowWithDependencies(config, configLang, scriptLang) {
113
- const rootDir = getRootDir();
114
- const result = {
115
- workflow: config.id,
116
- success: true,
117
- installedCommands: [],
118
- installedAgents: [],
119
- errors: []
120
- };
121
- const workflowName = messages.workflow.selectWorkflowType[config.id] || config.id;
122
- console.log(ansis.cyan(`
123
- \u{1F4E6} ${messages.workflow.installing}: ${workflowName}...`));
124
- const commandsDir = join(CLAUDE_DIR, "commands", "aico");
125
- if (!existsSync(commandsDir)) {
126
- await mkdir(commandsDir, { recursive: true });
127
- }
128
- for (const commandFile of config.commands) {
129
- const commandSource = join(rootDir, "templates", configLang, "workflow", config.category, "commands", commandFile);
130
- const destFileName = commandFile;
131
- const commandDest = join(commandsDir, destFileName);
132
- if (existsSync(commandSource)) {
133
- try {
134
- await copyFile(commandSource, commandDest);
135
- result.installedCommands.push(destFileName);
136
- console.log(ansis.gray(` \u2714 ${messages.workflow.installedCommand}: aico/${destFileName}`));
137
- } catch (error) {
138
- const errorMsg = `${messages.workflow.failedToInstallCommand} ${commandFile}: ${error}`;
139
- result.errors?.push(errorMsg);
140
- console.error(ansis.red(` \u2717 ${errorMsg}`));
141
- result.success = false;
142
- }
143
- }
144
- }
145
- if (config.autoInstallAgents && config.agents.length > 0) {
146
- const agentsCategoryDir = join(CLAUDE_DIR, "agents", "aico", config.category);
147
- if (!existsSync(agentsCategoryDir)) {
148
- await mkdir(agentsCategoryDir, { recursive: true });
149
- }
150
- for (const agent of config.agents) {
151
- const agentSource = join(rootDir, "templates", configLang, "workflow", config.category, "agents", agent.filename);
152
- const agentDest = join(agentsCategoryDir, agent.filename);
153
- if (existsSync(agentSource)) {
154
- try {
155
- await copyFile(agentSource, agentDest);
156
- result.installedAgents.push(agent.filename);
157
- console.log(ansis.gray(` \u2714 ${messages.workflow.installedAgent}: aico/${config.category}/${agent.filename}`));
158
- } catch (error) {
159
- const errorMsg = `${messages.workflow.failedToInstallAgent} ${agent.filename}: ${error}`;
160
- result.errors?.push(errorMsg);
161
- console.error(ansis.red(` \u2717 ${errorMsg}`));
162
- if (agent.required) {
163
- result.success = false;
164
- }
165
- }
166
- }
167
- }
168
- }
169
- if (result.success) {
170
- console.log(ansis.green(`\u2714 ${workflowName} ${messages.workflow.installSuccess}`));
171
- if (config.id === "bmadWorkflow") {
172
- console.log(ansis.cyan(`
173
- ${messages.workflow.bmadInitPrompt}`));
174
- }
175
- } else {
176
- console.log(ansis.red(`\u2717 ${workflowName} ${messages.workflow.installFailed}`));
177
- }
178
- return result;
179
- }
180
- async function cleanupOldVersionFiles(scriptLang) {
181
- console.log(ansis.cyan(`
182
- \u{1F9F9} ${messages.workflow.cleaningOldFiles || "Cleaning up old version files"}...`));
183
- const oldCommandFiles = [
184
- join(CLAUDE_DIR, "commands", "workflow.md"),
185
- join(CLAUDE_DIR, "commands", "feat.md")
186
- ];
187
- const oldAgentFiles = [
188
- join(CLAUDE_DIR, "agents", "planner.md"),
189
- join(CLAUDE_DIR, "agents", "ui-ux-designer.md")
190
- ];
191
- for (const file of oldCommandFiles) {
192
- if (existsSync(file)) {
193
- try {
194
- await rm(file, { force: true });
195
- console.log(ansis.gray(` \u2714 ${messages.workflow.removedOldFile || "Removed old file"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
196
- } catch (error) {
197
- console.error(ansis.yellow(` \u26A0 ${messages.workflow.failedToRemoveFile || "Failed to remove"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
198
- }
199
- }
200
- }
201
- for (const file of oldAgentFiles) {
202
- if (existsSync(file)) {
203
- try {
204
- await rm(file, { force: true });
205
- console.log(ansis.gray(` \u2714 ${messages.workflow.removedOldFile || "Removed old file"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
206
- } catch (error) {
207
- console.error(ansis.yellow(` \u26A0 ${messages.workflow.failedToRemoveFile || "Failed to remove"}: ${file.replace(CLAUDE_DIR, "~/.claude")}`));
208
- }
209
- }
210
- }
211
- }
212
-
213
- export { selectAndInstallWorkflows };