claude-coder 1.5.0 → 1.5.1

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 CHANGED
@@ -99,7 +99,7 @@ your-project/
99
99
  test.env # 测试凭证(API Key 等,可选)
100
100
  playwright-auth.json # Playwright 登录状态(可选,auth 命令生成)
101
101
  .runtime/ # 临时文件
102
- logs/ # 每 session 独立日志 + activity log
102
+ logs/ # 每 session 独立日志(含工具调用记录)
103
103
  requirements.md # 需求文档(可选)
104
104
  ```
105
105
 
@@ -207,7 +207,7 @@ templates/
207
207
  | `session_result.json` | 每次 session 结束 | 当前 session 结果(扁平格式,向后兼容旧 `current` 包装) |
208
208
  | `playwright-auth.json` | `claude-coder auth` | Playwright 登录状态(cookies + localStorage) |
209
209
  | `tests.json` | 首次测试时 | 验证记录(防止反复测试) |
210
- | `.runtime/` | 运行时 | 临时文件(phase、step、logs/session_N.activity.log |
210
+ | `.runtime/` | 运行时 | 临时文件(phase、step、logs/);工具调用记录合并到 session log |
211
211
 
212
212
  ---
213
213
 
@@ -450,7 +450,7 @@ query({
450
450
  ### V2 迁移条件(等待稳定后)
451
451
 
452
452
  1. V2 去掉 `unstable_` 前缀,正式发布
453
- 2. V2 支持 Hooks(当前项目依赖 PreToolUse 做 spinner 和 activity log)
453
+ 2. V2 支持 Hooks(当前项目依赖 PreToolUse 做 spinner 和日志记录)
454
454
  3. V2 支持 Subagents(未来可能用于扫描 Agent / 编码 Agent 分离)
455
455
 
456
456
  ### 可利用但尚未使用的 V1 特性
package/docs/README.en.md CHANGED
@@ -87,7 +87,7 @@ your-project/
87
87
  test.env # Test credentials (API keys, optional)
88
88
  playwright-auth.json # Playwright login state (optional, via auth command)
89
89
  .runtime/ # Temp files
90
- logs/ # Per-session logs + activity logs
90
+ logs/ # Per-session logs (with tool call traces)
91
91
  requirements.md # Requirements (optional)
92
92
  ```
