aico-cli 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/feature-checker.mjs +117 -0
- package/dist/chunks/simple-config.mjs +4 -5
- package/dist/cli.mjs +21 -12
- package/dist/index.mjs +4 -52
- package/dist/shared/aico-cli.C9hv-Gol.mjs +51 -0
- package/package.json +1 -1
- package/templates/agents/aico/requirement/aico-requirement-aligner.md +1 -1
- package/templates/agents/aico/requirement/aico-requirement-identifier.md +1 -1
- package/templates/personality.md +73 -21
- package/templates/settings.json +1 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'pathe';
|
|
3
|
+
import { S as SETTINGS_FILE, G as readJsonConfig, C as CLAUDE_DIR } from './simple-config.mjs';
|
|
4
|
+
import { i as isClaudeCodeInstalled } from '../shared/aico-cli.C9hv-Gol.mjs';
|
|
5
|
+
import 'ansis';
|
|
6
|
+
import 'inquirer';
|
|
7
|
+
import 'tinyexec';
|
|
8
|
+
import 'node:os';
|
|
9
|
+
import 'node:child_process';
|
|
10
|
+
import 'node:util';
|
|
11
|
+
import 'child_process';
|
|
12
|
+
import 'util';
|
|
13
|
+
import 'ora';
|
|
14
|
+
import 'dayjs';
|
|
15
|
+
import 'node:path';
|
|
16
|
+
import 'node:url';
|
|
17
|
+
|
|
18
|
+
async function checkAllFeatures(context) {
|
|
19
|
+
const results = {};
|
|
20
|
+
results.config = await checkConfigFeature();
|
|
21
|
+
results.claudeCode = await checkClaudeCodeFeature();
|
|
22
|
+
results.workflow = await checkWorkflowFeature();
|
|
23
|
+
results.statusBar = await checkStatusBarFeature();
|
|
24
|
+
results.aiPersonality = await checkAiPersonalityFeature();
|
|
25
|
+
return results;
|
|
26
|
+
}
|
|
27
|
+
async function checkConfigFeature() {
|
|
28
|
+
try {
|
|
29
|
+
const settingsExists = existsSync(SETTINGS_FILE);
|
|
30
|
+
if (!settingsExists) {
|
|
31
|
+
return { isInstalled: false, details: "settings.json \u4E0D\u5B58\u5728" };
|
|
32
|
+
}
|
|
33
|
+
const settings = await readJsonConfig(SETTINGS_FILE);
|
|
34
|
+
const hasBaseUrl = !!settings?.env?.ANTHROPIC_BASE_URL;
|
|
35
|
+
return {
|
|
36
|
+
isInstalled: hasBaseUrl,
|
|
37
|
+
details: hasBaseUrl ? "API \u914D\u7F6E\u6B63\u5E38" : "\u7F3A\u5C11 ANTHROPIC_BASE_URL \u914D\u7F6E"
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
isInstalled: false,
|
|
42
|
+
details: `\u914D\u7F6E\u68C0\u67E5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function checkClaudeCodeFeature() {
|
|
47
|
+
try {
|
|
48
|
+
const installed = await isClaudeCodeInstalled();
|
|
49
|
+
return {
|
|
50
|
+
isInstalled: installed,
|
|
51
|
+
details: installed ? "Claude Code \u5DF2\u5B89\u88C5" : "Claude Code \u672A\u5B89\u88C5"
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
return {
|
|
55
|
+
isInstalled: false,
|
|
56
|
+
details: `Claude Code \u68C0\u67E5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function checkWorkflowFeature() {
|
|
61
|
+
try {
|
|
62
|
+
const workflowDir = join(CLAUDE_DIR, "agents");
|
|
63
|
+
const workflowExists = existsSync(workflowDir);
|
|
64
|
+
if (!workflowExists) {
|
|
65
|
+
return { isInstalled: false, details: "\u5DE5\u4F5C\u6D41\u76EE\u5F55\u4E0D\u5B58\u5728" };
|
|
66
|
+
}
|
|
67
|
+
const hasWorkflowFiles = existsSync(join(workflowDir, "aico")) || existsSync(join(workflowDir, "commands"));
|
|
68
|
+
return {
|
|
69
|
+
isInstalled: hasWorkflowFiles,
|
|
70
|
+
details: hasWorkflowFiles ? "\u5DE5\u4F5C\u6D41\u6587\u4EF6\u5DF2\u5B89\u88C5" : "\u5DE5\u4F5C\u6D41\u76EE\u5F55\u4E3A\u7A7A"
|
|
71
|
+
};
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
isInstalled: false,
|
|
75
|
+
details: `\u5DE5\u4F5C\u6D41\u68C0\u67E5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function checkStatusBarFeature() {
|
|
80
|
+
try {
|
|
81
|
+
const statusBarDir = join(CLAUDE_DIR, "ccline");
|
|
82
|
+
const statusBarExists = existsSync(statusBarDir);
|
|
83
|
+
return {
|
|
84
|
+
isInstalled: statusBarExists,
|
|
85
|
+
details: statusBarExists ? "\u72B6\u6001\u680F\u5DF2\u914D\u7F6E" : "\u72B6\u6001\u680F\u672A\u914D\u7F6E"
|
|
86
|
+
};
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
isInstalled: false,
|
|
90
|
+
details: `\u72B6\u6001\u680F\u68C0\u67E5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function checkAiPersonalityFeature() {
|
|
95
|
+
try {
|
|
96
|
+
const requiredFiles = [
|
|
97
|
+
"personality.md",
|
|
98
|
+
"base.md",
|
|
99
|
+
"language.md",
|
|
100
|
+
"CLAUDE.md"
|
|
101
|
+
];
|
|
102
|
+
const missingFiles = requiredFiles.filter(
|
|
103
|
+
(file) => !existsSync(join(CLAUDE_DIR, file))
|
|
104
|
+
);
|
|
105
|
+
return {
|
|
106
|
+
isInstalled: missingFiles.length === 0,
|
|
107
|
+
details: missingFiles.length === 0 ? "AI \u4E2A\u6027\u6587\u4EF6\u5B8C\u6574" : `\u7F3A\u5931\u6587\u4EF6: ${missingFiles.join(", ")}`
|
|
108
|
+
};
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
isInstalled: false,
|
|
112
|
+
details: `AI \u4E2A\u6027\u6587\u4EF6\u68C0\u67E5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { checkAllFeatures };
|
|
@@ -8,12 +8,12 @@ import { promisify as promisify$1 } from 'node:util';
|
|
|
8
8
|
import { exec as exec$1 } from 'child_process';
|
|
9
9
|
import { promisify } from 'util';
|
|
10
10
|
import ora from 'ora';
|
|
11
|
-
import
|
|
11
|
+
import 'dayjs';
|
|
12
12
|
import { join as join$1 } from 'node:path';
|
|
13
13
|
import { join, dirname } from 'pathe';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
15
|
|
|
16
|
-
const version = "0.1.
|
|
16
|
+
const version = "0.1.7";
|
|
17
17
|
|
|
18
18
|
function displayBanner(subtitle) {
|
|
19
19
|
const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
|
|
@@ -3682,10 +3682,9 @@ function backupJsonConfig(path, backupDir) {
|
|
|
3682
3682
|
if (!exists(path)) {
|
|
3683
3683
|
return null;
|
|
3684
3684
|
}
|
|
3685
|
-
const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
|
|
3686
3685
|
const fileName = path.split("/").pop() || "config.json";
|
|
3687
3686
|
const baseDir = backupDir || join(path, "..", "backup");
|
|
3688
|
-
const backupPath = join(baseDir, `${fileName}.
|
|
3687
|
+
const backupPath = join(baseDir, `${fileName}.backup`);
|
|
3689
3688
|
try {
|
|
3690
3689
|
ensureDir(baseDir);
|
|
3691
3690
|
copyFile(path, backupPath);
|
|
@@ -5586,4 +5585,4 @@ async function openSettingsJson() {
|
|
|
5586
5585
|
}
|
|
5587
5586
|
}
|
|
5588
5587
|
|
|
5589
|
-
export { AICO_CONFIG_FILE as A,
|
|
5588
|
+
export { AICO_CONFIG_FILE as A, mergeMcpServers as B, CLAUDE_DIR as C, buildMcpServerConfig as D, fixWindowsMcpConfig as E, addCompletedOnboarding as F, readJsonConfig as G, isTermux as H, messages as I, getTermuxPrefix as J, createEscapablePrompt as K, LEGACY_AICO_CONFIG_FILE as L, MCP_SERVICES as M, displayBannerWithInfo as N, executeWithEscapeSupport as O, handleExitPromptError as P, handleGeneralError as Q, EscapeKeyPressed as R, SETTINGS_FILE as S, displayBanner as T, version as U, ConfigCheckerInstaller as V, init$1 as W, 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, ensureClaudeDir as l, mergeAndCleanPermissions as m, backupExistingConfig as n, openSettingsJson as o, copyConfigFiles as p, configureApi as q, mergeConfigs as r, mergeSettingsFile as s, getExistingApiConfig as t, updateDefaultModel as u, applyAiLanguageDirective as v, getMcpConfigPath as w, readMcpConfig as x, writeMcpConfig as y, backupMcpConfig as z };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import cac from 'cac';
|
|
3
3
|
import ansis from 'ansis';
|
|
4
|
-
import {
|
|
4
|
+
import { K as createEscapablePrompt, N as displayBannerWithInfo, i as init, O as executeWithEscapeSupport, P as handleExitPromptError, Q as handleGeneralError, R as EscapeKeyPressed, T as displayBanner, U as version, V as ConfigCheckerInstaller } from './chunks/simple-config.mjs';
|
|
5
5
|
import inquirer$1 from 'inquirer';
|
|
6
|
-
import { spawn, exec } from 'node:child_process';
|
|
6
|
+
import { spawn, exec as exec$1 } from 'node:child_process';
|
|
7
7
|
import 'tinyexec';
|
|
8
8
|
import 'node:os';
|
|
9
9
|
import 'node:fs';
|
|
10
10
|
import 'pathe';
|
|
11
11
|
import 'node:url';
|
|
12
|
-
import 'dayjs';
|
|
13
|
-
import { promisify } from 'node:util';
|
|
14
|
-
import 'child_process';
|
|
15
|
-
import 'util';
|
|
16
|
-
import 'ora';
|
|
17
12
|
import 'node:path';
|
|
13
|
+
import { exec } from 'child_process';
|
|
14
|
+
import { promisify } from 'util';
|
|
15
|
+
import { promisify as promisify$1 } from 'node:util';
|
|
16
|
+
import 'ora';
|
|
17
|
+
import 'dayjs';
|
|
18
18
|
|
|
19
19
|
const inquirer = {
|
|
20
20
|
...inquirer$1,
|
|
@@ -123,7 +123,9 @@ async function updateAicoCli() {
|
|
|
123
123
|
|
|
124
124
|
promisify(exec);
|
|
125
125
|
|
|
126
|
-
promisify(exec);
|
|
126
|
+
promisify$1(exec$1);
|
|
127
|
+
|
|
128
|
+
promisify$1(exec$1);
|
|
127
129
|
|
|
128
130
|
async function tryStartClaude(command, args, options) {
|
|
129
131
|
return new Promise((resolve, reject) => {
|
|
@@ -339,7 +341,7 @@ function setupCommands(cli) {
|
|
|
339
341
|
} else if (options.update) {
|
|
340
342
|
await update({});
|
|
341
343
|
} else if (options.company) {
|
|
342
|
-
const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.
|
|
344
|
+
const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.W; });
|
|
343
345
|
await init2({
|
|
344
346
|
apiType: "auth_token",
|
|
345
347
|
force: options.force,
|
|
@@ -347,7 +349,7 @@ function setupCommands(cli) {
|
|
|
347
349
|
skipPrompt: true
|
|
348
350
|
});
|
|
349
351
|
} else if (options.personal) {
|
|
350
|
-
const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.
|
|
352
|
+
const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.W; });
|
|
351
353
|
await init2({
|
|
352
354
|
apiType: "ccr_proxy",
|
|
353
355
|
force: options.force,
|
|
@@ -370,10 +372,17 @@ async function startCodeEditor() {
|
|
|
370
372
|
const checker = new ConfigCheckerInstaller(context);
|
|
371
373
|
const status = await checker.checkStatus();
|
|
372
374
|
if (status.isInstalled) {
|
|
373
|
-
console.log(ansis.green("\u2705 \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E\uFF0C\
|
|
375
|
+
console.log(ansis.green("\u2705 \u68C0\u6D4B\u5230\u5DF2\u6709\u914D\u7F6E\uFF0C\u68C0\u67E5\u5404\u529F\u80FD\u6A21\u5757\u5B89\u88C5\u72B6\u6001..."));
|
|
376
|
+
const { checkAllFeatures } = await import('./chunks/feature-checker.mjs');
|
|
377
|
+
const featureStatus = await checkAllFeatures(context);
|
|
378
|
+
const missingFeatures = Object.entries(featureStatus).filter(([_, status2]) => !status2.isInstalled).map(([name, _]) => name);
|
|
379
|
+
if (missingFeatures.length > 0) {
|
|
380
|
+
console.log(ansis.yellow(`\u26A0\uFE0F \u53D1\u73B0\u672A\u5B89\u88C5\u7684\u529F\u80FD\u6A21\u5757: ${missingFeatures.join(", ")}`));
|
|
381
|
+
console.log(ansis.yellow(" \u8FD0\u884C `aico --init` \u6216 `aico --update` \u6765\u5B89\u88C5\u7F3A\u5931\u529F\u80FD"));
|
|
382
|
+
}
|
|
374
383
|
} else {
|
|
375
384
|
console.log(ansis.yellow("\u26A0\uFE0F \u672A\u68C0\u6D4B\u5230\u914D\u7F6E\uFF0C\u5C06\u5148\u6267\u884C\u521D\u59CB\u5316\u914D\u7F6E..."));
|
|
376
|
-
const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.
|
|
385
|
+
const { init: init2 } = await import('./chunks/simple-config.mjs').then(function (n) { return n.W; });
|
|
377
386
|
await init2({ skipBanner: true, skipPrompt: true });
|
|
378
387
|
}
|
|
379
388
|
await startClaudeCodeEditor();
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
import
|
|
4
|
-
import ansis from 'ansis';
|
|
1
|
+
export { A as AICO_CONFIG_FILE, k as AI_OUTPUT_LANGUAGES, C as CLAUDE_DIR, e as CLAUDE_MD_FILE, f as ClAUDE_CONFIG_FILE, j as LANG_LABELS, L as LEGACY_AICO_CONFIG_FILE, M as MCP_SERVICES, S as SETTINGS_FILE, h as SUPPORTED_LANGS, F as addCompletedOnboarding, v as applyAiLanguageDirective, n as backupExistingConfig, z as backupMcpConfig, D as buildMcpServerConfig, d as cleanupPermissions, c as commandExists, q as configureApi, p as copyConfigFiles, l as ensureClaudeDir, E as fixWindowsMcpConfig, t as getExistingApiConfig, w as getMcpConfigPath, g as getPlatform, a as importRecommendedEnv, b as importRecommendedPermissions, i as init, m as mergeAndCleanPermissions, r as mergeConfigs, B as mergeMcpServers, s as mergeSettingsFile, o as openSettingsJson, x as readMcpConfig, u as updateDefaultModel, y as writeMcpConfig } from './chunks/simple-config.mjs';
|
|
2
|
+
export { a as installClaudeCode, b as installClaudeCodeSilently, i as isClaudeCodeInstalled } from './shared/aico-cli.C9hv-Gol.mjs';
|
|
3
|
+
import 'ansis';
|
|
5
4
|
import 'inquirer';
|
|
5
|
+
import 'tinyexec';
|
|
6
6
|
import 'node:os';
|
|
7
7
|
import 'node:fs';
|
|
8
8
|
import 'node:child_process';
|
|
@@ -14,51 +14,3 @@ import 'dayjs';
|
|
|
14
14
|
import 'node:path';
|
|
15
15
|
import 'pathe';
|
|
16
16
|
import 'node:url';
|
|
17
|
-
|
|
18
|
-
async function isClaudeCodeInstalled() {
|
|
19
|
-
return await commandExists("claude");
|
|
20
|
-
}
|
|
21
|
-
async function installClaudeCode(lang) {
|
|
22
|
-
getTranslation(lang);
|
|
23
|
-
if (isTermux()) {
|
|
24
|
-
console.log(ansis.yellow(`\u2139 ${messages.installation.termuxDetected}`));
|
|
25
|
-
const termuxPrefix = getTermuxPrefix();
|
|
26
|
-
console.log(ansis.gray(messages.installation.termuxPathInfo.replace("{path}", termuxPrefix)));
|
|
27
|
-
console.log(ansis.gray(`Node.js: ${termuxPrefix}/bin/node`));
|
|
28
|
-
console.log(ansis.gray(`npm: ${termuxPrefix}/bin/npm`));
|
|
29
|
-
}
|
|
30
|
-
console.log(messages.installation.installing);
|
|
31
|
-
try {
|
|
32
|
-
await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
33
|
-
console.log(`\u2714 ${messages.installation.installSuccess}`);
|
|
34
|
-
if (isTermux()) {
|
|
35
|
-
console.log(ansis.gray(`
|
|
36
|
-
Claude Code installed to: ${getTermuxPrefix()}/bin/claude`));
|
|
37
|
-
}
|
|
38
|
-
} catch (error) {
|
|
39
|
-
console.error(`\u2716 ${messages.installation.installFailed}`);
|
|
40
|
-
if (isTermux()) {
|
|
41
|
-
console.error(ansis.yellow(`
|
|
42
|
-
${messages.installation.termuxInstallHint}
|
|
43
|
-
`));
|
|
44
|
-
}
|
|
45
|
-
throw error;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
async function installClaudeCodeSilently() {
|
|
49
|
-
const installed = await isClaudeCodeInstalled();
|
|
50
|
-
if (installed) {
|
|
51
|
-
console.log(ansis.green("\u2714 \u5DF2\u5B89\u88C5 Claude Code"));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
console.log("\u6B63\u5728\u5B89\u88C5 Claude Code...");
|
|
55
|
-
try {
|
|
56
|
-
await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
57
|
-
console.log(ansis.green("\u2714 Claude Code \u5B89\u88C5\u6210\u529F"));
|
|
58
|
-
} catch (error) {
|
|
59
|
-
console.error(ansis.red("\u2716 Claude Code \u5B89\u88C5\u5931\u8D25"));
|
|
60
|
-
throw error;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { commandExists, installClaudeCode, installClaudeCodeSilently, isClaudeCodeInstalled };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { exec } from 'tinyexec';
|
|
2
|
+
import ansis from 'ansis';
|
|
3
|
+
import { c as commandExists, H as isTermux, I as messages, J as getTermuxPrefix } from '../chunks/simple-config.mjs';
|
|
4
|
+
|
|
5
|
+
async function isClaudeCodeInstalled() {
|
|
6
|
+
return await commandExists("claude");
|
|
7
|
+
}
|
|
8
|
+
async function installClaudeCode(lang) {
|
|
9
|
+
getTranslation(lang);
|
|
10
|
+
if (isTermux()) {
|
|
11
|
+
console.log(ansis.yellow(`\u2139 ${messages.installation.termuxDetected}`));
|
|
12
|
+
const termuxPrefix = getTermuxPrefix();
|
|
13
|
+
console.log(ansis.gray(messages.installation.termuxPathInfo.replace("{path}", termuxPrefix)));
|
|
14
|
+
console.log(ansis.gray(`Node.js: ${termuxPrefix}/bin/node`));
|
|
15
|
+
console.log(ansis.gray(`npm: ${termuxPrefix}/bin/npm`));
|
|
16
|
+
}
|
|
17
|
+
console.log(messages.installation.installing);
|
|
18
|
+
try {
|
|
19
|
+
await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
20
|
+
console.log(`\u2714 ${messages.installation.installSuccess}`);
|
|
21
|
+
if (isTermux()) {
|
|
22
|
+
console.log(ansis.gray(`
|
|
23
|
+
Claude Code installed to: ${getTermuxPrefix()}/bin/claude`));
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error(`\u2716 ${messages.installation.installFailed}`);
|
|
27
|
+
if (isTermux()) {
|
|
28
|
+
console.error(ansis.yellow(`
|
|
29
|
+
${messages.installation.termuxInstallHint}
|
|
30
|
+
`));
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function installClaudeCodeSilently() {
|
|
36
|
+
const installed = await isClaudeCodeInstalled();
|
|
37
|
+
if (installed) {
|
|
38
|
+
console.log(ansis.green("\u2714 \u5DF2\u5B89\u88C5 Claude Code"));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
console.log("\u6B63\u5728\u5B89\u88C5 Claude Code...");
|
|
42
|
+
try {
|
|
43
|
+
await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
44
|
+
console.log(ansis.green("\u2714 Claude Code \u5B89\u88C5\u6210\u529F"));
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(ansis.red("\u2716 Claude Code \u5B89\u88C5\u5931\u8D25"));
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { installClaudeCode as a, installClaudeCodeSilently as b, isClaudeCodeInstalled as i };
|
package/package.json
CHANGED
package/templates/personality.md
CHANGED
|
@@ -52,27 +52,79 @@ description: 专业的软件工程师,严格遵循SOLID、KISS、DRY、YAGNI
|
|
|
52
52
|
|
|
53
53
|
**每次代码变更都要体现:**
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
#### I. 规范驱动开发 (Specification-Driven Development)
|
|
56
|
+
每个功能从业务需求开始,严格区分业务逻辑与技术实现:
|
|
57
|
+
- 需求阶段仅关注业务功能(WHAT),严禁涉及技术实现(HOW)
|
|
58
|
+
- 设计阶段负责技术决策和架构,基于已批准的需求
|
|
59
|
+
- 实现阶段严格按照设计文档和任务清单执行
|
|
60
|
+
|
|
61
|
+
#### II. 测试驱动开发 (Test-Driven Development - 不可协商)
|
|
62
|
+
TDD为强制性要求,红-绿-重构循环严格执行:
|
|
63
|
+
- 测试必须先于实现编写
|
|
64
|
+
- 每个需求(REQ-XXX)都必须有对应的测试用例
|
|
65
|
+
- 测试必须先失败(RED),然后实现功能使其通过(GREEN)
|
|
66
|
+
- Git提交历史必须体现测试优先的开发顺序
|
|
67
|
+
|
|
68
|
+
#### III. 模块化架构 (Modular Architecture)
|
|
69
|
+
采用清晰的模块边界和职责分离:
|
|
70
|
+
- 每个功能作为独立的模块开发
|
|
71
|
+
- 模块之间通过明确的接口交互
|
|
72
|
+
- 支持嵌套模块结构用于复杂功能分解
|
|
73
|
+
- 避免循环依赖和紧耦合
|
|
74
|
+
|
|
75
|
+
#### IV. 增量开发 (Incremental Development)
|
|
76
|
+
优先考虑最佳实践、增量进展和早期验证:
|
|
77
|
+
- 任何阶段都不允许复杂性的大跳跃
|
|
78
|
+
- 每个任务都建立在前一个任务的基础上
|
|
79
|
+
- 尽早集成和测试,及时发现问题
|
|
80
|
+
- 保持系统在任何时刻都处于可工作状态
|
|
81
|
+
|
|
82
|
+
#### V. 简洁性原则 (Simplicity First)
|
|
83
|
+
遵循YAGNI原则,避免过度设计:
|
|
84
|
+
- 从最简单的实现开始
|
|
85
|
+
- 只在有明确需求时才增加复杂性
|
|
86
|
+
- 重构优于重写
|
|
87
|
+
- 优先使用标准库和成熟的框架
|
|
88
|
+
|
|
89
|
+
#### VI. 代码质量 (Code Quality)
|
|
90
|
+
**设计阶段检查点**
|
|
91
|
+
在进入实现阶段前,必须通过以下检查:
|
|
92
|
+
- 所有需求都有对应的设计方案
|
|
93
|
+
- 架构决策有明确的理由和权衡分析
|
|
94
|
+
- 测试策略完整,覆盖所有验收标准
|
|
95
|
+
- 技术风险已识别并有应对方案
|
|
96
|
+
|
|
97
|
+
**实现阶段检查点**
|
|
98
|
+
每个开发任务完成前,必须满足:
|
|
99
|
+
- 对应的测试用例已编写并通过
|
|
100
|
+
- 代码符合项目编码规范
|
|
101
|
+
- 所有公共接口都有文档
|
|
102
|
+
- 没有遗留的TODO或FIXME标记
|
|
103
|
+
|
|
104
|
+
**集成阶段检查点**
|
|
105
|
+
功能集成前的必要条件:
|
|
106
|
+
- 所有单元测试通过
|
|
107
|
+
- 集成测试验证了模块间交互
|
|
108
|
+
- 端到端测试覆盖了用户场景
|
|
109
|
+
- 性能指标在可接受范围内
|
|
110
|
+
|
|
111
|
+
#### VII. 技术约束(Technical Constraint)
|
|
112
|
+
**依赖管理:**
|
|
113
|
+
- 优先使用项目已有的技术栈
|
|
114
|
+
- 引入新依赖需要明确的理由和批准
|
|
115
|
+
- 避免重复造轮子,复用已有组件
|
|
116
|
+
- 考虑长期维护成本
|
|
117
|
+
|
|
118
|
+
**性能要求:**
|
|
119
|
+
- 批处理操作提供进度指示
|
|
120
|
+
- 内存使用控制在合理范围
|
|
121
|
+
- 支持并发操作不阻塞主流程
|
|
122
|
+
|
|
123
|
+
**安全考虑:**
|
|
124
|
+
- 所有用户输入必须验证
|
|
125
|
+
- 敏感信息不得硬编码
|
|
126
|
+
- 错误信息不暴露内部实现
|
|
127
|
+
- 遵循最小权限原则
|
|
76
128
|
|
|
77
129
|
### 4. 持续问题解决
|
|
78
130
|
|