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.
- package/README.md +236 -214
- package/bin/cli.js +170 -155
- package/package.json +55 -55
- package/recipes/_shared/roles/developer.md +11 -11
- package/recipes/_shared/roles/product.md +12 -12
- package/recipes/_shared/roles/tester.md +12 -12
- package/recipes/_shared/test/report-format.md +86 -86
- package/recipes/backend/base.md +27 -27
- package/recipes/backend/components/auth.md +18 -18
- package/recipes/backend/components/crud-api.md +18 -18
- package/recipes/backend/components/file-service.md +15 -15
- package/recipes/backend/manifest.json +20 -20
- package/recipes/backend/test/api-test.md +25 -25
- package/recipes/console/base.md +37 -37
- package/recipes/console/components/modal-form.md +20 -20
- package/recipes/console/components/pagination.md +17 -17
- package/recipes/console/components/search.md +17 -17
- package/recipes/console/components/table-list.md +18 -18
- package/recipes/console/components/tabs.md +14 -14
- package/recipes/console/components/tree.md +15 -15
- package/recipes/console/components/upload.md +15 -15
- package/recipes/console/manifest.json +24 -24
- package/recipes/console/test/crud-e2e.md +47 -47
- package/recipes/h5/base.md +26 -26
- package/recipes/h5/components/animation.md +11 -11
- package/recipes/h5/components/countdown.md +11 -11
- package/recipes/h5/components/share.md +11 -11
- package/recipes/h5/components/swiper.md +11 -11
- package/recipes/h5/manifest.json +21 -21
- package/recipes/h5/test/h5-e2e.md +20 -20
- package/src/commands/auth.js +420 -420
- package/src/commands/setup-modules/helpers.js +100 -100
- package/src/commands/setup-modules/index.js +25 -25
- package/src/commands/setup-modules/mcp.js +115 -115
- package/src/commands/setup-modules/provider.js +260 -260
- package/src/commands/setup-modules/safety.js +47 -47
- package/src/commands/setup-modules/simplify.js +52 -52
- package/src/commands/setup.js +172 -172
- package/src/common/assets.js +259 -245
- package/src/common/config.js +147 -125
- package/src/common/constants.js +55 -55
- package/src/common/indicator.js +260 -260
- package/src/common/interaction.js +170 -170
- package/src/common/logging.js +77 -77
- package/src/common/sdk.js +48 -50
- package/src/common/tasks.js +88 -88
- package/src/common/utils.js +214 -213
- package/src/core/coding.js +35 -33
- package/src/core/design.js +268 -0
- package/src/core/go.js +264 -264
- package/src/core/hooks.js +514 -500
- package/src/core/init.js +175 -166
- package/src/core/plan.js +194 -188
- package/src/core/prompts.js +292 -247
- package/src/core/repair.js +36 -36
- package/src/core/runner.js +471 -471
- package/src/core/scan.js +94 -93
- package/src/core/session.js +294 -280
- package/src/core/simplify.js +76 -74
- package/src/core/state.js +120 -105
- package/src/index.js +80 -76
- package/templates/{codingSystem.md → coding/system.md} +65 -65
- package/templates/{codingUser.md → coding/user.md} +18 -17
- package/templates/design/base.md +103 -0
- package/templates/design/fixSystem.md +71 -0
- package/templates/design/fixUser.md +3 -0
- package/templates/design/init.md +304 -0
- package/templates/design/system.md +108 -0
- package/templates/design/user.md +11 -0
- package/templates/{goSystem.md → go/system.md} +130 -130
- package/templates/{bash-process.md → other/bash-process.md} +12 -12
- package/templates/{coreProtocol.md → other/coreProtocol.md} +30 -29
- package/templates/{guidance.json → other/guidance.json} +72 -72
- package/templates/{requirements.example.md → other/requirements.example.md} +57 -57
- package/templates/{test_rule.md → other/test_rule.md} +192 -194
- package/templates/{web-testing.md → other/web-testing.md} +17 -17
- package/templates/{planSystem.md → plan/system.md} +78 -78
- package/templates/{planUser.md → plan/user.md} +10 -9
- package/templates/{scanSystem.md → scan/system.md} +120 -120
- package/templates/{scanUser.md → scan/user.md} +10 -10
- package/types/index.d.ts +217 -217
package/src/core/plan.js
CHANGED
|
@@ -1,188 +1,194 @@
|
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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, printModeBanner } = 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
|
+
- \`.claude-coder/project_profile.json\` — 项目元数据
|
|
33
|
+
- \`.claude-coder/design/\` — UI 设计稿目录(design_map.json 索引 + .pen 设计文件),存在时应在方案中参考`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function buildPlanOnlyPrompt(instruction, opts = {}) {
|
|
37
|
+
const reqFile = opts.reqFile || null;
|
|
38
|
+
return reqFile
|
|
39
|
+
? `需求文件路径: ${reqFile}\n先读取该文件,理解用户需求和约束。`
|
|
40
|
+
: instruction;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function copyPlanToProject(generatedPath) {
|
|
44
|
+
const filename = path.basename(generatedPath);
|
|
45
|
+
const targetDir = path.join(assets.projectRoot, '.claude-coder', 'plan');
|
|
46
|
+
const targetPath = path.join(targetDir, filename);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
if (!fs.existsSync(targetDir)) {
|
|
50
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
fs.copyFileSync(generatedPath, targetPath);
|
|
53
|
+
return targetPath;
|
|
54
|
+
} catch {
|
|
55
|
+
return generatedPath;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function _executePlanGen(session, instruction, opts = {}) {
|
|
60
|
+
const interactive = opts.interactive || false;
|
|
61
|
+
const prompt = buildPlanOnlyPrompt(instruction, opts);
|
|
62
|
+
const queryOpts = {
|
|
63
|
+
permissionMode: 'plan',
|
|
64
|
+
systemPrompt: buildPlanOnlySystem(opts),
|
|
65
|
+
cwd: opts.projectRoot || assets.projectRoot,
|
|
66
|
+
hooks: session.hooks,
|
|
67
|
+
};
|
|
68
|
+
if (!interactive) {
|
|
69
|
+
queryOpts.disallowedTools = ['askUserQuestion'];
|
|
70
|
+
}
|
|
71
|
+
if (opts.model) queryOpts.model = opts.model;
|
|
72
|
+
|
|
73
|
+
let capturedPlanPath = null;
|
|
74
|
+
|
|
75
|
+
const { success } = await session.runQuery(prompt, queryOpts, {
|
|
76
|
+
onMessage(message) {
|
|
77
|
+
if (message.type !== 'assistant' || !message.message?.content) return;
|
|
78
|
+
for (const block of message.message.content) {
|
|
79
|
+
if (block.type === 'tool_use' && block.name === 'Write') {
|
|
80
|
+
const target = block.input?.file_path || block.input?.path || '';
|
|
81
|
+
const normalized = target.replace(/\\/g, '/');
|
|
82
|
+
if (normalized.includes('.claude/plans/') && normalized.endsWith('.md')) {
|
|
83
|
+
capturedPlanPath = target;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (!success) {
|
|
91
|
+
log('warn', '计划生成查询未正常结束');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (capturedPlanPath && fs.existsSync(capturedPlanPath)) {
|
|
95
|
+
const targetPath = copyPlanToProject(capturedPlanPath);
|
|
96
|
+
return { success: true, targetPath, generatedPath: capturedPlanPath };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
log('warn', '无法从输出中提取计划路径');
|
|
100
|
+
log('info', `请手动查看: ${PLANS_DIR}`);
|
|
101
|
+
return { success: false, reason: 'no_path', targetPath: null };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function _askLine(question) {
|
|
105
|
+
if (!process.stdin.isTTY) return Promise.resolve('');
|
|
106
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
107
|
+
return new Promise(resolve => {
|
|
108
|
+
rl.question(question, answer => { rl.close(); resolve(answer.trim()); });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function promptAutoRun() {
|
|
113
|
+
const answer = await _askLine('任务分解完成后是否自动开始执行?(y/n) ');
|
|
114
|
+
return /^[Yy]/.test(answer);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ─── Main Entry ──────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
async function executePlan(config, input, opts = {}) {
|
|
120
|
+
const instruction = input || '';
|
|
121
|
+
|
|
122
|
+
if (opts.reqFile && instruction) {
|
|
123
|
+
log('info', `-r 模式下忽略文本输入,使用需求文件: ${opts.reqFile}`);
|
|
124
|
+
} else if (opts.reqFile) {
|
|
125
|
+
console.log(`需求文件: ${opts.reqFile}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!instruction && !opts.reqFile) {
|
|
129
|
+
throw new Error('用法: claude-coder plan "需求内容" 或 claude-coder plan -r [requirements.md]');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const modeLabel = opts.planOnly ? 'planOnly' : opts.interactive ? '交互模式' : '自动模式';
|
|
133
|
+
printModeBanner('plan', modeLabel, config?.model);
|
|
134
|
+
|
|
135
|
+
let shouldAutoRun = false;
|
|
136
|
+
if (!opts.planOnly) {
|
|
137
|
+
shouldAutoRun = await promptAutoRun();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const hookType = opts.interactive ? 'plan_interactive' : 'plan';
|
|
141
|
+
const ts = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 12);
|
|
142
|
+
const label = opts.planOnly ? 'plan_only' : 'plan_tasks';
|
|
143
|
+
|
|
144
|
+
const result = await Session.run(hookType, config, {
|
|
145
|
+
logFileName: `plan_${ts}.log`,
|
|
146
|
+
label,
|
|
147
|
+
|
|
148
|
+
async execute(session) {
|
|
149
|
+
log('info', '正在生成计划方案...');
|
|
150
|
+
|
|
151
|
+
const planResult = await _executePlanGen(session, instruction, opts);
|
|
152
|
+
|
|
153
|
+
if (!planResult.success) {
|
|
154
|
+
log('error', `\n计划生成失败: ${planResult.reason}`);
|
|
155
|
+
return { success: false, reason: planResult.reason };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
log('ok', `\n计划已生成: ${planResult.targetPath}`);
|
|
159
|
+
|
|
160
|
+
if (opts.planOnly) {
|
|
161
|
+
return { success: true, planPath: planResult.targetPath };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
log('info', '正在生成任务列表...');
|
|
165
|
+
|
|
166
|
+
const tasksPrompt = buildPlanPrompt(planResult.targetPath);
|
|
167
|
+
const queryOpts = session.buildQueryOptions(opts);
|
|
168
|
+
queryOpts.systemPrompt = buildSystemPrompt('plan');
|
|
169
|
+
|
|
170
|
+
const { success } = await session.runQuery(tasksPrompt, queryOpts, { continue: true });
|
|
171
|
+
if (!success) {
|
|
172
|
+
log('warn', '任务分解查询未正常结束');
|
|
173
|
+
return { success: false, reason: '任务分解未正常完成' };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
syncAfterPlan();
|
|
177
|
+
log('ok', '任务追加完成');
|
|
178
|
+
return { success: true, planPath: planResult.targetPath };
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (result.success) {
|
|
183
|
+
printStats();
|
|
184
|
+
|
|
185
|
+
if (shouldAutoRun) {
|
|
186
|
+
console.log('');
|
|
187
|
+
log('info', '开始自动执行任务(沿用会话上下文)...');
|
|
188
|
+
const { executeRun } = require('./runner');
|
|
189
|
+
await executeRun(config, { ...opts });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = { executePlan };
|