93
93
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-coder",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Claude Coder — Autonomous coding agent harness powered by Claude Code SDK. Scan, plan, code, validate, git-commit in a loop.",
5
5
  "bin": {
6
6
  "claude-coder": "bin/cli.js"
package/src/indicator.js CHANGED
@@ -18,9 +18,8 @@ class Indicator {
18
18
  this.startTime = Date.now();
19
19
  }
20
20
 
21
- start(sessionNum, activityLogPath) {
21
+ start(sessionNum) {
22
22
  this.sessionNum = sessionNum;
23
- this.activityLogPath = activityLogPath || null;
24
23
  this.startTime = Date.now();
25
24
  this.timer = setInterval(() => this._render(), 500);
26
25
  }
@@ -44,14 +43,7 @@ class Indicator {
44
43
  }
45
44
 
46
45
  appendActivity(toolName, summary) {
47
- const ts = new Date().toISOString();
48
- const entry = `[${ts}] ${toolName}: ${summary}`;
49
- this.lastActivity = entry;
50
- try {
51
- if (this.activityLogPath) {
52
- fs.appendFileSync(this.activityLogPath, entry + '\n', 'utf8');
53
- }
54
- } catch { /* ignore */ }
46
+ this.lastActivity = `${toolName}: ${summary}`;
55
47
  }
56
48
 
57
49
  _writePhaseFile() {
package/src/prompts.js CHANGED
@@ -211,25 +211,83 @@ function buildScanPrompt(projectType, requirement) {
211
211
 
212
212
  /**
213
213
  * Build user prompt for add sessions.
214
+ * Structure: Role (primacy) → Context → CoT → TaskGuide → Instruction (recency)
214
215
  */
215
216
  function buildAddPrompt(instruction) {
217
+ const p = paths();
218
+ const projectRoot = getProjectRoot();
216
219
  const taskGuide = buildTaskGuide();
220
+
221
+ // --- Context injection: pre-read project state ---
222
+ let profileContext = '';
223
+ if (fs.existsSync(p.profile)) {
224
+ try {
225
+ const profile = JSON.parse(fs.readFileSync(p.profile, 'utf8'));
226
+ const stack = profile.tech_stack || {};
227
+ const parts = [];
228
+ if (stack.backend?.framework) parts.push(`后端: ${stack.backend.framework}`);
229
+ if (stack.frontend?.framework) parts.push(`前端: ${stack.frontend.framework}`);
230
+ if (stack.backend?.language) parts.push(`语言: ${stack.backend.language}`);
231
+ if (parts.length) profileContext = `项目技术栈: ${parts.join(', ')}`;
232
+ } catch { /* ignore */ }
233
+ }
234
+
235
+ let taskContext = '';
236
+ let recentExamples = '';
237
+ try {
238
+ const taskData = loadTasks();
239
+ if (taskData) {
240
+ const stats = getStats(taskData);
241
+ const features = taskData.features || [];
242
+ const maxId = features.length ? features[features.length - 1].id : 'feat-000';
243
+ const maxPriority = features.length ? Math.max(...features.map(f => f.priority || 0)) : 0;
244
+ const categories = [...new Set(features.map(f => f.category))].join(', ');
245
+
246
+ taskContext = `已有 ${stats.total} 个任务(${stats.done} done, ${stats.pending} pending, ${stats.failed} failed)。` +
247
+ `最大 id: ${maxId}, 最大 priority: ${maxPriority}。已有 category: ${categories}。`;
248
+
249
+ const recent = features.slice(-3);
250
+ if (recent.length) {
251
+ recentExamples = '已有任务格式参考(保持一致性):\n' +
252
+ recent.map(f => ` ${f.id}: "${f.description}" (category=${f.category}, steps=${f.steps.length}步, depends_on=[${f.depends_on.join(',')}])`).join('\n');
253
+ }
254
+ }
255
+ } catch { /* ignore */ }
256
+
217
257
  return [
218
- '重要:这是任务追加 session,不是常规编码 session。不执行 6 步流程。',
258
+ // --- Primacy zone: role + identity ---
259
+ '你是资深需求分析师,擅长将模糊需求分解为可执行的原子任务。',
260
+ '这是任务追加 session,不是编码 session。你只分解任务,不实现代码。',
219
261
  '',
220
- '步骤:',
221
- '1. 读取 .claude-coder/tasks.json 了解已有任务和最大 id/priority',
222
- '2. 读取 .claude-coder/project_profile.json 了解项目技术栈',
223
- '3. 根据用户指令追加新任务(status: pending)',
262
+
263
+ // --- Context layer ---
264
+ profileContext,
265
+ taskContext,
266
+ recentExamples,
267
+ `项目绝对路径: ${projectRoot}`,
224
268
  '',
269
+
270
+ // --- CoT: explicit thinking steps ---
271
+ '执行步骤(按顺序,不可跳过):',
272
+ '1. 读取 .claude-coder/tasks.json 和 .claude-coder/project_profile.json,全面了解项目现状',
273
+ '2. 分析用户指令:识别核心功能点,判断是单任务还是需要拆分为多任务',
274
+ '3. 检查重复:对比已有任务,避免功能重叠',
275
+ '4. 确定依赖:新任务的 depends_on 引用已有或新增任务的 id,形成 DAG',
276
+ '5. 分解任务:每个任务对应一个独立可测试的功能单元,description 简明(40字内),steps 具体可操作',
277
+ '6. 追加到 tasks.json,id 和 priority 从已有最大值递增,status: pending',
278
+ '7. git add -A && git commit -m "chore: add new tasks"',
279
+ '8. 写入 session_result.json',
280
+ '',
281
+
282
+ // --- Quality constraints ---
225
283
  taskGuide,
226
284
  '',
227
- '新任务 id 和 priority 从已有最大值递增。不修改已有任务,不实现代码。',
228
- 'git add -A && git commit -m "chore: add new tasks"',
229
- '写入 session_result.json',
285
+ '不修改已有任务,不实现代码。',
230
286
  '',
287
+
288
+ // --- Recency zone: user instruction (highest attention) ---
231
289
  `用户指令:${instruction}`,
232
- ].join('\n');
290
+ ].filter(Boolean).join('\n');
233
291
  }
234
292
 
235
293
  module.exports = {
package/src/session.js CHANGED
@@ -99,10 +99,9 @@ async function runCodingSession(sessionNum, opts = {}) {
99
99
  const taskId = opts.taskId || 'unknown';
100
100
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
101
101
  const logFile = path.join(p.logsDir, `${taskId}_session_${sessionNum}_${dateStr}.log`);
102
- const activityLogFile = path.join(p.logsDir, `session_${sessionNum}.activity.log`);
103
102
  const logStream = fs.createWriteStream(logFile, { flags: 'a' });
104
103
 
105
- indicator.start(sessionNum, activityLogFile);
104
+ indicator.start(sessionNum);
106
105
 
107
106
  const editCounts = {};
108
107
  const EDIT_THRESHOLD = 5;
@@ -127,9 +126,11 @@ async function runCodingSession(sessionNum, opts = {}) {
127
126
  inferPhaseStep(indicator, input.tool_name, input.tool_input);
128
127
 
129
128
  const target = input.tool_input?.file_path || input.tool_input?.path || '';
130
- const toolSummary = target ? target.split('/').slice(-2).join('/') : '';
131
- if (toolSummary) {
132
- logStream.write(`[${new Date().toISOString()}] ${input.tool_name}: ${toolSummary}\n`);
129
+ const cmd = input.tool_input?.command || '';
130
+ const pattern = input.tool_input?.pattern || '';
131
+ const detail = target || cmd.slice(0, 200) || (pattern ? `pattern: ${pattern}` : '');
132
+ if (detail) {
133
+ logStream.write(`[${new Date().toISOString()}] ${input.tool_name}: ${detail}\n`);
133
134
  }
134
135
 
135
136
  if (['Write', 'Edit', 'MultiEdit'].includes(input.tool_name) && target) {