aico-cli 0.5.0 → 2.0.25

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.
Files changed (72) hide show
  1. package/bin/cli/README.md +43 -0
  2. package/bin/cli/cli.js +3780 -0
  3. package/bin/cli/package.json +32 -0
  4. package/bin/cli/sdk-tools.d.ts +275 -0
  5. package/bin/cli/sdk.d.ts +446 -0
  6. package/bin/cli/sdk.mjs +14840 -0
  7. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/annotations-23.0.0.jar +0 -0
  8. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/claude-code-jetbrains-plugin-0.1.11-beta-searchableOptions.jar +0 -0
  9. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/claude-code-jetbrains-plugin-0.1.11-beta.jar +0 -0
  10. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/config-1.4.3.jar +0 -0
  11. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/jansi-2.4.1.jar +0 -0
  12. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlin-logging-jvm-7.0.0.jar +0 -0
  13. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlin-reflect-2.0.21.jar +0 -0
  14. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlin-sdk-jvm-0.4.0.jar +0 -0
  15. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlin-stdlib-2.1.20.jar +0 -0
  16. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlinx-coroutines-core-jvm-1.9.0.jar +0 -0
  17. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlinx-coroutines-slf4j-1.9.0.jar +0 -0
  18. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlinx-io-bytestring-jvm-0.5.4.jar +0 -0
  19. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlinx-io-core-jvm-0.5.4.jar +0 -0
  20. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlinx-serialization-core-jvm-1.8.1.jar +0 -0
  21. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/kotlinx-serialization-json-jvm-1.8.1.jar +0 -0
  22. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-client-cio-jvm-3.0.2.jar +0 -0
  23. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-client-core-jvm-3.0.2.jar +0 -0
  24. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-events-jvm-3.0.2.jar +0 -0
  25. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-http-cio-jvm-3.0.2.jar +0 -0
  26. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-http-jvm-3.0.2.jar +0 -0
  27. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-io-jvm-3.0.2.jar +0 -0
  28. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-network-jvm-3.0.2.jar +0 -0
  29. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-network-tls-jvm-3.0.2.jar +0 -0
  30. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-serialization-jvm-3.0.2.jar +0 -0
  31. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-server-cio-jvm-3.0.2.jar +0 -0
  32. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-server-core-jvm-3.0.2.jar +0 -0
  33. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-server-sse-jvm-3.0.2.jar +0 -0
  34. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-server-websockets-jvm-3.0.2.jar +0 -0
  35. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-sse-jvm-3.0.2.jar +0 -0
  36. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-utils-jvm-3.0.2.jar +0 -0
  37. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-websocket-serialization-jvm-3.0.2.jar +0 -0
  38. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/ktor-websockets-jvm-3.0.2.jar +0 -0
  39. package/bin/cli/vendor/claude-code-jetbrains-plugin/lib/slf4j-api-2.0.16.jar +0 -0
  40. package/bin/cli/vendor/ripgrep/COPYING +3 -0
  41. package/bin/cli/vendor/ripgrep/arm64-darwin/rg +0 -0
  42. package/bin/cli/vendor/ripgrep/arm64-darwin/ripgrep.node +0 -0
  43. package/bin/cli/vendor/ripgrep/arm64-linux/rg +0 -0
  44. package/bin/cli/vendor/ripgrep/arm64-linux/ripgrep.node +0 -0
  45. package/bin/cli/vendor/ripgrep/x64-darwin/rg +0 -0
  46. package/bin/cli/vendor/ripgrep/x64-darwin/ripgrep.node +0 -0
  47. package/bin/cli/vendor/ripgrep/x64-linux/rg +0 -0
  48. package/bin/cli/vendor/ripgrep/x64-linux/ripgrep.node +0 -0
  49. package/bin/cli/vendor/ripgrep/x64-win32/rg.exe +0 -0
  50. package/bin/cli/vendor/ripgrep/x64-win32/ripgrep.node +0 -0
  51. package/bin/cli/yoga.wasm +0 -0
  52. package/dist/chunks/run-command.mjs +1 -0
  53. package/dist/chunks/simple-config.mjs +60 -15
  54. package/dist/cli.mjs +202 -64
  55. package/dist/index.mjs +3 -52
  56. package/package.json +2 -1
  57. package/templates/agents/base/panel-experts.md +244 -0
  58. package/templates/agents/code/python/345/274/200/345/217/221/344/270/223/345/256/266.md +49 -0
  59. package/templates/agents/code//345/256/211/345/205/250/346/274/217/346/264/236/350/257/206/345/210/253/344/270/223/345/256/266.md +51 -0
  60. package/templates/agents/code//346/200/247/350/203/275/345/210/206/346/236/220/344/270/223/345/256/266.md +49 -0
  61. package/templates/agents/code//346/212/200/346/234/257/346/226/207/346/241/243/345/267/245/347/250/213/345/270/210.md +49 -0
  62. package/templates/agents/code//346/240/271/346/234/254/345/216/237/345/233/240/345/210/206/346/236/220/345/270/210.md +49 -0
  63. package/templates/agents/code//347/263/273/347/273/237/346/236/266/346/236/204/345/270/210.md +232 -0
  64. package/templates/agents/code//350/264/250/351/207/217/350/257/204/344/274/260/345/267/245/347/250/213/345/270/210.md +49 -0
  65. package/templates/commands/base//344/270/223/345/256/266/347/273/204/345/210/206/346/236/220/346/231/272/350/203/275/344/275/223.md +82 -0
  66. package/templates/cursor.md +87 -0
  67. package/templates/hooks/claude-code-hooks.json +0 -9
  68. package/templates/hooks/notify.ps1 +110 -24
  69. package/templates/hooks/scripts/Stop/powershell/session-summary.ps1 +108 -78
  70. package/templates/hooks/scripts/UserPromptSubmit/powershell/input-notifier.ps1 +67 -39
  71. package/templates/personality.md +1 -1
  72. package/templates/settings.json +3 -15
