claude-coder 1.5.2 → 1.5.3
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/package.json +1 -1
- package/src/indicator.js +46 -25
- package/src/session.js +8 -2
package/package.json
CHANGED
package/src/indicator.js
CHANGED
|
@@ -16,6 +16,8 @@ class Indicator {
|
|
|
16
16
|
this.lastToolTime = Date.now();
|
|
17
17
|
this.sessionNum = 0;
|
|
18
18
|
this.startTime = Date.now();
|
|
19
|
+
this._lastContentKey = '';
|
|
20
|
+
this._lastRenderTime = 0;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
start(sessionNum) {
|
|
@@ -86,8 +88,16 @@ class Indicator {
|
|
|
86
88
|
|
|
87
89
|
_render() {
|
|
88
90
|
this.spinnerIndex++;
|
|
89
|
-
const
|
|
91
|
+
const contentKey = `${this.phase}|${this.step}|${this.toolTarget}`;
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
|
|
94
|
+
if (contentKey === this._lastContentKey && now - this._lastRenderTime < 5000) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this._lastContentKey = contentKey;
|
|
98
|
+
this._lastRenderTime = now;
|
|
90
99
|
|
|
100
|
+
const line = this.getStatusLine();
|
|
91
101
|
const maxWidth = process.stderr.columns || 80;
|
|
92
102
|
const truncated = line.length > maxWidth + 20 ? line.slice(0, maxWidth + 20) : line;
|
|
93
103
|
|
|
@@ -95,41 +105,60 @@ class Indicator {
|
|
|
95
105
|
}
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
function extractFileTarget(toolInput) {
|
|
109
|
+
const raw = typeof toolInput === 'object'
|
|
110
|
+
? (toolInput.file_path || toolInput.path || '')
|
|
111
|
+
: '';
|
|
112
|
+
if (!raw) return '';
|
|
113
|
+
return raw.split('/').slice(-2).join('/').slice(0, 40);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function extractBashLabel(cmd) {
|
|
117
|
+
if (cmd.includes('git ')) return 'Git 操作';
|
|
118
|
+
if (cmd.includes('npm ') || cmd.includes('pip ') || cmd.includes('pnpm ') || cmd.includes('yarn ')) return '安装依赖';
|
|
119
|
+
if (cmd.includes('curl') || cmd.includes('pytest') || cmd.includes('jest') || /\btest\b/.test(cmd)) return '测试验证';
|
|
120
|
+
if (cmd.includes('python ') || cmd.includes('node ')) return '执行脚本';
|
|
121
|
+
return '执行命令';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function extractBashTarget(cmd) {
|
|
125
|
+
let clean = cmd.replace(/^(?:cd\s+\S+\s*&&\s*)+/g, '').trim();
|
|
126
|
+
clean = clean.split(/\s*(?:\|{1,2}|;|&&|2>&1|>\s*\/dev\/null)\s*/)[0].trim();
|
|
127
|
+
return clean.slice(0, 40);
|
|
128
|
+
}
|
|
129
|
+
|
|
99
130
|
function inferPhaseStep(indicator, toolName, toolInput) {
|
|
100
131
|
const name = (toolName || '').toLowerCase();
|
|
101
132
|
|
|
102
133
|
indicator.lastToolTime = Date.now();
|
|
103
134
|
|
|
104
|
-
const rawTarget = typeof toolInput === 'object'
|
|
105
|
-
? (toolInput.file_path || toolInput.path || toolInput.command || toolInput.pattern || '')
|
|
106
|
-
: String(toolInput || '');
|
|
107
|
-
const shortTarget = rawTarget.split('/').slice(-2).join('/').slice(0, 40);
|
|
108
|
-
indicator.toolTarget = shortTarget;
|
|
109
|
-
|
|
110
135
|
if (name === 'write' || name === 'edit' || name === 'multiedit' || name === 'str_replace_editor' || name === 'strreplace') {
|
|
111
136
|
indicator.updatePhase('coding');
|
|
137
|
+
indicator.updateStep('编辑文件');
|
|
138
|
+
indicator.toolTarget = extractFileTarget(toolInput);
|
|
112
139
|
} else if (name === 'bash' || name === 'shell') {
|
|
113
140
|
const cmd = typeof toolInput === 'object' ? (toolInput.command || '') : String(toolInput || '');
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
} else if (cmd.includes('test') || cmd.includes('curl') || cmd.includes('pytest')) {
|
|
119
|
-
indicator.updateStep('测试验证');
|
|
120
|
-
indicator.updatePhase('coding');
|
|
121
|
-
} else {
|
|
141
|
+
const label = extractBashLabel(cmd);
|
|
142
|
+
indicator.updateStep(label);
|
|
143
|
+
indicator.toolTarget = extractBashTarget(cmd);
|
|
144
|
+
if (label === '测试验证' || label === '执行脚本' || label === '执行命令') {
|
|
122
145
|
indicator.updatePhase('coding');
|
|
123
146
|
}
|
|
124
147
|
} else if (name === 'read' || name === 'glob' || name === 'grep' || name === 'ls') {
|
|
125
148
|
indicator.updatePhase('thinking');
|
|
126
149
|
indicator.updateStep('读取文件');
|
|
150
|
+
indicator.toolTarget = extractFileTarget(toolInput);
|
|
127
151
|
} else if (name === 'task') {
|
|
128
152
|
indicator.updatePhase('thinking');
|
|
129
153
|
indicator.updateStep('子 Agent 搜索');
|
|
154
|
+
indicator.toolTarget = '';
|
|
130
155
|
} else if (name === 'websearch' || name === 'webfetch') {
|
|
131
156
|
indicator.updatePhase('thinking');
|
|
132
157
|
indicator.updateStep('查阅文档');
|
|
158
|
+
indicator.toolTarget = '';
|
|
159
|
+
} else {
|
|
160
|
+
indicator.updateStep('工具调用');
|
|
161
|
+
indicator.toolTarget = '';
|
|
133
162
|
}
|
|
134
163
|
|
|
135
164
|
let summary;
|
|
@@ -137,15 +166,7 @@ function inferPhaseStep(indicator, toolName, toolInput) {
|
|
|
137
166
|
const target = toolInput.file_path || toolInput.path || '';
|
|
138
167
|
const cmd = toolInput.command || '';
|
|
139
168
|
const pattern = toolInput.pattern || '';
|
|
140
|
-
|
|
141
|
-
summary = target;
|
|
142
|
-
} else if (cmd) {
|
|
143
|
-
summary = cmd.slice(0, 200);
|
|
144
|
-
} else if (pattern) {
|
|
145
|
-
summary = `pattern: ${pattern}`;
|
|
146
|
-
} else {
|
|
147
|
-
summary = JSON.stringify(toolInput).slice(0, 200);
|
|
148
|
-
}
|
|
169
|
+
summary = target || (cmd ? cmd.slice(0, 200) : '') || (pattern ? `pattern: ${pattern}` : JSON.stringify(toolInput).slice(0, 200));
|
|
149
170
|
} else {
|
|
150
171
|
summary = String(toolInput || '').slice(0, 200);
|
|
151
172
|
}
|
package/src/session.js
CHANGED
|
@@ -73,14 +73,20 @@ function writeSessionSeparator(logStream, sessionNum, label) {
|
|
|
73
73
|
logStream.write(`\n${sep}\n[Session ${sessionNum}] ${label} ${new Date().toISOString()}\n${sep}\n`);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
let _lastPrintedStatusKey = '';
|
|
77
|
+
|
|
76
78
|
function logMessage(message, logStream, indicator) {
|
|
77
79
|
if (message.type === 'assistant' && message.message?.content) {
|
|
78
80
|
for (const block of message.message.content) {
|
|
79
81
|
if (block.type === 'text' && block.text) {
|
|
80
82
|
if (indicator) {
|
|
81
|
-
const statusLine = indicator.getStatusLine();
|
|
82
83
|
process.stderr.write('\r\x1b[K');
|
|
83
|
-
|
|
84
|
+
const contentKey = `${indicator.phase}|${indicator.step}|${indicator.toolTarget}`;
|
|
85
|
+
if (contentKey !== _lastPrintedStatusKey) {
|
|
86
|
+
_lastPrintedStatusKey = contentKey;
|
|
87
|
+
const statusLine = indicator.getStatusLine();
|
|
88
|
+
if (statusLine) process.stderr.write(statusLine + '\n');
|
|
89
|
+
}
|
|
84
90
|
}
|
|
85
91
|
process.stdout.write(block.text);
|
|
86
92
|
if (logStream) logStream.write(block.text);
|