claude-coder 1.7.0 → 1.8.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 (52) hide show
  1. package/README.md +177 -125
  2. package/bin/cli.js +159 -161
  3. package/package.json +52 -47
  4. package/src/commands/auth.js +294 -0
  5. package/src/commands/setup-modules/helpers.js +105 -0
  6. package/src/commands/setup-modules/index.js +26 -0
  7. package/src/commands/setup-modules/mcp.js +95 -0
  8. package/src/commands/setup-modules/provider.js +261 -0
  9. package/src/commands/setup-modules/safety.js +62 -0
  10. package/src/commands/setup-modules/simplify.js +53 -0
  11. package/src/commands/setup.js +172 -0
  12. package/src/common/assets.js +192 -0
  13. package/src/{config.js → common/config.js} +138 -201
  14. package/src/common/constants.js +57 -0
  15. package/src/{indicator.js → common/indicator.js} +222 -217
  16. package/src/common/interaction.js +170 -0
  17. package/src/common/logging.js +77 -0
  18. package/src/common/sdk.js +51 -0
  19. package/src/{tasks.js → common/tasks.js} +157 -172
  20. package/src/common/utils.js +147 -0
  21. package/src/core/base.js +54 -0
  22. package/src/core/coding.js +55 -0
  23. package/src/core/context.js +132 -0
  24. package/src/core/hooks.js +529 -0
  25. package/src/{init.js → core/init.js} +163 -144
  26. package/src/core/plan.js +318 -0
  27. package/src/core/prompts.js +253 -0
  28. package/src/core/query.js +48 -0
  29. package/src/core/repair.js +58 -0
  30. package/src/{runner.js → core/runner.js} +352 -420
  31. package/src/core/scan.js +89 -0
  32. package/src/core/simplify.js +59 -0
  33. package/src/core/validator.js +138 -0
  34. package/{prompts/ADD_GUIDE.md → templates/addGuide.md} +98 -98
  35. package/templates/addUser.md +26 -0
  36. package/{prompts/CLAUDE.md → templates/agentProtocol.md} +195 -199
  37. package/templates/bash-process.md +5 -0
  38. package/{prompts/coding_user.md → templates/codingUser.md} +31 -23
  39. package/templates/guidance.json +35 -0
  40. package/templates/playwright.md +17 -0
  41. package/templates/requirements.example.md +56 -56
  42. package/{prompts/SCAN_PROTOCOL.md → templates/scanProtocol.md} +118 -118
  43. package/{prompts/scan_user.md → templates/scanUser.md} +17 -17
  44. package/templates/test_rule.md +194 -194
  45. package/prompts/add_user.md +0 -24
  46. package/src/auth.js +0 -245
  47. package/src/hooks.js +0 -160
  48. package/src/prompts.js +0 -295
  49. package/src/scanner.js +0 -62
  50. package/src/session.js +0 -352
  51. package/src/setup.js +0 -579
  52. package/src/validator.js +0 -181
