claude-coder 1.9.2 → 1.10.0

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 (81) hide show
  1. package/README.md +236 -214
  2. package/bin/cli.js +170 -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 -420
  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 +259 -245
  40. package/src/common/config.js +147 -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 +48 -50
  46. package/src/common/tasks.js +88 -88
  47. package/src/common/utils.js +214 -213
  48. package/src/core/coding.js +35 -33
  49. package/src/core/design.js +268 -0
  50. package/src/core/go.js +264 -264
  51. package/src/core/hooks.js +514 -500
  52. package/src/core/init.js +175 -166
  53. package/src/core/plan.js +194 -188
  54. package/src/core/prompts.js +292 -247
  55. package/src/core/repair.js +36 -36
  56. package/src/core/runner.js +471 -471
  57. package/src/core/scan.js +94 -93
  58. package/src/core/session.js +294 -280
  59. package/src/core/simplify.js +76 -74
  60. package/src/core/state.js +120 -105
  61. package/src/index.js +80 -76
  62. package/templates/{codingSystem.md → coding/system.md} +65 -65
  63. package/templates/{codingUser.md → coding/user.md} +18 -17
  64. package/templates/design/base.md +103 -0
  65. package/templates/design/fixSystem.md +71 -0
  66. package/templates/design/fixUser.md +3 -0
  67. package/templates/design/init.md +304 -0
  68. package/templates/design/system.md +108 -0
  69. package/templates/design/user.md +11 -0
  70. package/templates/{goSystem.md → go/system.md} +130 -130
  71. package/templates/{bash-process.md → other/bash-process.md} +12 -12
  72. package/templates/{coreProtocol.md → other/coreProtocol.md} +30 -29
  73. package/templates/{guidance.json → other/guidance.json} +72 -72
  74. package/templates/{requirements.example.md → other/requirements.example.md} +57 -57
  75. package/templates/{test_rule.md → other/test_rule.md} +192 -194
  76. package/templates/{web-testing.md → other/web-testing.md} +17 -17
  77. package/templates/{planSystem.md → plan/system.md} +78 -78
  78. package/templates/{planUser.md → plan/user.md} +10 -9
  79. package/templates/{scanSystem.md → scan/system.md} +120 -120
  80. package/templates/{scanUser.md → scan/user.md} +10 -10
  81. package/types/index.d.ts +217 -217
