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/plan.js CHANGED
@@ -1,187 +1,188 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const readline = require('readline');
7
- const { buildSystemPrompt, buildPlanPrompt } = require('./prompts');
8
- const { log } = require('../common/config');
9
- const { assets } = require('../common/assets');
10
- const { printStats } = require('../common/tasks');
11
- const { syncAfterPlan } = require('./state');
12
- const { Session } = require('./session');
13
-
14
- const PLANS_DIR = path.join(os.homedir(), '.claude', 'plans');
15
-
16
- function buildPlanOnlySystem(opts = {}) {
17
- const interactive = opts.interactive || false;
18
- const interactionRule = interactive
19
- ? '如有不确定的关键决策点,使用 AskUserQuestion 工具向用户提问,对话确认方案。'
20
- : '不要提问,默认使用最佳推荐方案。';
21
-
22
- return `你是一个资深技术架构师。根据用户需求,探索项目代码库后输出完整的技术方案文档。
23
-
24
- 【流程】
25
- 1. 探索项目代码库,理解结构和技术栈
26
- 2. ${interactionRule}
27
- 3. 使用 Write 工具将完整计划写入 ~/.claude/plans/ 目录(.md 格式)
28
- 4. 写入后输出标记(独占一行):PLAN_FILE_PATH: <计划文件绝对路径>
29
- 5. 简要总结计划要点`;
30
- }
31
-
32
- function buildPlanOnlyPrompt(instruction, opts = {}) {
33
- const reqFile = opts.reqFile || null;
34
- return reqFile
35
- ? `需求文件路径: ${reqFile}\n先读取该文件,理解用户需求和约束。`
36
- : instruction;
37
- }
38
-
39
- function copyPlanToProject(generatedPath) {
40
- const filename = path.basename(generatedPath);
41
- const targetDir = path.join(assets.projectRoot, '.claude-coder', 'plan');
42
- const targetPath = path.join(targetDir, filename);
43
-
44
- try {
45
- if (!fs.existsSync(targetDir)) {
46
- fs.mkdirSync(targetDir, { recursive: true });
47
- }
48
- fs.copyFileSync(generatedPath, targetPath);
49
- return targetPath;
50
- } catch {
51
- return generatedPath;
52
- }
53
- }
54
-
55
- async function _executePlanGen(session, instruction, opts = {}) {
56
- const interactive = opts.interactive || false;
57
- const prompt = buildPlanOnlyPrompt(instruction, opts);
58
- const queryOpts = {
59
- permissionMode: 'plan',
60
- systemPrompt: buildPlanOnlySystem(opts),
61
- cwd: opts.projectRoot || assets.projectRoot,
62
- hooks: session.hooks,
63
- };
64
- if (!interactive) {
65
- queryOpts.disallowedTools = ['askUserQuestion'];
66
- }
67
- if (opts.model) queryOpts.model = opts.model;
68
-
69
- let capturedPlanPath = null;
70
-
71
- const { success } = await session.runQuery(prompt, queryOpts, {
72
- onMessage(message) {
73
- if (message.type !== 'assistant' || !message.message?.content) return;
74
- for (const block of message.message.content) {
75
- if (block.type === 'tool_use' && block.name === 'Write') {
76
- const target = block.input?.file_path || block.input?.path || '';
77
- if (target.includes('.claude/plans/') && target.endsWith('.md')) {
78
- capturedPlanPath = target;
79
- }
80
- }
81
- }
82
- },
83
- });
84
-
85
- if (!success) {
86
- log('warn', '计划生成查询未正常结束');
87
- }
88
-
89
- if (capturedPlanPath && fs.existsSync(capturedPlanPath)) {
90
- const targetPath = copyPlanToProject(capturedPlanPath);
91
- return { success: true, targetPath, generatedPath: capturedPlanPath };
92
- }
93
-
94
- log('warn', '无法从输出中提取计划路径');
95
- log('info', `请手动查看: ${PLANS_DIR}`);
96
- return { success: false, reason: 'no_path', targetPath: null };
97
- }
98
-
99
- async function promptAutoRun() {
100
- if (!process.stdin.isTTY) return false;
101
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
102
- return new Promise(resolve => {
103
- rl.question('任务分解完成后是否自动开始执行?(y/n) ', answer => {
104
- rl.close();
105
- resolve(/^[Yy]/.test(answer.trim()));
106
- });
107
- });
108
- }
109
-
110
- // ─── Main Entry ──────────────────────────────────────────
111
-
112
- async function executePlan(config, input, opts = {}) {
113
- const instruction = input || '';
114
-
115
- if (opts.reqFile && instruction) {
116
- log('info', `-r 模式下忽略文本输入,使用需求文件: ${opts.reqFile}`);
117
- } else if (opts.reqFile) {
118
- console.log(`需求文件: ${opts.reqFile}`);
119
- }
120
-
121
- if (!instruction && !opts.reqFile) {
122
- throw new Error('用法: claude-coder plan "需求内容" 或 claude-coder plan -r [requirements.md]');
123
- }
124
-
125
- if (opts.interactive) {
126
- log('info', '交互模式已启用,模型可能会向您提问');
127
- }
128
-
129
- let shouldAutoRun = false;
130
- if (!opts.planOnly) {
131
- shouldAutoRun = await promptAutoRun();
132
- }
133
-
134
- const hookType = opts.interactive ? 'plan_interactive' : 'plan';
135
- const ts = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 12);
136
- const label = opts.planOnly ? 'plan_only' : 'plan_tasks';
137
-
138
- const result = await Session.run(hookType, config, {
139
- logFileName: `plan_${ts}.log`,
140
- label,
141
-
142
- async execute(session) {
143
- log('info', '正在生成计划方案...');
144
-
145
- const planResult = await _executePlanGen(session, instruction, opts);
146
-
147
- if (!planResult.success) {
148
- log('error', `\n计划生成失败: ${planResult.reason || planResult.error}`);
149
- return { success: false, reason: planResult.reason };
150
- }
151
-
152
- log('ok', `\n计划已生成: ${planResult.targetPath}`);
153
-
154
- if (opts.planOnly) {
155
- return { success: true, planPath: planResult.targetPath };
156
- }
157
-
158
- log('info', '正在生成任务列表...');
159
-
160
- const tasksPrompt = buildPlanPrompt(planResult.targetPath);
161
- const queryOpts = session.buildQueryOptions(opts);
162
- queryOpts.systemPrompt = buildSystemPrompt('plan');
163
-
164
- const { success } = await session.runQuery(tasksPrompt, queryOpts);
165
- if (!success) {
166
- log('warn', '任务分解查询未正常结束');
167
- }
168
-
169
- syncAfterPlan();
170
- log('ok', '任务追加完成');
171
- return { success: true, planPath: planResult.targetPath };
172
- },
173
- });
174
-
175
- if (result.success) {
176
- printStats();
177
-
178
- if (shouldAutoRun) {
179
- console.log('');
180
- log('info', '开始自动执行任务...');
181
- const { executeRun } = require('./runner');
182
- await executeRun(config, opts);
183
- }
184
- }
185
- }
186
-
187
- module.exports = { executePlan };
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const readline = require('readline');
7
+ const { buildSystemPrompt, buildPlanPrompt } = require('./prompts');
8
+ const { log } = require('../common/config');
9
+ const { assets } = require('../common/assets');
10
+ const { printStats } = require('../common/tasks');
11
+ const { syncAfterPlan } = require('./state');
12
+ const { Session } = require('./session');
13
+
14
+ const PLANS_DIR = path.join(os.homedir(), '.claude', 'plans');
15
+
16
+ function buildPlanOnlySystem(opts = {}) {
17
+ const interactive = opts.interactive || false;
18
+ const interactionRule = interactive
19
+ ? '如有不确定的关键决策点,使用 AskUserQuestion 工具向用户提问,对话确认方案。'
20
+ : '不要提问,默认使用最佳推荐方案。';
21
+
22
+ return `你是一个资深技术架构师。根据用户需求,探索项目代码库后输出完整的技术方案文档。
23
+
24
+ 【流程】
25
+ 1. 探索项目代码库,理解结构和技术栈
26
+ 2. ${interactionRule}
27
+ 3. 使用 Write 工具将完整计划写入 ~/.claude/plans/ 目录(.md 格式)
28
+ 4. 写入后输出标记(独占一行):PLAN_FILE_PATH: <计划文件绝对路径>
29
+ 5. 简要总结计划要点`;
30
+ }
31
+
32
+ function buildPlanOnlyPrompt(instruction, opts = {}) {
33
+ const reqFile = opts.reqFile || null;
34
+ return reqFile
35
+ ? `需求文件路径: ${reqFile}\n先读取该文件,理解用户需求和约束。`
36
+ : instruction;
37
+ }
38
+
39
+ function copyPlanToProject(generatedPath) {
40
+ const filename = path.basename(generatedPath);
41
+ const targetDir = path.join(assets.projectRoot, '.claude-coder', 'plan');
42
+ const targetPath = path.join(targetDir, filename);
43
+
44
+ try {
45
+ if (!fs.existsSync(targetDir)) {
46
+ fs.mkdirSync(targetDir, { recursive: true });
47
+ }
48
+ fs.copyFileSync(generatedPath, targetPath);
49
+ return targetPath;
50
+ } catch {
51
+ return generatedPath;
52
+ }
53
+ }
54
+
55
+ async function _executePlanGen(session, instruction, opts = {}) {
56
+ const interactive = opts.interactive || false;
57
+ const prompt = buildPlanOnlyPrompt(instruction, opts);
58
+ const queryOpts = {
59
+ permissionMode: 'plan',
60
+ systemPrompt: buildPlanOnlySystem(opts),
61
+ cwd: opts.projectRoot || assets.projectRoot,
62
+ hooks: session.hooks,
63
+ };
64
+ if (!interactive) {
65
+ queryOpts.disallowedTools = ['askUserQuestion'];
66
+ }
67
+ if (opts.model) queryOpts.model = opts.model;
68
+
69
+ let capturedPlanPath = null;
70
+
71
+ const { success } = await session.runQuery(prompt, queryOpts, {
72
+ onMessage(message) {
73
+ if (message.type !== 'assistant' || !message.message?.content) return;
74
+ for (const block of message.message.content) {
75
+ if (block.type === 'tool_use' && block.name === 'Write') {
76
+ const target = block.input?.file_path || block.input?.path || '';
77
+ const normalized = target.replace(/\\/g, '/');
78
+ if (normalized.includes('.claude/plans/') && normalized.endsWith('.md')) {
79
+ capturedPlanPath = target;
80
+ }
81
+ }
82
+ }
83
+ },
84
+ });
85
+
86
+ if (!success) {
87
+ log('warn', '计划生成查询未正常结束');
88
+ }
89
+
90
+ if (capturedPlanPath && fs.existsSync(capturedPlanPath)) {
91
+ const targetPath = copyPlanToProject(capturedPlanPath);
92
+ return { success: true, targetPath, generatedPath: capturedPlanPath };
93
+ }
94
+
95
+ log('warn', '无法从输出中提取计划路径');
96
+ log('info', `请手动查看: ${PLANS_DIR}`);
97
+ return { success: false, reason: 'no_path', targetPath: null };
98
+ }
99
+
100
+ async function promptAutoRun() {
101
+ if (!process.stdin.isTTY) return false;
102
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
103
+ return new Promise(resolve => {
104
+ rl.question('任务分解完成后是否自动开始执行?(y/n) ', answer => {
105
+ rl.close();
106
+ resolve(/^[Yy]/.test(answer.trim()));
107
+ });
108
+ });
109
+ }
110
+
111
+ // ─── Main Entry ──────────────────────────────────────────
112
+
113
+ async function executePlan(config, input, opts = {}) {
114
+ const instruction = input || '';
115
+
116
+ if (opts.reqFile && instruction) {
117
+ log('info', `-r 模式下忽略文本输入,使用需求文件: ${opts.reqFile}`);
118
+ } else if (opts.reqFile) {
119
+ console.log(`需求文件: ${opts.reqFile}`);
120
+ }
121
+
122
+ if (!instruction && !opts.reqFile) {
123
+ throw new Error('用法: claude-coder plan "需求内容" 或 claude-coder plan -r [requirements.md]');
124
+ }
125
+
126
+ if (opts.interactive) {
127
+ log('info', '交互模式已启用,模型可能会向您提问');
128
+ }
129
+
130
+ let shouldAutoRun = false;
131
+ if (!opts.planOnly) {
132
+ shouldAutoRun = await promptAutoRun();
133
+ }
134
+
135
+ const hookType = opts.interactive ? 'plan_interactive' : 'plan';
136
+ const ts = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 12);
137
+ const label = opts.planOnly ? 'plan_only' : 'plan_tasks';
138
+
139
+ const result = await Session.run(hookType, config, {
140
+ logFileName: `plan_${ts}.log`,
141
+ label,
142
+
143
+ async execute(session) {
144
+ log('info', '正在生成计划方案...');
145
+
146
+ const planResult = await _executePlanGen(session, instruction, opts);
147
+
148
+ if (!planResult.success) {
149
+ log('error', `\n计划生成失败: ${planResult.reason || planResult.error}`);
150
+ return { success: false, reason: planResult.reason };
151
+ }
152
+
153
+ log('ok', `\n计划已生成: ${planResult.targetPath}`);
154
+
155
+ if (opts.planOnly) {
156
+ return { success: true, planPath: planResult.targetPath };
157
+ }
158
+
159
+ log('info', '正在生成任务列表...');
160
+
161
+ const tasksPrompt = buildPlanPrompt(planResult.targetPath);
162
+ const queryOpts = session.buildQueryOptions(opts);
163
+ queryOpts.systemPrompt = buildSystemPrompt('plan');
164
+
165
+ const { success } = await session.runQuery(tasksPrompt, queryOpts);
166
+ if (!success) {
167
+ log('warn', '任务分解查询未正常结束');
168
+ }
169
+
170
+ syncAfterPlan();
171
+ log('ok', '任务追加完成');
172
+ return { success: true, planPath: planResult.targetPath };
173
+ },
174
+ });
175
+
176
+ if (result.success) {
177
+ printStats();
178
+
179
+ if (shouldAutoRun) {
180
+ console.log('');
181
+ log('info', '开始自动执行任务...');
182
+ const { executeRun } = require('./runner');
183
+ await executeRun(config, opts);
184
+ }
185
+ }
186
+ }
187
+
188
+ module.exports = { executePlan };