@@ -0,0 +1,3 @@
1
+ This project is dual-licensed under the Unlicense and MIT licenses.
2
+
3
+ You may use this code under the terms of either license.
Binary file
@@ -16,6 +16,7 @@ import 'node:path';
16
16
  import 'pathe';
17
17
  import 'node:url';
18
18
  import 'node:events';
19
+ import 'path';
19
20
 
20
21
  async function run(command) {
21
22
  try {
@@ -13,7 +13,7 @@ import { join as join$1 } from 'node:path';
13
13
  import { join, dirname, basename } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
 
16
- const version = "0.5.0";
16
+ const version = "2.0.25";
17
17
 
18
18
  function displayBanner(subtitle) {
19
19
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
@@ -3267,26 +3267,26 @@ const MCP_SERVICES = [
3267
3267
  }
3268
3268
  },
3269
3269
  {
3270
- id: "mcp-deepwiki",
3271
- name: "DeepWiki",
3272
- description: "\u67E5\u8BE2 GitHub \u4ED3\u5E93\u6587\u6863\u548C\u793A\u4F8B",
3270
+ id: "chrome-devtools",
3271
+ name: "Chrome DevTools",
3272
+ description: "Chrome \u5F00\u53D1\u8005\u5DE5\u5177 MCP \u670D\u52A1",
3273
3273
  requiresApiKey: false,
3274
3274
  config: {
3275
3275
  type: "stdio",
3276
3276
  command: "npx",
3277
- args: ["-y", "mcp-deepwiki@latest"],
3277
+ args: ["chrome-devtools-mcp@latest"],
3278
3278
  env: {}
3279
3279
  }
3280
3280
  },
3281
3281
  {
3282
- id: "chrome-devtools",
3283
- name: "Chrome DevTools",
3284
- description: "Chrome \u5F00\u53D1\u8005\u5DE5\u5177 MCP \u670D\u52A1",
3282
+ id: "sequential-thinking",
3283
+ name: "Sequential Thinking",
3284
+ description: "\u987A\u5E8F\u601D\u8003 MCP \u670D\u52A1",
3285
3285
  requiresApiKey: false,
3286
3286
  config: {
3287
3287
  type: "stdio",
3288
3288
  command: "npx",
3289
- args: ["chrome-devtools-mcp@latest"],
3289
+ args: ["-y", "sequential-thinking-mcp@latest"],
3290
3290
  env: {}
3291
3291
  }
3292
3292
  }
@@ -5284,7 +5284,8 @@ class InstallationComposer {
5284
5284
  }
5285
5285
  /**
5286
5286
  * 公司配置安装
5287
- * 包含:Claude Code + 固定API配置 + CCometixLine + MCP + Workflow
5287
+ * 包含:固定API配置 + CCometixLine + MCP + Workflow
5288
+ * Claude Code 由 startClaudeCodeEditor 函数自动安装
5288
5289
  * 公司配置不需要安装 CCR
5289
5290
  */
5290
5291
  async installCompanySetup(options = {}) {
@@ -5310,7 +5311,6 @@ class InstallationComposer {
5310
5311
  const configType = configCheckResult?.data?.configType;
5311
5312
  if (configType === "none" || options.force) {
5312
5313
  const companySteps = [
5313
- INSTALLER_NAMES.CLAUDE_CODE,
5314
5314
  INSTALLER_NAMES.CONFIG,
5315
5315
  INSTALLER_NAMES.CCOMETIX_LINE,
5316
5316
  INSTALLER_NAMES.MCP
@@ -5323,7 +5323,6 @@ class InstallationComposer {
5323
5323
  } else {
5324
5324
  console.log(ansis.yellow(`\u26A0 \u68C0\u6D4B\u5230${configType === "company" ? "\u516C\u53F8" : "\u4E2A\u4EBA"}\u914D\u7F6E\uFF0C\u5C06\u5F3A\u5236\u6267\u884C\u5B8C\u6574\u516C\u53F8\u914D\u7F6E`));
5325
5325
  const companySteps = [
5326
- INSTALLER_NAMES.CLAUDE_CODE,
5327
5326
  INSTALLER_NAMES.CONFIG,
5328
5327
  INSTALLER_NAMES.CCOMETIX_LINE,
5329
5328
  INSTALLER_NAMES.MCP
@@ -5337,12 +5336,12 @@ class InstallationComposer {
5337
5336
  }
5338
5337
  /**
5339
5338
  * 个人配置安装
5340
- * 包含:Claude Code + CCR + 配置备份应用 + CCometixLine + MCP + Workflow
5339
+ * 包含:CCR + 配置备份应用 + CCometixLine + MCP + Workflow
5340
+ * Claude Code 由 startClaudeCodeEditor 函数自动安装
5341
5341
  */
5342
5342
  async installPersonalSetup(options = {}) {
5343
5343
  console.log(ansis.cyan("\n\u{1F464} \u5F00\u59CB\u4E2A\u4EBA\u914D\u7F6E\u5B89\u88C5...\n"));
5344
5344
  const installationSteps = [
5345
- INSTALLER_NAMES.CLAUDE_CODE,
5346
5345
  INSTALLER_NAMES.CCR,
5347
5346
  INSTALLER_NAMES.CONFIG,
5348
5347
  INSTALLER_NAMES.CCOMETIX_LINE,
@@ -5492,6 +5491,52 @@ const init$1 = {
5492
5491
  init: init
5493
5492
  };
5494
5493
 
5494
+ async function isClaudeCodeInstalled() {
5495
+ return await commandExists("claude");
5496
+ }
5497
+ async function installClaudeCode(lang) {
5498
+ getTranslation(lang);
5499
+ if (isTermux()) {
5500
+ console.log(ansis.yellow(`\u2139 ${messages.installation.termuxDetected}`));
5501
+ const termuxPrefix = getTermuxPrefix();
5502
+ console.log(ansis.gray(messages.installation.termuxPathInfo.replace("{path}", termuxPrefix)));
5503
+ console.log(ansis.gray(`Node.js: ${termuxPrefix}/bin/node`));
5504
+ console.log(ansis.gray(`npm: ${termuxPrefix}/bin/npm`));
5505
+ }
5506
+ console.log(messages.installation.installing);
5507
+ try {
5508
+ await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
5509
+ console.log(`\u2714 ${messages.installation.installSuccess}`);
5510
+ if (isTermux()) {
5511
+ console.log(ansis.gray(`
5512
+ Claude Code installed to: ${getTermuxPrefix()}/bin/claude`));
5513
+ }
5514
+ } catch (error) {
5515
+ console.error(`\u2716 ${messages.installation.installFailed}`);
5516
+ if (isTermux()) {
5517
+ console.error(ansis.yellow(`
5518
+ ${messages.installation.termuxInstallHint}
5519
+ `));
5520
+ }
5521
+ throw error;
5522
+ }
5523
+ }
5524
+ async function installClaudeCodeSilently() {
5525
+ const installed = await isClaudeCodeInstalled();
5526
+ if (installed) {
5527
+ console.log(ansis.green("\u2714 \u5DF2\u5B89\u88C5 Claude Code"));
5528
+ return;
5529
+ }
5530
+ console.log("\u6B63\u5728\u5B89\u88C5 Claude Code...");
5531
+ try {
5532
+ await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
5533
+ console.log(ansis.green("\u2714 Claude Code \u5B89\u88C5\u6210\u529F"));
5534
+ } catch (error) {
5535
+ console.error(ansis.red("\u2716 Claude Code \u5B89\u88C5\u5931\u8D25"));
5536
+ throw error;
5537
+ }
5538
+ }
5539
+
5495
5540
  const __dirname = dirname(fileURLToPath(import.meta.url));
5496
5541
  function getTemplateSettings() {
5497
5542
  const templatePath = join(__dirname, "../../templates/settings.json");
@@ -5570,4 +5615,4 @@ async function openSettingsJson() {
5570
5615
  }
5571
5616
  }
5572
5617
 
5573
- export { 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, addCompletedOnboarding as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, createEscapablePrompt as N, displayBannerWithInfo as O, executeWithEscapeSupport as P, handleExitPromptError as Q, handleGeneralError as R, SETTINGS_FILE as S, EscapeKeyPressed as T, displayBanner as U, ConfigCheckerInstaller as V, updateAicoConfig as W, version as X, InstallationComposer as Y, readAicoConfig as Z, init$1 as _, init as a, getPlatform as b, commandExists as c, importRecommendedEnv as d, importRecommendedPermissions as e, cleanupPermissions as f, getTermuxPrefix as g, mergeAndCleanPermissions as h, isTermux as i, CLAUDE_MD_FILE as j, ClAUDE_CONFIG_FILE as k, SUPPORTED_LANGS as l, messages as m, LANG_LABELS as n, openSettingsJson as o, AI_OUTPUT_LANGUAGES 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 };
5618
+ export { 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, addCompletedOnboarding as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, createEscapablePrompt as N, displayBannerWithInfo as O, executeWithEscapeSupport as P, handleExitPromptError as Q, handleGeneralError as R, SETTINGS_FILE as S, EscapeKeyPressed as T, displayBanner as U, ConfigCheckerInstaller as V, updateAicoConfig as W, version as X, InstallationComposer as Y, readAicoConfig as Z, init$1 as _, importRecommendedEnv as a, 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 };
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 { N as createEscapablePrompt, O as displayBannerWithInfo, a as init, P as executeWithEscapeSupport, Q as handleExitPromptError, R as handleGeneralError, T as EscapeKeyPressed, U as displayBanner, V as ConfigCheckerInstaller, W as updateAicoConfig, X as version, Y as InstallationComposer, Z as readAicoConfig } from './chunks/simple-config.mjs';
4
+ import { N as createEscapablePrompt, l as isClaudeCodeInstalled, n as installClaudeCode, O as displayBannerWithInfo, i as init, P as executeWithEscapeSupport, Q as handleExitPromptError, R as handleGeneralError, T as EscapeKeyPressed, U as displayBanner, V as ConfigCheckerInstaller, W as updateAicoConfig, X as version, Y as InstallationComposer, Z as readAicoConfig } from './chunks/simple-config.mjs';
5
5
  import inquirer$1 from 'inquirer';
6
6
  import { spawn, exec as exec$1 } from 'node:child_process';
7
7
  import { EventEmitter } from 'node:events';
@@ -13,6 +13,7 @@ import 'node:path';
13
13
  import { exec } from 'child_process';
14
14
  import { promisify } from 'util';
15
15
  import { promisify as promisify$1 } from 'node:util';
16
+ import path from 'path';
16
17
  import 'ora';
17
18
  import 'dayjs';
18
19
  import 'node:url';
@@ -175,10 +176,7 @@ class ProcessManager extends EventEmitter {
175
176
  unregisterProcess(pid) {
176
177
  const info = this.processes.get(pid);
177
178
  if (info) {
178
- this.log(`\u6CE8\u9500\u8FDB\u7A0B: ${info.name} (PID: ${pid})`, "info");
179
179
  this.processes.delete(pid);
180
- } else {
181
- this.log(`\u5C1D\u8BD5\u6CE8\u9500\u4E0D\u5B58\u5728\u7684\u8FDB\u7A0B (PID: ${pid})`, "warning");
182
180
  }
183
181
  }
184
182
  /**
@@ -201,60 +199,83 @@ class ProcessManager extends EventEmitter {
201
199
  this.log("\u7528\u6237\u8BF7\u6C42\u5F3A\u5236\u5173\u95ED\uFF0C\u7ACB\u5373\u7EC8\u6B62\u6240\u6709\u8FDB\u7A0B...", "warning");
202
200
  };
203
201
  process.once("SIGINT", forceShutdownHandler);
204
- let runningProcesses = Array.from(this.processes.values()).filter((p) => p.status === "running");
205
- if (runningProcesses.length > 0) {
206
- this.log(`\u5411 ${runningProcesses.length} \u4E2A\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\u53D1\u9001SIGTERM\u4FE1\u53F7...`, "info");
207
- for (const info of runningProcesses) {
208
- try {
209
- info.process.kill("SIGTERM");
210
- info.status = "killed";
211
- } catch (error) {
212
- this.log(`\u65E0\u6CD5\u7EC8\u6B62\u8FDB\u7A0B ${info.name} (PID: ${info.pid}): ${error}`, "error");
202
+ try {
203
+ let runningProcesses = Array.from(this.processes.values()).filter((p) => p.status === "running");
204
+ if (runningProcesses.length > 0) {
205
+ for (const info of runningProcesses) {
206
+ try {
207
+ info.process.kill("SIGTERM");
208
+ info.status = "killed";
209
+ } catch (error) {
210
+ this.log(`\u65E0\u6CD5\u7EC8\u6B62\u8FDB\u7A0B ${info.name} (PID: ${info.pid}): ${error}`, "error");
211
+ }
213
212
  }
214
- }
215
- const maxWaitTime = 1e3;
216
- const checkInterval = 100;
217
- let waitedTime = 0;
218
- while (waitedTime < maxWaitTime && !forceShutdownRequested) {
219
- await new Promise((resolve) => setTimeout(resolve, checkInterval));
220
- waitedTime += checkInterval;
221
- runningProcesses = Array.from(this.processes.values()).filter((p) => p.status === "running");
222
- if (runningProcesses.length === 0) {
223
- break;
213
+ const maxWaitTime = 1e3;
214
+ const checkInterval = 100;
215
+ let waitedTime = 0;
216
+ while (waitedTime < maxWaitTime && !forceShutdownRequested) {
217
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
218
+ waitedTime += checkInterval;
219
+ runningProcesses = Array.from(this.processes.values()).filter((p) => p.status === "running");
220
+ if (runningProcesses.length === 0) {
221
+ break;
222
+ }
224
223
  }
225
224
  }
226
- }
227
- process.removeListener("SIGINT", forceShutdownHandler);
228
- runningProcesses = Array.from(this.processes.values()).filter((p) => p.status === "running");
229
- if (runningProcesses.length > 0) {
230
- this.log(`\u5F3A\u5236\u7EC8\u6B62 ${runningProcesses.length} \u4E2A\u4ECD\u5728\u8FD0\u884C\u7684\u8FDB\u7A0B...`, "warning");
231
- for (const info of runningProcesses) {
232
- try {
233
- info.process.kill("SIGKILL");
234
- this.log(`\u5F3A\u5236\u7EC8\u6B62\u8FDB\u7A0B ${info.name} (PID: ${info.pid})`, "warning");
235
- } catch (error) {
236
- this.log(`\u65E0\u6CD5\u5F3A\u5236\u7EC8\u6B62\u8FDB\u7A0B ${info.name} (PID: ${info.pid}): ${error}`, "error");
225
+ process.removeListener("SIGINT", forceShutdownHandler);
226
+ runningProcesses = Array.from(this.processes.values()).filter((p) => p.status === "running");
227
+ if (runningProcesses.length > 0) {
228
+ this.log(`\u5F3A\u5236\u7EC8\u6B62 ${runningProcesses.length} \u4E2A\u4ECD\u5728\u8FD0\u884C\u7684\u8FDB\u7A0B...`, "warning");
229
+ for (const info of runningProcesses) {
230
+ try {
231
+ info.process.kill("SIGKILL");
232
+ this.log(`\u5F3A\u5236\u7EC8\u6B62\u8FDB\u7A0B ${info.name} (PID: ${info.pid})`, "warning");
233
+ } catch (error) {
234
+ this.log(`\u65E0\u6CD5\u5F3A\u5236\u7EC8\u6B62\u8FDB\u7A0B ${info.name} (PID: ${info.pid}): ${error}`, "error");
235
+ }
237
236
  }
238
237
  }
238
+ const totalTime = Date.now() - firstSignalTime;
239
+ this.log(`\u5173\u95ED\u5B8C\u6210\uFF0C\u8017\u65F6 ${totalTime}ms`, "success");
240
+ } catch (error) {
241
+ this.log(`\u5173\u95ED\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF: ${error}`, "error");
242
+ } finally {
243
+ this.cleanup();
244
+ setTimeout(() => {
245
+ process.exit(0);
246
+ }, 100);
239
247
  }
240
- const totalTime = Date.now() - firstSignalTime;
241
- this.log(`\u5173\u95ED\u5B8C\u6210\uFF0C\u8017\u65F6 ${totalTime}ms`, "success");
242
- this.cleanup();
243
- process.exit(0);
244
248
  }
245
249
  /**
246
250
  * 清理所有进程
247
251
  */
248
252
  cleanup() {
249
- for (const [pid, info] of this.processes) {
250
- if (info.status === "running") {
251
- try {
252
- info.process.kill("SIGKILL");
253
- } catch {
253
+ try {
254
+ let cleanedCount = 0;
255
+ for (const [pid, info] of this.processes) {
256
+ if (info.status === "running") {
257
+ try {
258
+ if (info.process.kill("SIGTERM")) {
259
+ this.log(`\u5DF2\u53D1\u9001 SIGTERM \u4FE1\u53F7\u7ED9\u8FDB\u7A0B ${info.name} (PID: ${pid})`, "info");
260
+ cleanedCount++;
261
+ }
262
+ } catch (error) {
263
+ this.log(`\u53D1\u9001 SIGTERM \u4FE1\u53F7\u7ED9\u8FDB\u7A0B ${info.name} (PID: ${pid}) \u5931\u8D25: ${error}`, "warning");
264
+ try {
265
+ if (info.process.kill("SIGKILL")) {
266
+ this.log(`\u5DF2\u53D1\u9001 SIGKILL \u4FE1\u53F7\u7ED9\u8FDB\u7A0B ${info.name} (PID: ${pid})`, "warning");
267
+ cleanedCount++;
268
+ }
269
+ } catch (killError) {
270
+ this.log(`\u53D1\u9001 SIGKILL \u4FE1\u53F7\u7ED9\u8FDB\u7A0B ${info.name} (PID: ${pid}) \u5931\u8D25: ${killError}`, "error");
271
+ }
272
+ }
254
273
  }
255
274
  }
275
+ this.processes.clear();
276
+ } catch (error) {
277
+ this.log(`\u8FDB\u7A0B\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF: ${error}`, "error");
256
278
  }
257
- this.processes.clear();
258
279
  }
259
280
  /**
260
281
  * 获取当前运行的进程数量
@@ -531,6 +552,81 @@ promisify$1(exec$1);
531
552
 
532
553
  promisify$1(exec$1);
533
554
 
555
+ async function checkLocalClaudeCode() {
556
+ try {
557
+ const fs = await import('fs');
558
+ const localClaudePath = path.resolve(process.cwd(), "bin/cli/cli.js");
559
+ if (fs.existsSync(localClaudePath)) {
560
+ const stats = fs.statSync(localClaudePath);
561
+ return {
562
+ exists: true,
563
+ path: localClaudePath,
564
+ size: stats.size
565
+ };
566
+ }
567
+ return {
568
+ exists: false,
569
+ path: localClaudePath
570
+ };
571
+ } catch (error) {
572
+ return {
573
+ exists: false,
574
+ path: path.resolve(process.cwd(), "bin/cli/cli.js"),
575
+ error: error instanceof Error ? error.message : String(error)
576
+ };
577
+ }
578
+ }
579
+ async function checkGlobalClaudeCode() {
580
+ try {
581
+ const isWindows = process.platform === "win32";
582
+ const command = isWindows ? "claude.cmd" : "claude";
583
+ const { spawnSync } = await import('child_process');
584
+ const whichCommand = isWindows ? "where" : "which";
585
+ const result = spawnSync(whichCommand, [command], {
586
+ stdio: "pipe",
587
+ timeout: 5e3
588
+ // 5秒超时
589
+ });
590
+ if (result.status === 0 && result.stdout) {
591
+ const output = result.stdout.toString().trim();
592
+ return {
593
+ installed: true,
594
+ command: output.split("\n")[0]
595
+ // 返回第一个匹配的路径
596
+ };
597
+ }
598
+ return {
599
+ installed: false,
600
+ error: result.stderr?.toString() || "\u547D\u4EE4\u672A\u627E\u5230"
601
+ };
602
+ } catch (error) {
603
+ return {
604
+ installed: false,
605
+ error: error instanceof Error ? error.message : String(error)
606
+ };
607
+ }
608
+ }
609
+ async function performHealthCheck() {
610
+ const localCheck = await checkLocalClaudeCode();
611
+ if (localCheck.exists) {
612
+ console.log(ansis.green(`\u2705 \u68C0\u6D4B\u5230\u7F16\u8F91\u5668`));
613
+ } else {
614
+ console.log(ansis.yellow(`\u26A0\uFE0F \u6CA1\u6709\u68C0\u6D4B\u5230\u7F16\u8F91\u5668: ${localCheck.path}`));
615
+ if (localCheck.error) {
616
+ console.log(ansis.gray(` \u9519\u8BEF\u8BE6\u60C5: ${localCheck.error}`));
617
+ }
618
+ }
619
+ const globalCheck = await checkGlobalClaudeCode();
620
+ if (globalCheck.installed) {
621
+ console.log(ansis.green(`\u{1F680} \u542F\u52A8\u7F16\u8F91\u5668`));
622
+ } else {
623
+ console.log(ansis.yellow("\u26A0\uFE0F \u5168\u5C40 Claude Code \u672A\u5B89\u88C5"));
624
+ if (globalCheck.error) {
625
+ console.log(ansis.gray(` \u9519\u8BEF\u8BE6\u60C5: ${globalCheck.error}`));
626
+ }
627
+ }
628
+ }
629
+
534
630
  async function tryStartClaude(command, args, options) {
535
631
  process.platform === "win32";
536
632
  const spawnOptions = {
@@ -545,6 +641,7 @@ async function tryStartClaude(command, args, options) {
545
641
  async function startClaudeCodeEditor(_lang) {
546
642
  try {
547
643
  console.log(ansis.cyan("\u{1F680} \u6B63\u5728\u542F\u52A8\u4EE3\u7801\u7F16\u8F91\u5668..."));
644
+ await performHealthCheck();
548
645
  const isWindows = process.platform === "win32";
549
646
  const spawnOptions = {
550
647
  stdio: "inherit",
@@ -555,56 +652,97 @@ async function startClaudeCodeEditor(_lang) {
555
652
  // 禁用shell模式,避免进程泄漏(Windows和Unix都适用)
556
653
  };
557
654
  try {
558
- const command = isWindows ? "claude.cmd" : "claude";
559
- const args = [];
560
- if (isWindows) {
561
- await tryStartClaude(command, args, spawnOptions);
562
- } else {
563
- await tryStartClaude(command, args, spawnOptions);
655
+ const localCheck = await checkLocalClaudeCode();
656
+ if (!localCheck.exists) {
657
+ throw new Error(`\u672C\u5730 aico\u8FD0\u884C\u547D\u4EE4 \u6587\u4EF6\u4E0D\u5B58\u5728: ${localCheck.path}${localCheck.error ? ` (${localCheck.error})` : ""}`);
564
658
  }
659
+ const command = isWindows ? "node.exe" : "node";
660
+ const args = [localCheck.path];
661
+ await tryStartClaude(command, args, spawnOptions);
565
662
  return;
566
- } catch (firstError) {
567
- if (firstError.code === "ENOENT") {
568
- console.log(ansis.yellow("\u26A0\uFE0F \u76F4\u63A5\u8C03\u7528 claude \u5931\u8D25\uFF0C\u5C1D\u8BD5\u4F7F\u7528 npx..."));
663
+ } catch (localError) {
664
+ console.log(ansis.yellow("\u{1F4A1} \u5C1D\u8BD5\u81EA\u52A8\u5B89\u88C5\u5E76\u542F\u52A8..."));
665
+ try {
666
+ const installed = await isClaudeCodeInstalled();
667
+ if (!installed) {
668
+ console.log(ansis.cyan("\u{1F4E6} \u68C0\u6D4B\u5230 Claude Code \u672A\u5B89\u88C5\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5..."));
669
+ await installClaudeCode(_lang || "zh-CN");
670
+ console.log(ansis.green("\u2705 Claude Code \u5B89\u88C5\u5B8C\u6210"));
671
+ }
672
+ const command = isWindows ? "claude.cmd" : "claude";
673
+ const args = [];
674
+ console.log(ansis.gray(`\u{1F527} \u4F7F\u7528\u5168\u5C40\u547D\u4EE4: ${command}`));
675
+ if (isWindows) {
676
+ await tryStartClaude(command, args, spawnOptions);
677
+ } else {
678
+ await tryStartClaude(command, args, spawnOptions);
679
+ }
680
+ return;
681
+ } catch (installError) {
682
+ console.log(ansis.yellow("\u26A0\uFE0F \u5B89\u88C5\u540E\u542F\u52A8\u5931\u8D25: "), ansis.gray(installError.message));
683
+ console.log(ansis.yellow("\u{1F4A1} \u5C1D\u8BD5\u4F7F\u7528 npx \u542F\u52A8..."));
569
684
  try {
570
685
  const npxArgs = ["@anthropic-ai/claude-code"];
686
+ console.log(ansis.gray(`\u{1F527} \u4F7F\u7528 npx \u547D\u4EE4: npx ${npxArgs.join(" ")}`));
571
687
  if (isWindows) {
572
688
  await tryStartClaude("npx.cmd", npxArgs, spawnOptions);
573
689
  } else {
574
690
  await tryStartClaude("npx", npxArgs, spawnOptions);
575
691
  }
576
692
  return;
577
- } catch (secondError) {
578
- throw firstError;
693
+ } catch (npxError) {
694
+ console.log(ansis.yellow("\u26A0\uFE0F npx \u542F\u52A8\u4E5F\u5931\u8D25: "), ansis.gray(npxError.message));
695
+ throw new Error(`\u6240\u6709\u542F\u52A8\u65B9\u5F0F\u5747\u5931\u8D25:
696
+ - \u672C\u5730\u542F\u52A8: ${localError.message}
697
+ - \u5168\u5C40\u542F\u52A8: ${installError.message || "\u8DF3\u8FC7"}
698
+ - npx\u542F\u52A8: ${npxError.message}`);
579
699
  }
580
- } else {
581
- throw firstError;
582
700
  }
583
701
  }
584
702
  } catch (error) {
585
703
  console.error(ansis.red("\u274C \u542F\u52A8\u4EE3\u7801\u7F16\u8F91\u5668\u5931\u8D25:"));
586
704
  const isWindows = process.platform === "win32";
705
+ console.error(ansis.yellow("\u{1F4CB} \u8BE6\u7EC6\u8BCA\u65AD\u4FE1\u606F:"));
706
+ console.error(ansis.gray(` \u9519\u8BEF\u7C7B\u578B: ${error.name || "Unknown"}`));
707
+ console.error(ansis.gray(` \u9519\u8BEF\u4EE3\u7801: ${error.code || "\u65E0"}`));
708
+ console.error(ansis.gray(` \u9519\u8BEF\u6D88\u606F: ${error.message || error}`));
709
+ console.error(ansis.gray(` \u5F53\u524D\u76EE\u5F55: ${process.cwd()}`));
710
+ console.error(ansis.gray(` \u64CD\u4F5C\u7CFB\u7EDF: ${process.platform}`));
711
+ console.error(ansis.gray(` Node.js \u7248\u672C: ${process.version}`));
712
+ console.error(ansis.gray(` \u5185\u5B58\u4F7F\u7528: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB`));
587
713
  if (error.code === "ENOENT" || error.message?.includes("command not found") || error.message?.includes("ENOENT")) {
588
- console.error(ansis.yellow("\u{1F4A1} \u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 Claude Code:"));
589
- console.error(ansis.gray(" npm install -g @anthropic-ai/claude-code"));
714
+ console.error(ansis.yellow("\u{1F4A1} \u53EF\u80FD\u7684\u539F\u56E0:"));
715
+ console.error(ansis.gray(" 1. \u672C\u5730 Claude Code \u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u8DEF\u5F84\u9519\u8BEF"));
716
+ console.error(ansis.gray(" 2. \u81EA\u52A8\u5B89\u88C5 Claude Code \u5931\u8D25"));
717
+ console.error(ansis.gray(" 3. Node.js \u73AF\u5883\u95EE\u9898"));
718
+ console.error(ansis.gray(" 4. PATH \u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u95EE\u9898"));
719
+ console.error(ansis.yellow("\u{1F4A1} \u89E3\u51B3\u65B9\u6848:"));
720
+ console.error(ansis.gray(" - \u786E\u4FDD\u9879\u76EE\u5DF2\u6B63\u786E\u6784\u5EFA\uFF0Cbin/cli/cli.js \u6587\u4EF6\u5B58\u5728"));
721
+ console.error(ansis.gray(" - \u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\uFF0C\u786E\u4FDD\u53EF\u4EE5\u8BBF\u95EE npm \u4ED3\u5E93"));
722
+ console.error(ansis.gray(" - \u624B\u52A8\u5B89\u88C5: npm install -g @anthropic-ai/claude-code"));
723
+ console.error(ansis.gray(" - \u68C0\u67E5 Node.js \u548C npm \u7248\u672C\u517C\u5BB9\u6027"));
590
724
  if (isWindows) {
591
725
  console.error(ansis.yellow("\u{1F4A1} Windows \u7528\u6237\u989D\u5916\u63D0\u793A:"));
592
726
  console.error(ansis.gray(" 1. \u91CD\u542F\u547D\u4EE4\u884C\u7A97\u53E3\u4EE5\u5237\u65B0 PATH \u73AF\u5883\u53D8\u91CF"));
593
727
  console.error(ansis.gray(" 2. \u786E\u8BA4 npm \u5168\u5C40\u5B89\u88C5\u8DEF\u5F84\u5728 PATH \u4E2D"));
594
728
  console.error(ansis.gray(" 3. \u5C1D\u8BD5\u4F7F\u7528 npx.cmd @anthropic-ai/claude-code --dangerously-skip-permissions"));
595
729
  console.error(ansis.gray(" 4. \u68C0\u67E5\u662F\u5426\u5B89\u88C5\u4E86 Node.js \u548C npm"));
730
+ console.error(ansis.gray(" 5. \u5C1D\u8BD5\u4EE5\u7BA1\u7406\u5458\u6743\u9650\u8FD0\u884C"));
596
731
  }
597
732
  } else if (error.message?.includes("spawn") || error.message?.includes("\u8FDB\u7A0B")) {
598
733
  console.error(ansis.yellow("\u{1F4A1} \u8FDB\u7A0B\u542F\u52A8\u5931\u8D25\uFF0C\u53EF\u80FD\u662F\u8FDB\u7A0B\u7BA1\u7406\u95EE\u9898:"));
599
734
  console.error(ansis.gray(" 1. \u68C0\u67E5\u7CFB\u7EDF\u662F\u5426\u6709\u8DB3\u591F\u7684\u8D44\u6E90"));
600
735
  console.error(ansis.gray(" 2. \u5C1D\u8BD5\u5173\u95ED\u5176\u4ED6\u5E94\u7528\u7A0B\u5E8F\u91CA\u653E\u5185\u5B58"));
736
+ console.error(ansis.gray(" 3. \u68C0\u67E5\u8FDB\u7A0B\u7BA1\u7406\u5668\u72B6\u6001"));
601
737
  if (isWindows) {
602
- console.error(ansis.gray(" 3. Windows\u7528\u6237: \u5C1D\u8BD5\u4EE5\u7BA1\u7406\u5458\u6743\u9650\u8FD0\u884C"));
603
- console.error(ansis.gray(" 4. Windows\u7528\u6237: \u68C0\u67E5\u9632\u75C5\u6BD2\u8F6F\u4EF6\u662F\u5426\u963B\u6B62\u4E86\u8FDB\u7A0B\u542F\u52A8"));
738
+ console.error(ansis.gray(" 4. Windows\u7528\u6237: \u5C1D\u8BD5\u4EE5\u7BA1\u7406\u5458\u6743\u9650\u8FD0\u884C"));
739
+ console.error(ansis.gray(" 5. Windows\u7528\u6237: \u68C0\u67E5\u9632\u75C5\u6BD2\u8F6F\u4EF6\u662F\u5426\u963B\u6B62\u4E86\u8FDB\u7A0B\u542F\u52A8"));
604
740
  }
605
741
  } else {
606
- console.error(ansis.gray(` \u9519\u8BEF\u4FE1\u606F: ${error.message || error}`));
607
- console.error(ansis.gray(` \u9519\u8BEF\u4EE3\u7801: ${error.code || "\u65E0"}`));
742
+ console.error(ansis.yellow("\u{1F4A1} \u672A\u77E5\u9519\u8BEF\u7C7B\u578B\uFF0C\u8BF7\u68C0\u67E5\u4EE5\u4E0B\u5185\u5BB9:"));
743
+ console.error(ansis.gray(" 1. \u67E5\u770B\u5B8C\u6574\u7684\u9519\u8BEF\u5806\u6808\u4FE1\u606F"));
744
+ console.error(ansis.gray(" 2. \u68C0\u67E5\u7CFB\u7EDF\u65E5\u5FD7"));
745
+ console.error(ansis.gray(" 3. \u5C1D\u8BD5\u91CD\u542F\u7CFB\u7EDF"));
608
746
  }
609
747
  try {
610
748
  const processCount = processManager.getProcessCount();
@@ -639,7 +777,7 @@ function createDefaultContext() {
639
777
  };
640
778
  }
641
779
  async function launchCodeEditor() {
642
- return startClaudeCodeEditor();
780
+ return startClaudeCodeEditor("zh-CN");
643
781
  }
644
782
  async function launchCUI() {
645
783
  try {