claude-coder 1.8.2 → 1.8.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.
- package/README.md +167 -167
- package/bin/cli.js +172 -172
- package/package.json +53 -52
- package/recipes/_shared/roles/developer.md +11 -0
- package/recipes/_shared/roles/product.md +12 -0
- package/recipes/_shared/roles/tester.md +12 -0
- package/recipes/_shared/test/report-format.md +86 -0
- package/recipes/backend/base.md +27 -0
- package/recipes/backend/components/auth.md +18 -0
- package/recipes/backend/components/crud-api.md +18 -0
- package/recipes/backend/components/file-service.md +15 -0
- package/recipes/backend/manifest.json +20 -0
- package/recipes/backend/test/api-test.md +25 -0
- package/recipes/console/base.md +37 -0
- package/recipes/console/components/modal-form.md +20 -0
- package/recipes/console/components/pagination.md +17 -0
- package/recipes/console/components/search.md +17 -0
- package/recipes/console/components/table-list.md +18 -0
- package/recipes/console/components/tabs.md +14 -0
- package/recipes/console/components/tree.md +15 -0
- package/recipes/console/components/upload.md +15 -0
- package/recipes/console/manifest.json +24 -0
- package/recipes/console/test/crud-e2e.md +47 -0
- package/recipes/h5/base.md +26 -0
- package/recipes/h5/components/animation.md +11 -0
- package/recipes/h5/components/countdown.md +11 -0
- package/recipes/h5/components/share.md +11 -0
- package/recipes/h5/components/swiper.md +11 -0
- package/recipes/h5/manifest.json +21 -0
- package/recipes/h5/test/h5-e2e.md +20 -0
- package/src/commands/auth.js +290 -240
- package/src/commands/setup-modules/helpers.js +99 -99
- package/src/commands/setup-modules/index.js +25 -25
- package/src/commands/setup-modules/mcp.js +94 -94
- package/src/commands/setup-modules/provider.js +260 -260
- package/src/commands/setup-modules/safety.js +61 -61
- package/src/commands/setup-modules/simplify.js +52 -52
- package/src/commands/setup.js +172 -172
- package/src/common/assets.js +236 -236
- package/src/common/config.js +125 -125
- package/src/common/constants.js +55 -55
- package/src/common/indicator.js +222 -222
- package/src/common/interaction.js +170 -170
- package/src/common/logging.js +77 -77
- package/src/common/sdk.js +50 -50
- package/src/common/tasks.js +88 -88
- package/src/common/utils.js +161 -161
- package/src/core/coding.js +55 -55
- package/src/core/context.js +117 -117
- package/src/core/go.js +310 -310
- package/src/core/harness.js +484 -484
- package/src/core/hooks.js +533 -533
- package/src/core/init.js +171 -171
- package/src/core/plan.js +325 -325
- package/src/core/prompts.js +227 -227
- package/src/core/query.js +49 -49
- package/src/core/repair.js +46 -46
- package/src/core/runner.js +195 -195
- package/src/core/scan.js +89 -89
- package/src/core/session.js +56 -56
- package/src/core/simplify.js +53 -52
- package/templates/bash-process.md +12 -12
- package/templates/codingSystem.md +65 -65
- package/templates/codingUser.md +17 -17
- package/templates/coreProtocol.md +29 -29
- package/templates/goSystem.md +130 -130
- package/templates/guidance.json +52 -52
- package/templates/planSystem.md +78 -78
- package/templates/planUser.md +8 -8
- package/templates/playwright.md +16 -16
- package/templates/requirements.example.md +57 -57
- package/templates/scanSystem.md +120 -120
- package/templates/scanUser.md +10 -10
- package/templates/test_rule.md +194 -194
package/src/core/init.js
CHANGED
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const net = require('net');
|
|
5
|
-
const http = require('http');
|
|
6
|
-
const { spawn, execSync } = require('child_process');
|
|
7
|
-
const { log } = require('../common/config');
|
|
8
|
-
const { assets } = require('../common/assets');
|
|
9
|
-
const { scan } = require('./scan');
|
|
10
|
-
|
|
11
|
-
function loadProfile() {
|
|
12
|
-
const data = assets.readJson('profile', null);
|
|
13
|
-
if (!data) {
|
|
14
|
-
log('error', 'project_profile.json 读取失败或已损坏');
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
return data;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function isPortFree(port) {
|
|
21
|
-
return new Promise(resolve => {
|
|
22
|
-
const server = net.createServer();
|
|
23
|
-
server.once('error', () => resolve(false));
|
|
24
|
-
server.once('listening', () => { server.close(); resolve(true); });
|
|
25
|
-
server.listen(port, '127.0.0.1');
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function waitForHealth(url, timeoutMs = 15000) {
|
|
30
|
-
const start = Date.now();
|
|
31
|
-
return new Promise(resolve => {
|
|
32
|
-
const check = () => {
|
|
33
|
-
if (Date.now() - start > timeoutMs) { resolve(false); return; }
|
|
34
|
-
const req = http.get(url, res => {
|
|
35
|
-
resolve(res.statusCode < 500);
|
|
36
|
-
});
|
|
37
|
-
req.on('error', () => setTimeout(check, 1000));
|
|
38
|
-
req.setTimeout(3000, () => { req.destroy(); setTimeout(check, 1000); });
|
|
39
|
-
};
|
|
40
|
-
check();
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function runCmd(cmd, cwd) {
|
|
45
|
-
try {
|
|
46
|
-
execSync(cmd, { cwd: cwd || assets.projectRoot, stdio: 'inherit', shell: true });
|
|
47
|
-
return true;
|
|
48
|
-
} catch {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function deployAssets() {
|
|
54
|
-
const deployed = assets.deployAll();
|
|
55
|
-
if (deployed.length > 0) {
|
|
56
|
-
for (const file of deployed) {
|
|
57
|
-
log('ok', `已部署 → .claude-coder/assets/${file}`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function deployRecipes() {
|
|
63
|
-
const deployed = assets.deployRecipes();
|
|
64
|
-
if (deployed.length > 0) {
|
|
65
|
-
log('ok', `已部署 ${deployed.length} 个食谱文件 → .claude-coder/recipes/`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function init() {
|
|
70
|
-
assets.ensureDirs();
|
|
71
|
-
const projectRoot = assets.projectRoot;
|
|
72
|
-
|
|
73
|
-
if (!assets.exists('profile')) {
|
|
74
|
-
log('info', 'profile 不存在,正在执行项目扫描...');
|
|
75
|
-
const scanResult = await scan({ projectRoot });
|
|
76
|
-
if (!scanResult.success) {
|
|
77
|
-
log('error', '项目扫描失败');
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const profile = loadProfile();
|
|
83
|
-
let stepCount = 0;
|
|
84
|
-
|
|
85
|
-
deployAssets();
|
|
86
|
-
deployRecipes();
|
|
87
|
-
|
|
88
|
-
const envSetup = profile.env_setup || {};
|
|
89
|
-
if (envSetup.python_env && envSetup.python_env !== 'system' && envSetup.python_env !== 'none') {
|
|
90
|
-
stepCount++;
|
|
91
|
-
if (envSetup.python_env.startsWith('conda:')) {
|
|
92
|
-
const envName = envSetup.python_env.slice(6);
|
|
93
|
-
log('info', `[${stepCount}] Python 环境: conda activate ${envName}`);
|
|
94
|
-
runCmd(`conda activate ${envName}`);
|
|
95
|
-
} else if (envSetup.python_env === 'venv') {
|
|
96
|
-
log('info', `[${stepCount}] Python 环境: venv`);
|
|
97
|
-
runCmd('source .venv/bin/activate || .venv\\Scripts\\activate');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (envSetup.node_version && envSetup.node_version !== 'none') {
|
|
101
|
-
stepCount++;
|
|
102
|
-
log('info', `[${stepCount}] Node.js: v${envSetup.node_version}`);
|
|
103
|
-
runCmd(`nvm use ${envSetup.node_version}`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const pkgManagers = (profile.tech_stack && profile.tech_stack.package_managers) || [];
|
|
107
|
-
for (const pm of pkgManagers) {
|
|
108
|
-
stepCount++;
|
|
109
|
-
if (pm === 'npm' || pm === 'yarn' || pm === 'pnpm') {
|
|
110
|
-
if (fs.existsSync(`${projectRoot}/node_modules`)) {
|
|
111
|
-
log('ok', `[${stepCount}] ${pm} 依赖已安装,跳过`);
|
|
112
|
-
} else {
|
|
113
|
-
log('info', `[${stepCount}] 安装依赖: ${pm} install`);
|
|
114
|
-
runCmd(`${pm} install`, projectRoot);
|
|
115
|
-
}
|
|
116
|
-
} else if (pm === 'pip') {
|
|
117
|
-
const reqFile = fs.existsSync(`${projectRoot}/requirements.txt`);
|
|
118
|
-
if (reqFile) {
|
|
119
|
-
log('info', `[${stepCount}] 安装依赖: pip install -r requirements.txt`);
|
|
120
|
-
runCmd('pip install -r requirements.txt', projectRoot);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const customInit = profile.custom_init || [];
|
|
126
|
-
for (const cmd of customInit) {
|
|
127
|
-
stepCount++;
|
|
128
|
-
log('info', `[${stepCount}] 自定义: ${cmd}`);
|
|
129
|
-
runCmd(cmd, projectRoot);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const services = profile.services || [];
|
|
133
|
-
for (const svc of services) {
|
|
134
|
-
stepCount++;
|
|
135
|
-
const free = await isPortFree(svc.port);
|
|
136
|
-
if (!free) {
|
|
137
|
-
log('ok', `[${stepCount}] ${svc.name} 已在端口 ${svc.port} 运行,跳过`);
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
log('info', `[${stepCount}] 启动 ${svc.name} (端口 ${svc.port})...`);
|
|
142
|
-
const cwd = svc.cwd ? `${projectRoot}/${svc.cwd}` : projectRoot;
|
|
143
|
-
const child = spawn(svc.command, { cwd, shell: true, detached: true, stdio: 'ignore' });
|
|
144
|
-
child.unref();
|
|
145
|
-
|
|
146
|
-
if (svc.health_check) {
|
|
147
|
-
const healthy = await waitForHealth(svc.health_check);
|
|
148
|
-
if (healthy) {
|
|
149
|
-
log('ok', `${svc.name} 就绪: ${svc.health_check}`);
|
|
150
|
-
} else {
|
|
151
|
-
log('warn', `${svc.name} 健康检查超时 (${svc.health_check}),继续执行`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (stepCount === 0) {
|
|
157
|
-
log('info', '无需初始化操作');
|
|
158
|
-
} else {
|
|
159
|
-
log('ok', `初始化完成 (${stepCount} 步)`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (services.length > 0) {
|
|
163
|
-
console.log('');
|
|
164
|
-
for (const svc of services) {
|
|
165
|
-
console.log(` ${svc.name}: http://localhost:${svc.port}`);
|
|
166
|
-
}
|
|
167
|
-
console.log('');
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
module.exports = { init };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const net = require('net');
|
|
5
|
+
const http = require('http');
|
|
6
|
+
const { spawn, execSync } = require('child_process');
|
|
7
|
+
const { log } = require('../common/config');
|
|
8
|
+
const { assets } = require('../common/assets');
|
|
9
|
+
const { scan } = require('./scan');
|
|
10
|
+
|
|
11
|
+
function loadProfile() {
|
|
12
|
+
const data = assets.readJson('profile', null);
|
|
13
|
+
if (!data) {
|
|
14
|
+
log('error', 'project_profile.json 读取失败或已损坏');
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isPortFree(port) {
|
|
21
|
+
return new Promise(resolve => {
|
|
22
|
+
const server = net.createServer();
|
|
23
|
+
server.once('error', () => resolve(false));
|
|
24
|
+
server.once('listening', () => { server.close(); resolve(true); });
|
|
25
|
+
server.listen(port, '127.0.0.1');
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function waitForHealth(url, timeoutMs = 15000) {
|
|
30
|
+
const start = Date.now();
|
|
31
|
+
return new Promise(resolve => {
|
|
32
|
+
const check = () => {
|
|
33
|
+
if (Date.now() - start > timeoutMs) { resolve(false); return; }
|
|
34
|
+
const req = http.get(url, res => {
|
|
35
|
+
resolve(res.statusCode < 500);
|
|
36
|
+
});
|
|
37
|
+
req.on('error', () => setTimeout(check, 1000));
|
|
38
|
+
req.setTimeout(3000, () => { req.destroy(); setTimeout(check, 1000); });
|
|
39
|
+
};
|
|
40
|
+
check();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function runCmd(cmd, cwd) {
|
|
45
|
+
try {
|
|
46
|
+
execSync(cmd, { cwd: cwd || assets.projectRoot, stdio: 'inherit', shell: true });
|
|
47
|
+
return true;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function deployAssets() {
|
|
54
|
+
const deployed = assets.deployAll();
|
|
55
|
+
if (deployed.length > 0) {
|
|
56
|
+
for (const file of deployed) {
|
|
57
|
+
log('ok', `已部署 → .claude-coder/assets/${file}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function deployRecipes() {
|
|
63
|
+
const deployed = assets.deployRecipes();
|
|
64
|
+
if (deployed.length > 0) {
|
|
65
|
+
log('ok', `已部署 ${deployed.length} 个食谱文件 → .claude-coder/recipes/`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function init() {
|
|
70
|
+
assets.ensureDirs();
|
|
71
|
+
const projectRoot = assets.projectRoot;
|
|
72
|
+
|
|
73
|
+
if (!assets.exists('profile')) {
|
|
74
|
+
log('info', 'profile 不存在,正在执行项目扫描...');
|
|
75
|
+
const scanResult = await scan({ projectRoot });
|
|
76
|
+
if (!scanResult.success) {
|
|
77
|
+
log('error', '项目扫描失败');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const profile = loadProfile();
|
|
83
|
+
let stepCount = 0;
|
|
84
|
+
|
|
85
|
+
deployAssets();
|
|
86
|
+
deployRecipes();
|
|
87
|
+
|
|
88
|
+
const envSetup = profile.env_setup || {};
|
|
89
|
+
if (envSetup.python_env && envSetup.python_env !== 'system' && envSetup.python_env !== 'none') {
|
|
90
|
+
stepCount++;
|
|
91
|
+
if (envSetup.python_env.startsWith('conda:')) {
|
|
92
|
+
const envName = envSetup.python_env.slice(6);
|
|
93
|
+
log('info', `[${stepCount}] Python 环境: conda activate ${envName}`);
|
|
94
|
+
runCmd(`conda activate ${envName}`);
|
|
95
|
+
} else if (envSetup.python_env === 'venv') {
|
|
96
|
+
log('info', `[${stepCount}] Python 环境: venv`);
|
|
97
|
+
runCmd('source .venv/bin/activate || .venv\\Scripts\\activate');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (envSetup.node_version && envSetup.node_version !== 'none') {
|
|
101
|
+
stepCount++;
|
|
102
|
+
log('info', `[${stepCount}] Node.js: v${envSetup.node_version}`);
|
|
103
|
+
runCmd(`nvm use ${envSetup.node_version}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const pkgManagers = (profile.tech_stack && profile.tech_stack.package_managers) || [];
|
|
107
|
+
for (const pm of pkgManagers) {
|
|
108
|
+
stepCount++;
|
|
109
|
+
if (pm === 'npm' || pm === 'yarn' || pm === 'pnpm') {
|
|
110
|
+
if (fs.existsSync(`${projectRoot}/node_modules`)) {
|
|
111
|
+
log('ok', `[${stepCount}] ${pm} 依赖已安装,跳过`);
|
|
112
|
+
} else {
|
|
113
|
+
log('info', `[${stepCount}] 安装依赖: ${pm} install`);
|
|
114
|
+
runCmd(`${pm} install`, projectRoot);
|
|
115
|
+
}
|
|
116
|
+
} else if (pm === 'pip') {
|
|
117
|
+
const reqFile = fs.existsSync(`${projectRoot}/requirements.txt`);
|
|
118
|
+
if (reqFile) {
|
|
119
|
+
log('info', `[${stepCount}] 安装依赖: pip install -r requirements.txt`);
|
|
120
|
+
runCmd('pip install -r requirements.txt', projectRoot);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const customInit = profile.custom_init || [];
|
|
126
|
+
for (const cmd of customInit) {
|
|
127
|
+
stepCount++;
|
|
128
|
+
log('info', `[${stepCount}] 自定义: ${cmd}`);
|
|
129
|
+
runCmd(cmd, projectRoot);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const services = profile.services || [];
|
|
133
|
+
for (const svc of services) {
|
|
134
|
+
stepCount++;
|
|
135
|
+
const free = await isPortFree(svc.port);
|
|
136
|
+
if (!free) {
|
|
137
|
+
log('ok', `[${stepCount}] ${svc.name} 已在端口 ${svc.port} 运行,跳过`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
log('info', `[${stepCount}] 启动 ${svc.name} (端口 ${svc.port})...`);
|
|
142
|
+
const cwd = svc.cwd ? `${projectRoot}/${svc.cwd}` : projectRoot;
|
|
143
|
+
const child = spawn(svc.command, { cwd, shell: true, detached: true, stdio: 'ignore' });
|
|
144
|
+
child.unref();
|
|
145
|
+
|
|
146
|
+
if (svc.health_check) {
|
|
147
|
+
const healthy = await waitForHealth(svc.health_check);
|
|
148
|
+
if (healthy) {
|
|
149
|
+
log('ok', `${svc.name} 就绪: ${svc.health_check}`);
|
|
150
|
+
} else {
|
|
151
|
+
log('warn', `${svc.name} 健康检查超时 (${svc.health_check}),继续执行`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (stepCount === 0) {
|
|
157
|
+
log('info', '无需初始化操作');
|
|
158
|
+
} else {
|
|
159
|
+
log('ok', `初始化完成 (${stepCount} 步)`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (services.length > 0) {
|
|
163
|
+
console.log('');
|
|
164
|
+
for (const svc of services) {
|
|
165
|
+
console.log(` ${svc.name}: http://localhost:${svc.port}`);
|
|
166
|
+
}
|
|
167
|
+
console.log('');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = { init };
|