claude-coder 1.0.6 → 1.0.8

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.
@@ -183,11 +183,11 @@ flowchart TB
183
183
 
184
184
  | Session 类型 | systemPrompt | user prompt | 触发条件 |
185
185
  |---|---|---|---|
186
- | **编码** | CLAUDE.md | `buildCodingPrompt()` + 8 个条件 hint | 主循环每次迭代 |
186
+ | **编码** | CLAUDE.md | `buildCodingPrompt()` + 10 个条件 hint | 主循环每次迭代 |
187
187
  | **扫描** | CLAUDE.md + SCAN_PROTOCOL.md | `buildScanPrompt()` + 任务分解指导 + profile 质量要求 | 首次运行 |
188
188
  | **追加** | CLAUDE.md | `buildAddPrompt()` + 任务分解指导 | `claude-coder add` |
189
189
 
190
- ### 编码 Session 的 8 个条件 Hint
190
+ ### 编码 Session 的 10 个条件 Hint
191
191
 
192
192
  | # | Hint | 触发条件 | 影响 |
193
193
  |---|---|---|---|
@@ -197,8 +197,10 @@ flowchart TB
197
197
  | 4 | `docsHint` | profile.existing_docs 非空或 profile 有缺陷 | Step 4:读文档后再编码;profile 缺陷时提示 Agent 在 Step 6 补全 services/docs |
198
198
  | 5 | `envHint` | 连续成功且 session>1 | Step 2:跳过 init |
199
199
  | 6 | `retryContext` | 上次校验失败 | 全局:避免同样错误 |
200
- | 7 | `taskHint` | tasks.json 存在且有待办任务 | Step 1:跳过读取 tasks.json,harness 已注入当前任务上下文 |
200
+ | 7 | `taskHint` | tasks.json 存在且有待办任务 | Step 1:跳过读取 tasks.json,harness 已注入当前任务上下文 + .claude-coder/ 路径提示 |
201
201
  | 8 | `memoryHint` | session_result.json 存在且有历史记录 | Step 1:跳过读取 session_result.json,harness 已注入上次会话摘要 |
202
+ | 9 | `serviceHint` | 始终注入 | Step 6:单次模式停止服务,连续模式保持服务运行 |
203
+ | 10 | `toolGuidance` | 始终注入 | 全局:工具使用规范(Grep/Glob/Read/LS/MultiEdit/Task 替代 bash 命令),非 Claude 模型必需 |
202
204
 
203
205
  ---
204
206
 
@@ -266,7 +268,7 @@ sequenceDiagram
266
268
  | 维度 | 评分 | 说明 |
267
269
  |------|------|------|
268
270
  | **CLAUDE.md 系统提示** | 8/10 | U 型注意力设计;铁律清晰;状态机和 6 步流程是核心竞争力 |
269
- | **动态 prompt** | 8.5/10 | 8 个条件 hint 精准注入,含 task/memory 上下文注入,减少 Agent 冗余 Read 调用 |
271
+ | **动态 prompt** | 9/10 | 10 个条件 hint 精准注入,含 task/memory 上下文注入 + 服务管理 + 工具使用指导,减少 Agent 冗余操作 |
270
272
  | **SCAN_PROTOCOL.md** | 8.5/10 | 新旧项目分支完整,profile 格式全面 |
271
273
  | **tests.json 设计** | 7.5/10 | 精简字段,核心目的(防反复测试)明确 |
272
274
  | **注入时机** | 9/10 | 静态规则 vs 动态上下文分离干净 |
package/docs/README.en.md CHANGED
@@ -50,9 +50,9 @@ Each session, the agent autonomously follows 6 steps: restore context → env ch
50
50
  |---------|-------------|
51
51
  | `claude-coder setup` | Interactive model configuration |
52
52
  | `claude-coder run [requirement]` | Auto-coding loop |
53
+ | `claude-coder run --max 1` | Single session (replaces old view mode) |
53
54
  | `claude-coder run --dry-run` | Preview mode |
54
55
  | `claude-coder init` | Initialize project environment |
55
- | `claude-coder view [requirement]` | Observation mode (single session) |
56
56
  | `claude-coder add "instruction"` | Append tasks |
57
57
  | `claude-coder validate` | Manually validate last session |
