claude-coder 1.9.0 → 1.9.2

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