@@ -1,125 +1,147 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
-
5
- const COLOR = {
6
- red: '\x1b[0;31m',
7
- green: '\x1b[0;32m',
8
- yellow: '\x1b[1;33m',
9
- blue: '\x1b[0;34m',
10
- magenta: '\x1b[0;35m',
11
- cyan: '\x1b[0;36m',
12
- bold: '\x1b[1m',
13
- dim: '\x1b[2m',
14
- reset: '\x1b[0m',
15
- };
16
-
17
- function log(level, msg) {
18
- const tags = {
19
- info: `${COLOR.blue}[INFO]${COLOR.reset} `,
20
- ok: `${COLOR.green}[OK]${COLOR.reset} `,
21
- warn: `${COLOR.yellow}[WARN]${COLOR.reset} `,
22
- error: `${COLOR.red}[ERROR]${COLOR.reset}`,
23
- };
24
- console.error(`${tags[level] || ''} ${msg} \n`);
25
- }
26
-
27
- // --------------- .env parsing ---------------
28
-
29
- function parseEnvFile(filepath) {
30
- if (!fs.existsSync(filepath)) return {};
31
- const content = fs.readFileSync(filepath, 'utf8');
32
- const vars = {};
33
- for (const line of content.split('\n')) {
34
- const trimmed = line.trim();
35
- if (!trimmed || trimmed.startsWith('#')) continue;
36
- const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
37
- if (match) {
38
- vars[match[1]] = match[2].trim().replace(/^["']|["']$/g, '');
39
- }
40
- }
41
- return vars;
42
- }
43
-
44
- // --------------- Model mapping ---------------
45
-
46
- function loadConfig() {
47
- const { assets } = require('./assets');
48
- const envPath = assets.path('env');
49
- const env = envPath ? parseEnvFile(envPath) : {};
50
- const config = {
51
- provider: env.MODEL_PROVIDER || 'claude',
52
- baseUrl: env.ANTHROPIC_BASE_URL || '',
53
- apiKey: env.ANTHROPIC_API_KEY || '',
54
- authToken: env.ANTHROPIC_AUTH_TOKEN || '',
55
- model: env.ANTHROPIC_MODEL || '',
56
- timeoutMs: parseInt(env.API_TIMEOUT_MS, 10) || 3000000,
57
- webTestTool: env.WEB_TEST_TOOL || '',
58
- webTestMode: env.WEB_TEST_MODE || 'persistent',
59
- disableNonessential: env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC || '',
60
- effortLevel: env.CLAUDE_CODE_EFFORT_LEVEL || '',
61
- defaultOpus: env.ANTHROPIC_DEFAULT_OPUS_MODEL || '',
62
- defaultSonnet: env.ANTHROPIC_DEFAULT_SONNET_MODEL || '',
63
- defaultHaiku: env.ANTHROPIC_DEFAULT_HAIKU_MODEL || '',
64
- thinkingBudget: env.ANTHROPIC_THINKING_BUDGET || '',
65
- stallTimeout: parseInt(env.SESSION_STALL_TIMEOUT, 10) || 600,
66
- completionTimeout: parseInt(env.SESSION_COMPLETION_TIMEOUT, 10) || 300,
67
- maxTurns: parseInt(env.SESSION_MAX_TURNS, 10) || 0,
68
- editThreshold: parseInt(env.EDIT_THRESHOLD, 10) || 15,
69
- simplifyInterval: env.SIMPLIFY_INTERVAL !== undefined ? parseInt(env.SIMPLIFY_INTERVAL, 10) : 5,
70
- simplifyCommits: env.SIMPLIFY_COMMITS !== undefined ? parseInt(env.SIMPLIFY_COMMITS, 10) : 5,
71
- raw: env,
72
- };
73
-
74
- // 以下是兼容deepseek最实惠的而改写的配置,不一定正确。只是多次调用后得出的结果。
75
- if (config.baseUrl && config.baseUrl.includes('deepseek') && config.model === 'deepseek-chat') {
76
- config.model = 'claude-3-haiku-20240307';
77
- config.defaultOpus = 'claude-3-haiku-20240307';
78
- config.defaultSonnet = 'claude-3-haiku-20240307';
79
- config.defaultHaiku = 'claude-3-haiku-20240307';
80
- config.thinkingBudget = '0';
81
- }
82
-
83
- return config;
84
- }
85
-
86
- function buildEnvVars(config) {
87
- const env = { ...process.env };
88
- if (config.baseUrl) env.ANTHROPIC_BASE_URL = config.baseUrl;
89
- if (config.apiKey) env.ANTHROPIC_API_KEY = config.apiKey;
90
- if (config.authToken) env.ANTHROPIC_AUTH_TOKEN = config.authToken;
91
- if (config.model) env.ANTHROPIC_MODEL = config.model;
92
- if (config.timeoutMs) env.API_TIMEOUT_MS = String(config.timeoutMs);
93
- if (config.disableNonessential) env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = config.disableNonessential;
94
- if (config.effortLevel) env.CLAUDE_CODE_EFFORT_LEVEL = config.effortLevel;
95
- if (config.defaultOpus) env.ANTHROPIC_DEFAULT_OPUS_MODEL = config.defaultOpus;
96
- if (config.defaultSonnet) env.ANTHROPIC_DEFAULT_SONNET_MODEL = config.defaultSonnet;
97
- if (config.defaultHaiku) env.ANTHROPIC_DEFAULT_HAIKU_MODEL = config.defaultHaiku;
98
- if (config.thinkingBudget) env.ANTHROPIC_THINKING_BUDGET = config.thinkingBudget;
99
- return env;
100
- }
101
-
102
- function updateEnvVar(key, value) {
103
- const { assets } = require('./assets');
104
- const envPath = assets.path('env');
105
- if (!envPath || !fs.existsSync(envPath)) return false;
106
- let content = fs.readFileSync(envPath, 'utf8');
107
- const regex = new RegExp(`^${key}=.*$`, 'm');
108
- if (regex.test(content)) {
109
- content = content.replace(regex, `${key}=${value}`);
110
- } else {
111
- const suffix = content.endsWith('\n') ? '' : '\n';
112
- content += `${suffix}${key}=${value}\n`;
113
- }
114
- fs.writeFileSync(envPath, content, 'utf8');
115
- return true;
116
- }
117
-
118
- module.exports = {
119
- COLOR,
120
- log,
121
- parseEnvFile,
122
- loadConfig,
123
- buildEnvVars,
124
- updateEnvVar,
125
- };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+
5
+ const COLOR = {
6
+ red: '\x1b[0;31m',
7
+ green: '\x1b[0;32m',
8
+ yellow: '\x1b[1;33m',
9
+ blue: '\x1b[0;34m',
10
+ magenta: '\x1b[0;35m',
11
+ cyan: '\x1b[0;36m',
12
+ bold: '\x1b[1m',
13
+ dim: '\x1b[2m',
14
+ reset: '\x1b[0m',
15
+ };
16
+
17
+ function log(level, msg) {
18
+ const tags = {
19
+ info: `${COLOR.blue}[INFO]${COLOR.reset} `,
20
+ ok: `${COLOR.green}[OK]${COLOR.reset} `,
21
+ warn: `${COLOR.yellow}[WARN]${COLOR.reset} `,
22
+ error: `${COLOR.red}[ERROR]${COLOR.reset}`,
23
+ };
24
+ console.error(`${tags[level] || ''} ${msg} \n`);
25
+ }
26
+
27
+ // --------------- .env parsing ---------------
28
+
29
+ function parseEnvFile(filepath) {
30
+ if (!fs.existsSync(filepath)) return {};
31
+ const content = fs.readFileSync(filepath, 'utf8');
32
+ const vars = {};
33
+ for (const line of content.split('\n')) {
34
+ const trimmed = line.trim();
35
+ if (!trimmed || trimmed.startsWith('#')) continue;
36
+ const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
37
+ if (match) {
38
+ vars[match[1]] = match[2].trim().replace(/^["']|["']$/g, '');
39
+ }
40
+ }
41
+ return vars;
42
+ }
43
+
44
+ // --------------- Model mapping ---------------
45
+
46
+ function loadConfig() {
47
+ const { assets } = require('./assets');
48
+ const envPath = assets.path('env');
49
+ const env = envPath ? parseEnvFile(envPath) : {};
50
+ const config = {
51
+ provider: env.MODEL_PROVIDER || 'claude',
52
+ baseUrl: env.ANTHROPIC_BASE_URL || '',
53
+ apiKey: env.ANTHROPIC_API_KEY || '',
54
+ authToken: env.ANTHROPIC_AUTH_TOKEN || '',
55
+ model: env.ANTHROPIC_MODEL || '',
56
+ timeoutMs: parseInt(env.API_TIMEOUT_MS, 10) || 3000000,
57
+ webTestTool: env.WEB_TEST_TOOL || '',
58
+ webTestMode: env.WEB_TEST_MODE || 'persistent',
59
+ disableNonessential: env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC || '',
60
+ effortLevel: env.CLAUDE_CODE_EFFORT_LEVEL || '',
61
+ defaultOpus: env.ANTHROPIC_DEFAULT_OPUS_MODEL || '',
62
+ defaultSonnet: env.ANTHROPIC_DEFAULT_SONNET_MODEL || '',
63
+ defaultHaiku: env.ANTHROPIC_DEFAULT_HAIKU_MODEL || '',
64
+ thinkingBudget: env.ANTHROPIC_THINKING_BUDGET || '',
65
+ stallTimeout: parseInt(env.SESSION_STALL_TIMEOUT, 10) || 600,
66
+ completionTimeout: parseInt(env.SESSION_COMPLETION_TIMEOUT, 10) || 300,
67
+ maxTurns: parseInt(env.SESSION_MAX_TURNS, 10) || 0,
68
+ editThreshold: parseInt(env.EDIT_THRESHOLD, 10) || 15,
69
+ simplifyInterval: env.SIMPLIFY_INTERVAL !== undefined ? parseInt(env.SIMPLIFY_INTERVAL, 10) : 5,
70
+ simplifyCommits: env.SIMPLIFY_COMMITS !== undefined ? parseInt(env.SIMPLIFY_COMMITS, 10) : 5,
71
+ raw: env,
72
+ };
73
+
74
+ // 以下是兼容deepseek最实惠的而改写的配置,不一定正确。只是多次调用后得出的结果。
75
+ if (config.baseUrl && config.baseUrl.includes('deepseek') && config.model === 'deepseek-chat') {
76
+ config.model = 'claude-3-haiku-20240307';
77
+ config.defaultOpus = 'claude-3-haiku-20240307';
78
+ config.defaultSonnet = 'claude-3-haiku-20240307';
79
+ config.defaultHaiku = 'claude-3-haiku-20240307';
80
+ config.thinkingBudget = '0';
81
+ }
82
+
83
+ return config;
84
+ }
85
+
86
+ function buildEnvVars(config) {
87
+ const env = { ...process.env };
88
+ if (config.baseUrl) env.ANTHROPIC_BASE_URL = config.baseUrl;
89
+ if (config.apiKey) env.ANTHROPIC_API_KEY = config.apiKey;
90
+ if (config.authToken) env.ANTHROPIC_AUTH_TOKEN = config.authToken;
91
+ if (config.model) env.ANTHROPIC_MODEL = config.model;
92
+ if (config.timeoutMs) env.API_TIMEOUT_MS = String(config.timeoutMs);
93
+ if (config.disableNonessential) env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = config.disableNonessential;
94
+ if (config.effortLevel) env.CLAUDE_CODE_EFFORT_LEVEL = config.effortLevel;
95
+ if (config.defaultOpus) env.ANTHROPIC_DEFAULT_OPUS_MODEL = config.defaultOpus;
96
+ if (config.defaultSonnet) env.ANTHROPIC_DEFAULT_SONNET_MODEL = config.defaultSonnet;
97
+ if (config.defaultHaiku) env.ANTHROPIC_DEFAULT_HAIKU_MODEL = config.defaultHaiku;
98
+ if (config.thinkingBudget) env.ANTHROPIC_THINKING_BUDGET = config.thinkingBudget;
99
+ return env;
100
+ }
101
+
102
+ function updateEnvVar(key, value) {
103
+ const { assets } = require('./assets');
104
+ const envPath = assets.path('env');
105
+ if (!envPath || !fs.existsSync(envPath)) return false;
106
+ let content = fs.readFileSync(envPath, 'utf8');
107
+ const regex = new RegExp(`^${key}=.*$`, 'm');
108
+ if (regex.test(content)) {
109
+ content = content.replace(regex, `${key}=${value}`);
110
+ } else {
111
+ const suffix = content.endsWith('\n') ? '' : '\n';
112
+ content += `${suffix}${key}=${value}\n`;
113
+ }
114
+ fs.writeFileSync(envPath, content, 'utf8');
115
+ return true;
116
+ }
117
+
118
+ const REPO_URL = 'https://lk19940215.github.io/claude-coder';
119
+
120
+ /**
121
+ * @param {string} command - 命令名(run / plan / design / go / simplify / scan)
122
+ * @param {string} detail - 右侧附加信息(模式、范围等)
123
+ * @param {string} [model] - 模型名
124
+ */
125
+ function printModeBanner(command, detail, model) {
126
+ const sep = ` ${COLOR.dim}│${COLOR.reset} `;
127
+ const parts = [`${COLOR.bold}Claude Coder${COLOR.reset}`, command];
128
+ if (model) parts.push(`model: ${model}`);
129
+ if (detail) parts.push(detail);
130
+ const inner = parts.join(sep);
131
+ console.error('');
132
+ console.error(`${COLOR.cyan}╔══════════════════════════════════════════════╗${COLOR.reset}`);
133
+ console.error(`${COLOR.cyan}║${COLOR.reset} ${inner}`);
134
+ console.error(`${COLOR.cyan}║${COLOR.reset} ${COLOR.dim}${REPO_URL}${COLOR.reset}`);
135
+ console.error(`${COLOR.cyan}╚══════════════════════════════════════════════╝${COLOR.reset}`);
136
+ console.error('');
137
+ }
138
+
139
+ module.exports = {
140
+ COLOR,
141
+ log,
142
+ printModeBanner,
143
+ parseEnvFile,
144
+ loadConfig,
145
+ buildEnvVars,
146
+ updateEnvVar,
147
+ };
@@ -1,56 +1,56 @@
1
- 'use strict';
2
-
3
- // ─────────────────────────────────────────────────────────────
4
- // 常量集中管理
5
- // ─────────────────────────────────────────────────────────────
6
-
7
- /**
8
- * 任务状态
9
- */
10
- const TASK_STATUSES = Object.freeze(['pending', 'in_progress', 'testing', 'done', 'failed']);
11
-
12
- /**
13
- * 状态迁移规则
14
- */
15
- const STATUS_TRANSITIONS = Object.freeze({
16
- pending: ['in_progress'],
17
- in_progress: ['testing'],
18
- testing: ['done', 'failed'],
19
- failed: ['in_progress'],
20
- done: [],
21
- });
22
-
23
- /**
24
- * 文件名常量
25
- */
26
- const FILES = Object.freeze({
27
- SESSION_RESULT: 'session_result.json',
28
- TASKS: 'tasks.json',
29
- PROFILE: 'project_profile.json',
30
- PROGRESS: 'progress.json',
31
- TEST_ENV: 'test.env',
32
- PLAYWRIGHT_AUTH: 'playwright-auth.json',
33
- ENV: '.env',
34
- MCP_CONFIG: '.mcp.json',
35
- });
36
-
37
- /**
38
- * 重试配置
39
- */
40
- const RETRY = Object.freeze({
41
- MAX_ATTEMPTS: 3,
42
- SCAN_ATTEMPTS: 3,
43
- });
44
-
45
- /**
46
- * 编辑防护阈值
47
- */
48
- const EDIT_THRESHOLD = 15;
49
-
50
- module.exports = {
51
- TASK_STATUSES,
52
- STATUS_TRANSITIONS,
53
- FILES,
54
- RETRY,
55
- EDIT_THRESHOLD,
1
+ 'use strict';
2
+
3
+ // ─────────────────────────────────────────────────────────────
4
+ // 常量集中管理
5
+ // ─────────────────────────────────────────────────────────────
6
+
7
+ /**
8
+ * 任务状态
9
+ */
10
+ const TASK_STATUSES = Object.freeze(['pending', 'in_progress', 'testing', 'done', 'failed']);
11
+
12
+ /**
13
+ * 状态迁移规则
14
+ */
15
+ const STATUS_TRANSITIONS = Object.freeze({
16
+ pending: ['in_progress'],
17
+ in_progress: ['testing'],
18
+ testing: ['done', 'failed'],
19
+ failed: ['in_progress'],
20
+ done: [],
21
+ });
22
+
23
+ /**
24
+ * 文件名常量
25
+ */
26
+ const FILES = Object.freeze({
27
+ SESSION_RESULT: 'session_result.json',
28
+ TASKS: 'tasks.json',
29
+ PROFILE: 'project_profile.json',
30
+ PROGRESS: 'progress.json',
31
+ TEST_ENV: 'test.env',
32
+ PLAYWRIGHT_AUTH: 'playwright-auth.json',
33
+ ENV: '.env',
34
+ MCP_CONFIG: '.mcp.json',
35
+ });
36
+
37
+ /**
38
+ * 重试配置
39
+ */
40
+ const RETRY = Object.freeze({
41
+ MAX_ATTEMPTS: 3,
42
+ SCAN_ATTEMPTS: 3,
43
+ });
44
+
45
+ /**
46
+ * 编辑防护阈值
47
+ */
48
+ const EDIT_THRESHOLD = 15;
49
+
50
+ module.exports = {
51
+ TASK_STATUSES,
52
+ STATUS_TRANSITIONS,
53
+ FILES,
54
+ RETRY,
55
+ EDIT_THRESHOLD,
56
56
  };