58
58
  | `claude-coder status` | View progress and costs |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-coder",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
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/config.js CHANGED
@@ -148,7 +148,12 @@ function buildEnvVars(config) {
148
148
  // --------------- Allowed tools ---------------
149
149
 
150
150
  function getAllowedTools(config) {
151
- const tools = ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'];
151
+ const tools = [
152
+ 'Read', 'Edit', 'MultiEdit', 'Write',
153
+ 'Bash', 'Glob', 'Grep', 'LS',
154
+ 'Task',
155
+ 'WebSearch', 'WebFetch',
156
+ ];
152
157
  if (config.mcpPlaywright) tools.push('mcp__playwright__*');
153
158
  return tools;
154
159
  }
package/src/indicator.js CHANGED
@@ -58,24 +58,29 @@ class Indicator {
58
58
  try { fs.writeFileSync(paths().stepFile, this.step, 'utf8'); } catch { /* ignore */ }
59
59
  }
60
60
 
61
- _render() {
61
+ getStatusLine() {
62
62
  const elapsed = Math.floor((Date.now() - this.startTime) / 1000);
63
63
  const mm = String(Math.floor(elapsed / 60)).padStart(2, '0');
64
64
  const ss = String(elapsed % 60).padStart(2, '0');
65
65
  const spinner = SPINNERS[this.spinnerIndex % SPINNERS.length];
66
- this.spinnerIndex++;
67
66
 
68
67
  const phaseLabel = this.phase === 'thinking'
69
68
  ? `${COLOR.yellow}思考中${COLOR.reset}`
70
69
  : `${COLOR.green}编码中${COLOR.reset}`;
71
70
 
72
- let line = `\r${spinner} [Session ${this.sessionNum}] ${phaseLabel} ${mm}:${ss}`;
71
+ let line = `${spinner} [Session ${this.sessionNum}] ${phaseLabel} ${mm}:${ss}`;
73
72
  if (this.step) line += ` | ${this.step}`;
73
+ return line;
74
+ }
75
+
76
+ _render() {
77
+ this.spinnerIndex++;
78
+ const line = this.getStatusLine();
74
79
 
75
80
  const maxWidth = process.stderr.columns || 80;
76
- if (line.length > maxWidth + 20) line = line.slice(0, maxWidth + 20);
81
+ const truncated = line.length > maxWidth + 20 ? line.slice(0, maxWidth + 20) : line;
77
82
 
78
- process.stderr.write(`\r\x1b[K${line}`);
83
+ process.stderr.write(`\r\x1b[K${truncated}`);
79
84
  }
80
85
  }
81
86
 
@@ -83,7 +88,7 @@ class Indicator {
83
88
  function inferPhaseStep(indicator, toolName, toolInput) {
84
89
  const name = (toolName || '').toLowerCase();
85
90
 
86
- if (name === 'write' || name === 'edit' || name === 'str_replace_editor' || name === 'strreplace') {
91
+ if (name === 'write' || name === 'edit' || name === 'multiedit' || name === 'str_replace_editor' || name === 'strreplace') {
87
92
  indicator.updatePhase('coding');
88
93
  } else if (name === 'bash' || name === 'shell') {
89
94
  const cmd = typeof toolInput === 'object' ? (toolInput.command || '') : String(toolInput || '');
@@ -97,9 +102,15 @@ function inferPhaseStep(indicator, toolName, toolInput) {
97
102
  } else {
98
103
  indicator.updatePhase('coding');
99
104
  }
100
- } else if (name === 'read' || name === 'glob' || name === 'grep') {
105
+ } else if (name === 'read' || name === 'glob' || name === 'grep' || name === 'ls') {
101
106
  indicator.updatePhase('thinking');
102
107
  indicator.updateStep('读取文件');
108
+ } else if (name === 'task') {
109
+ indicator.updatePhase('thinking');
110
+ indicator.updateStep('子 Agent 搜索');
111
+ } else if (name === 'websearch' || name === 'webfetch') {
112
+ indicator.updatePhase('thinking');
113
+ indicator.updateStep('查阅文档');
103
114
  }
104
115
 
105
116
  const summary = typeof toolInput === 'object'
package/src/prompts.js CHANGED
@@ -108,6 +108,7 @@ function buildCodingPrompt(sessionNum, opts = {}) {
108
108
  taskHint = `任务上下文: ${next.id} "${next.description}" (${next.status}), ` +
109
109
  `category=${next.category}, steps=${next.steps.length}步。` +
110
110
  `进度: ${stats.done}/${stats.total} done, ${stats.failed} failed。` +
111
+ `运行时目录: .claude-coder/(隐藏目录,ls -a 可见,所有 tasks.json/profile 等文件均在此目录下)。` +
111
112
  `第一步无需读取 tasks.json(已注入),直接确认任务后进入 Step 2。`;
112
113
  }
113
114
  }
@@ -126,6 +127,25 @@ function buildCodingPrompt(sessionNum, opts = {}) {
126
127
  } catch { /* ignore */ }
127
128
  }
128
129
 
130
+ // Hint 9: Service management (continuous vs single-shot mode)
131
+ const maxSessions = opts.maxSessions || 50;
132
+ const serviceHint = maxSessions === 1
133
+ ? '单次模式:收尾时停止所有后台服务。'
134
+ : '连续模式:收尾时不要停止后台服务,保持服务运行以便下个 session 继续使用。';
135
+
136
+ // Hint 10: Tool usage guidance (critical for non-Claude models)
137
+ const toolGuidance = [
138
+ '可用工具与使用规范(严格遵守):',
139
+ '- 搜索文件名: Glob(如 **/*.ts),禁止 bash find',
140
+ '- 搜索文件内容: Grep(正则,基于 ripgrep),禁止 bash grep',
141
+ '- 读文件: Read(支持批量多文件同时读取),禁止 bash cat/head/tail',
142
+ '- 列目录: LS,禁止 bash ls',
143
+ '- 编辑文件: 同一文件多处修改用 MultiEdit(一次原子调用),单处用 Edit',
144
+ '- 复杂搜索: Task(启动子 Agent 并行搜索,不消耗主 context),适合开放式探索',
145
+ '- 查文档/API: WebSearch + WebFetch',
146
+ '- 效率: 多个 Read/Glob/Grep 尽量合并为一次批量调用,减少工具轮次',
147
+ ].join('\n');
148
+
129
149
  return [
130
150
  `Session ${sessionNum}。执行 6 步流程。`,
131
151
  '效率要求:先规划后编码,完成全部编码后再统一测试,禁止编码-测试反复跳转。后端任务用 curl 验证,不启动浏览器。',
@@ -136,6 +156,8 @@ function buildCodingPrompt(sessionNum, opts = {}) {
136
156
  envHint,
137
157
  taskHint,
138
158
  memoryHint,
159
+ serviceHint,
160
+ toolGuidance,
139
161
  `完成后写入 session_result.json。${retryContext}`,
140
162
  ].filter(Boolean).join('\n');
141
163
  }
package/src/runner.js CHANGED
@@ -269,6 +269,7 @@ async function run(requirement, opts = {}) {
269
269
  const sessionResult = await runCodingSession(session, {
270
270
  projectRoot,
271
271
  consecutiveFailures,
272
+ maxSessions,
272
273
  lastValidateLog: consecutiveFailures > 0 ? '上次校验失败' : '',
273
274
  });
274
275
 
package/src/session.js CHANGED
@@ -66,7 +66,11 @@ function logMessage(message, logStream, indicator) {
66
66
  if (message.type === 'assistant' && message.message?.content) {
67
67
  for (const block of message.message.content) {
68
68
  if (block.type === 'text' && block.text) {
69
- if (indicator) process.stderr.write('\r\x1b[K');
69
+ if (indicator) {
70
+ const statusLine = indicator.getStatusLine();
71
+ process.stderr.write('\r\x1b[K');
72
+ if (statusLine) process.stderr.write(statusLine + '\n');
73
+ }
70
74
  process.stdout.write(block.text);
71
75
  if (logStream) logStream.write(block.text);
72
76
  }
@@ -210,7 +210,8 @@ pending ──→ in_progress ──→ testing ──→ done
210
210
  - 确认方案完整后,**一次性**完成所有编码
211
211
  - **禁止边写边试**:完成全部编码后再进入第五步统一测试
212
212
  4. **高效执行**:禁止碎片化操作(读一个文件、思考、再读一个),批量读取、批量修改、减少工具调用轮次
213
- 5. **跳过已完成的步骤**:文件已存在且内容正确的步骤直接跳过
213
+ 5. **工具优先**:用 Grep/Glob 替代 bash grep/find,用 Read/LS 替代 bash cat/ls,同一文件多处修改用 MultiEdit
214
+ 6. **跳过已完成的步骤**:文件已存在且内容正确的步骤直接跳过
214
215
 
215
216
  ### 第五步:测试验证
216
217
 
@@ -241,7 +242,7 @@ pending ──→ in_progress ──→ testing ──→ done
241
242
 
242
243
  ### 第六步:收尾(每次会话必须执行)
243
244
 
244
- 1. **停止本次启动的后台服务**:`lsof -ti :端口 | xargs kill`,避免下次 session 端口冲突
245
+ 1. **后台服务管理**:根据 prompt 提示决定——单次模式(`--max 1`)时停止所有后台服务(`lsof -ti :端口 | xargs kill`);连续模式时保持服务运行,下个 session 继续使用
245
246
  2. **按需更新文档和 profile**:
246
247
  - **README / 用户文档**:仅当对外行为变化(新增功能、API 变更、使用方式变化)时更新
247
248
  - **架构 / API 文档**:如果本次新增了模块、改变了模块职责或新增了 API 端点,更新 `existing_docs` 中对应的架构或 API 文档。同时更新 `project_profile.json` 的 `existing_docs` 列表(若新增了文档文件)