package/src/validator.js DELETED
@@ -1,181 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const { execSync } = require('child_process');
5
- const { paths, log, getProjectRoot } = require('./config');
6
- const { loadTasks, getFeatures } = require('./tasks');
7
-
8
- function tryExtractFromBroken(text) {
9
- const result = {};
10
-
11
- // session_result: 只能是 success 或 failed
12
- const srMatch = text.match(/"session_result"\s*:\s*"(success|failed)"/);
13
- if (srMatch) result.session_result = srMatch[1];
14
-
15
- // status_after: 可能是 pending/in_progress/testing/done/failed 或 N/A
16
- const saMatch = text.match(/"status_after"\s*:\s*"([^"]+)"/);
17
- if (saMatch) result.status_after = saMatch[1];
18
-
19
- // status_before: 同上
20
- const sbMatch = text.match(/"status_before"\s*:\s*"([^"]+)"/);
21
- if (sbMatch) result.status_before = sbMatch[1];
22
-
23
- // notes: 可选字段,字符串类型
24
- const notesMatch = text.match(/"notes"\s*:\s*"([^"]*)"/);
25
- if (notesMatch) result.notes = notesMatch[1];
26
-
27
- return Object.keys(result).length > 0 ? result : null;
28
- }
29
-
30
- function inferFromTasks(taskId) {
31
- if (!taskId) return null;
32
- const data = loadTasks();
33
- if (!data) return null;
34
- const task = getFeatures(data).find(f => f.id === taskId);
35
- return task ? task.status : null;
36
- }
37
-
38
- function validateSessionResult() {
39
- const p = paths();
40
-
41
- if (!fs.existsSync(p.sessionResult)) {
42
- log('error', 'Agent 未生成 session_result.json');
43
- return { valid: false, fatal: true, recoverable: false, reason: 'session_result.json 不存在' };
44
- }
45
-
46
- const raw = fs.readFileSync(p.sessionResult, 'utf8');
47
- let data;
48
- try {
49
- data = JSON.parse(raw);
50
- } catch (err) {
51
- log('warn', `session_result.json 解析失败: ${err.message}`);
52
- const extracted = tryExtractFromBroken(raw);
53
- if (extracted) {
54
- log('info', `从截断 JSON 中提取到关键字段: ${JSON.stringify(extracted)}`);
55
- return { valid: false, fatal: false, recoverable: true, reason: 'JSON 截断但提取到关键字段', data: extracted };
56
- }
57
- return { valid: false, fatal: false, recoverable: true, reason: `JSON 解析失败: ${err.message}` };
58
- }
59
-
60
- // Backward compat: unwrap legacy { current: {...} } format
61
- if (data.current && typeof data.current === 'object') {
62
- data = data.current;
63
- }
64
-
65
- const required = ['session_result', 'status_after'];
66
- const missing = required.filter(k => !(k in data));
67
- if (missing.length > 0) {
68
- log('warn', `session_result.json 缺少字段: ${missing.join(', ')}`);
69
- return { valid: false, fatal: false, recoverable: true, reason: `缺少字段: ${missing.join(', ')}` };
70
- }
71
-
72
- if (!['success', 'failed'].includes(data.session_result)) {
73
- log('warn', `session_result 必须是 success 或 failed,实际是: ${data.session_result}`);
74
- return { valid: false, fatal: false, recoverable: true, reason: `无效 session_result: ${data.session_result}`, data };
75
- }
76
-
77
- const validStatuses = ['pending', 'in_progress', 'testing', 'done', 'failed'];
78
- if (!validStatuses.includes(data.status_after)) {
79
- log('warn', `status_after 不合法: ${data.status_after}`);
80
- return { valid: false, fatal: false, recoverable: true, reason: `无效 status_after: ${data.status_after}`, data };
81
- }
82
-
83
- if (data.session_result === 'success') {
84
- log('ok', 'session_result.json 合法 (success)');
85
- } else {
86
- log('warn', 'session_result.json 合法,但 Agent 报告失败 (failed)');
87
- }
88
-
89
- return { valid: true, fatal: false, recoverable: false, data };
90
- }
91
-
92
- function checkGitProgress(headBefore) {
93
- if (!headBefore) {
94
- log('info', '未提供 head_before,跳过 git 检查');
95
- return { hasCommit: false, warning: false };
96
- }
97
-
98
- const projectRoot = getProjectRoot();
99
- let headAfter;
100
- try {
101
- headAfter = execSync('git rev-parse HEAD', { cwd: projectRoot, encoding: 'utf8' }).trim();
102
- } catch {
103
- headAfter = 'none';
104
- }
105
-
106
- if (headBefore === headAfter) {
107
- log('warn', '本次会话没有新的 git 提交');
108
- return { hasCommit: false, warning: true };
109
- }
110
-
111
- try {
112
- const msg = execSync('git log --oneline -1', { cwd: projectRoot, encoding: 'utf8' }).trim();
113
- log('ok', `检测到新提交: ${msg}`);
114
- } catch { /* ignore */ }
115
-
116
- return { hasCommit: true, warning: false };
117
- }
118
-
119
- function checkTestCoverage(taskId, statusAfter) {
120
- const p = paths();
121
-
122
- if (!fs.existsSync(p.testsFile)) return;
123
- if (statusAfter !== 'done' || !taskId) return;
124
-
125
- try {
126
- const tests = JSON.parse(fs.readFileSync(p.testsFile, 'utf8'));
127
- const testCases = tests.test_cases || [];
128
- const taskTests = testCases.filter(t => t.feature_id === taskId);
129
- if (taskTests.length > 0) {
130
- const failed = taskTests.filter(t => t.last_result === 'fail');
131
- if (failed.length > 0) {
132
- log('warn', `tests.json 中有失败的验证记录: ${failed.map(t => t.id).join(', ')}`);
133
- } else {
134
- log('ok', `${taskTests.length} 条验证记录覆盖任务 ${taskId}`);
135
- }
136
- }
137
- } catch { /* ignore */ }
138
- }
139
-
140
- async function validate(headBefore, taskId) {
141
- log('info', '========== 开始校验 ==========');
142
-
143
- const srResult = validateSessionResult();
144
- const gitResult = checkGitProgress(headBefore);
145
-
146
- let fatal = false;
147
- let hasWarnings = false;
148
-
149
- if (srResult.valid) {
150
- hasWarnings = gitResult.warning;
151
- } else {
152
- // session_result.json has issues — cross-validate with git + tasks.json
153
- if (gitResult.hasCommit) {
154
- const taskStatus = inferFromTasks(taskId);
155
- if (taskStatus === 'done' || taskStatus === 'testing') {
156
- log('warn', `session_result.json 异常,但 tasks.json 显示 ${taskId} 已 ${taskStatus},且有新提交,降级为警告`);
157
- } else {
158
- log('warn', 'session_result.json 异常,但有新提交,降级为警告(不回滚代码)');
159
- }
160
- hasWarnings = true;
161
- } else {
162
- log('error', '无新提交且 session_result.json 异常,视为致命');
163
- fatal = true;
164
- }
165
- }
166
-
167
- const statusAfter = srResult.data?.status_after || inferFromTasks(taskId) || null;
168
- checkTestCoverage(taskId, statusAfter);
169
-
170
- if (fatal) {
171
- log('error', '========== 校验失败 (致命) ==========');
172
- } else if (hasWarnings) {
173
- log('warn', '========== 校验通过 (有警告) ==========');
174
- } else {
175
- log('ok', '========== 校验全部通过 ==========');
176
- }
177
-
178
- return { fatal, hasWarnings, sessionData: srResult.data };
179
- }
180
-
181
- module.exports = { validate, validateSessionResult, checkGitProgress };