@grinev/opencode-telegram-bot 0.5.0 → 0.6.1-rc.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/.env.example +11 -0
- package/README.md +24 -19
- package/dist/bot/commands/new.js +2 -0
- package/dist/bot/commands/sessions.js +2 -0
- package/dist/bot/handlers/permission.js +54 -30
- package/dist/bot/index.js +87 -20
- package/dist/config.js +31 -0
- package/dist/permission/manager.js +58 -42
- package/dist/pinned/manager.js +7 -5
- package/dist/settings/manager.js +6 -1
- package/dist/summary/aggregator.js +132 -48
- package/dist/summary/formatter.js +91 -15
- package/dist/summary/tool-message-batcher.js +259 -0
- package/package.json +1 -1
package/dist/pinned/manager.js
CHANGED
|
@@ -266,7 +266,7 @@ class PinnedMessageManager {
|
|
|
266
266
|
logger.debug(`[PinnedManager] loadDiffsFromMessages: ${messagesData.length} messages`);
|
|
267
267
|
const filesMap = new Map();
|
|
268
268
|
let toolCount = 0;
|
|
269
|
-
let
|
|
269
|
+
let fileToolCount = 0;
|
|
270
270
|
for (const { parts } of messagesData) {
|
|
271
271
|
for (const part of parts) {
|
|
272
272
|
if (part.type !== "tool")
|
|
@@ -275,10 +275,12 @@ class PinnedMessageManager {
|
|
|
275
275
|
const toolPart = part;
|
|
276
276
|
if (toolPart.state.status !== "completed")
|
|
277
277
|
continue;
|
|
278
|
-
if (toolPart.tool === "edit" ||
|
|
279
|
-
|
|
278
|
+
if (toolPart.tool === "edit" ||
|
|
279
|
+
toolPart.tool === "write" ||
|
|
280
|
+
toolPart.tool === "apply_patch") {
|
|
281
|
+
fileToolCount++;
|
|
280
282
|
}
|
|
281
|
-
if (toolPart.tool === "edit" &&
|
|
283
|
+
if ((toolPart.tool === "edit" || toolPart.tool === "apply_patch") &&
|
|
282
284
|
toolPart.state.metadata &&
|
|
283
285
|
"filediff" in toolPart.state.metadata) {
|
|
284
286
|
const filediff = toolPart.state.metadata.filediff;
|
|
@@ -318,7 +320,7 @@ class PinnedMessageManager {
|
|
|
318
320
|
}
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
|
-
logger.debug(`[PinnedManager] loadDiffsFromMessages: found ${toolCount} tool parts, ${
|
|
323
|
+
logger.debug(`[PinnedManager] loadDiffsFromMessages: found ${toolCount} tool parts, ${fileToolCount} file tools`);
|
|
322
324
|
if (filesMap.size > 0) {
|
|
323
325
|
this.state.changedFiles = Array.from(filesMap.values());
|
|
324
326
|
logger.info(`[PinnedManager] Loaded ${this.state.changedFiles.length} file diffs from messages`);
|
package/dist/settings/manager.js
CHANGED
|
@@ -119,5 +119,10 @@ export function __resetSettingsForTests() {
|
|
|
119
119
|
settingsWriteQueue = Promise.resolve();
|
|
120
120
|
}
|
|
121
121
|
export async function loadSettings() {
|
|
122
|
-
|
|
122
|
+
const loadedSettings = (await readSettingsFile());
|
|
123
|
+
if ("toolMessagesIntervalSec" in loadedSettings) {
|
|
124
|
+
delete loadedSettings.toolMessagesIntervalSec;
|
|
125
|
+
void writeSettingsFile(loadedSettings);
|
|
126
|
+
}
|
|
127
|
+
currentSettings = loadedSettings;
|
|
123
128
|
}
|
|
@@ -1,6 +1,29 @@
|
|
|
1
|
-
import { prepareCodeFile } from "./formatter.js";
|
|
1
|
+
import { normalizePathForDisplay, prepareCodeFile } from "./formatter.js";
|
|
2
2
|
import { logger } from "../utils/logger.js";
|
|
3
3
|
import { getCurrentProject } from "../settings/manager.js";
|
|
4
|
+
function extractFirstUpdatedFileFromTitle(title) {
|
|
5
|
+
for (const rawLine of title.split("\n")) {
|
|
6
|
+
const line = rawLine.trim();
|
|
7
|
+
if (line.length >= 3 && line[1] === " " && /[AMDURC]/.test(line[0])) {
|
|
8
|
+
return line.slice(2).trim();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
function countDiffChangesFromText(text) {
|
|
14
|
+
let additions = 0;
|
|
15
|
+
let deletions = 0;
|
|
16
|
+
for (const line of text.split("\n")) {
|
|
17
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
18
|
+
additions++;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (line.startsWith("-") && !line.startsWith("---")) {
|
|
22
|
+
deletions++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { additions, deletions };
|
|
26
|
+
}
|
|
4
27
|
class SummaryAggregator {
|
|
5
28
|
currentSessionId = null;
|
|
6
29
|
currentMessageParts = new Map();
|
|
@@ -19,6 +42,7 @@ class SummaryAggregator {
|
|
|
19
42
|
onPermissionCallback = null;
|
|
20
43
|
onSessionDiffCallback = null;
|
|
21
44
|
onFileChangeCallback = null;
|
|
45
|
+
onClearedCallback = null;
|
|
22
46
|
processedToolStates = new Set();
|
|
23
47
|
bot = null;
|
|
24
48
|
chatId = null;
|
|
@@ -61,6 +85,9 @@ class SummaryAggregator {
|
|
|
61
85
|
setOnFileChange(callback) {
|
|
62
86
|
this.onFileChangeCallback = callback;
|
|
63
87
|
}
|
|
88
|
+
setOnCleared(callback) {
|
|
89
|
+
this.onClearedCallback = callback;
|
|
90
|
+
}
|
|
64
91
|
startTypingIndicator() {
|
|
65
92
|
if (this.typingTimer) {
|
|
66
93
|
return;
|
|
@@ -145,6 +172,14 @@ class SummaryAggregator {
|
|
|
145
172
|
this.processedToolStates.clear();
|
|
146
173
|
this.messageCount = 0;
|
|
147
174
|
this.lastUpdated = 0;
|
|
175
|
+
if (this.onClearedCallback) {
|
|
176
|
+
try {
|
|
177
|
+
this.onClearedCallback();
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
logger.error("[Aggregator] Error in clear callback:", err);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
148
183
|
}
|
|
149
184
|
handleMessageUpdated(event) {
|
|
150
185
|
const { info } = event.properties;
|
|
@@ -160,8 +195,11 @@ class SummaryAggregator {
|
|
|
160
195
|
this.startTypingIndicator();
|
|
161
196
|
// Notify that agent started thinking
|
|
162
197
|
if (this.onThinkingCallback) {
|
|
198
|
+
const callback = this.onThinkingCallback;
|
|
163
199
|
setImmediate(() => {
|
|
164
|
-
|
|
200
|
+
if (typeof callback === "function") {
|
|
201
|
+
callback(info.sessionID);
|
|
202
|
+
}
|
|
165
203
|
});
|
|
166
204
|
}
|
|
167
205
|
}
|
|
@@ -260,10 +298,12 @@ class SummaryAggregator {
|
|
|
260
298
|
}
|
|
261
299
|
if ("status" in state && state.status === "completed") {
|
|
262
300
|
logger.debug(`[Aggregator] Tool completed: callID=${part.callID}, tool=${part.tool}`, JSON.stringify(state, null, 2));
|
|
263
|
-
const
|
|
264
|
-
if (!this.processedToolStates.has(
|
|
265
|
-
this.processedToolStates.add(
|
|
301
|
+
const completedKey = `completed-${part.callID}`;
|
|
302
|
+
if (!this.processedToolStates.has(completedKey)) {
|
|
303
|
+
this.processedToolStates.add(completedKey);
|
|
304
|
+
const preparedFileContext = this.prepareToolFileContext(part.tool, input, title, state.metadata);
|
|
266
305
|
const toolData = {
|
|
306
|
+
sessionId: part.sessionID,
|
|
267
307
|
messageId: messageID,
|
|
268
308
|
callId: part.callID,
|
|
269
309
|
tool: part.tool,
|
|
@@ -271,61 +311,105 @@ class SummaryAggregator {
|
|
|
271
311
|
input,
|
|
272
312
|
title,
|
|
273
313
|
metadata: state.metadata,
|
|
314
|
+
hasFileAttachment: !!preparedFileContext.fileData,
|
|
274
315
|
};
|
|
275
316
|
logger.debug(`[Aggregator] Sending tool notification to Telegram: tool=${part.tool}, title=${title || "N/A"}`);
|
|
276
317
|
if (this.onToolCallback) {
|
|
277
318
|
this.onToolCallback(toolData);
|
|
278
319
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const fileData = prepareCodeFile(input.content, input.filePath, "write");
|
|
287
|
-
if (fileData && this.onToolFileCallback) {
|
|
288
|
-
logger.debug(`[Aggregator] Sending write file: ${fileData.filename} (${fileData.buffer.length} bytes)`);
|
|
289
|
-
this.onToolFileCallback(fileData);
|
|
290
|
-
}
|
|
291
|
-
// Notify about file change for pinned message
|
|
292
|
-
if (this.onFileChangeCallback) {
|
|
293
|
-
const lines = input.content.split("\n").length;
|
|
294
|
-
this.onFileChangeCallback({
|
|
295
|
-
file: input.filePath,
|
|
296
|
-
additions: lines,
|
|
297
|
-
deletions: 0,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
320
|
+
if (preparedFileContext.fileData && this.onToolFileCallback) {
|
|
321
|
+
logger.debug(`[Aggregator] Sending ${part.tool} file: ${preparedFileContext.fileData.filename} (${preparedFileContext.fileData.buffer.length} bytes)`);
|
|
322
|
+
this.onToolFileCallback({
|
|
323
|
+
...toolData,
|
|
324
|
+
hasFileAttachment: true,
|
|
325
|
+
fileData: preparedFileContext.fileData,
|
|
326
|
+
});
|
|
300
327
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
"diff" in state.metadata &&
|
|
304
|
-
"filediff" in state.metadata) {
|
|
305
|
-
const filediff = state.metadata.filediff;
|
|
306
|
-
const filePath = filediff.file;
|
|
307
|
-
const diff = state.metadata.diff;
|
|
308
|
-
if (filePath && diff) {
|
|
309
|
-
const fileData = prepareCodeFile(diff, filePath, "edit");
|
|
310
|
-
if (fileData && this.onToolFileCallback) {
|
|
311
|
-
logger.debug(`[Aggregator] Sending edit file: ${fileData.filename} (${fileData.buffer.length} bytes)`);
|
|
312
|
-
this.onToolFileCallback(fileData);
|
|
313
|
-
}
|
|
314
|
-
// Notify about file change for pinned message
|
|
315
|
-
if (this.onFileChangeCallback) {
|
|
316
|
-
this.onFileChangeCallback({
|
|
317
|
-
file: filePath,
|
|
318
|
-
additions: filediff.additions || 0,
|
|
319
|
-
deletions: filediff.deletions || 0,
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
}
|
|
328
|
+
if (preparedFileContext.fileChange && this.onFileChangeCallback) {
|
|
329
|
+
this.onFileChangeCallback(preparedFileContext.fileChange);
|
|
323
330
|
}
|
|
324
331
|
}
|
|
325
332
|
}
|
|
326
333
|
}
|
|
327
334
|
this.lastUpdated = Date.now();
|
|
328
335
|
}
|
|
336
|
+
prepareToolFileContext(tool, input, title, metadata) {
|
|
337
|
+
if (tool === "write" && input) {
|
|
338
|
+
const filePath = typeof input.filePath === "string" ? normalizePathForDisplay(input.filePath) : "";
|
|
339
|
+
const hasContent = typeof input.content === "string";
|
|
340
|
+
const content = hasContent ? input.content : "";
|
|
341
|
+
if (!filePath || !hasContent) {
|
|
342
|
+
return { fileData: null, fileChange: null };
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
fileData: prepareCodeFile(content, filePath, "write"),
|
|
346
|
+
fileChange: {
|
|
347
|
+
file: filePath,
|
|
348
|
+
additions: content.split("\n").length,
|
|
349
|
+
deletions: 0,
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
if (tool === "edit" && metadata) {
|
|
354
|
+
const editMetadata = metadata;
|
|
355
|
+
const filePath = editMetadata.filediff?.file
|
|
356
|
+
? normalizePathForDisplay(editMetadata.filediff.file)
|
|
357
|
+
: "";
|
|
358
|
+
const diffText = typeof editMetadata.diff === "string" ? editMetadata.diff : "";
|
|
359
|
+
if (!filePath || !diffText) {
|
|
360
|
+
return { fileData: null, fileChange: null };
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
fileData: prepareCodeFile(diffText, filePath, "edit"),
|
|
364
|
+
fileChange: {
|
|
365
|
+
file: filePath,
|
|
366
|
+
additions: editMetadata.filediff?.additions || 0,
|
|
367
|
+
deletions: editMetadata.filediff?.deletions || 0,
|
|
368
|
+
},
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (tool === "apply_patch") {
|
|
372
|
+
const patchMetadata = metadata;
|
|
373
|
+
const filePathFromInput = input && typeof input.filePath === "string"
|
|
374
|
+
? normalizePathForDisplay(input.filePath)
|
|
375
|
+
: input && typeof input.path === "string"
|
|
376
|
+
? normalizePathForDisplay(input.path)
|
|
377
|
+
: "";
|
|
378
|
+
const filePathFromTitle = title ? extractFirstUpdatedFileFromTitle(title) : "";
|
|
379
|
+
const filePath = (patchMetadata?.filediff?.file && normalizePathForDisplay(patchMetadata.filediff.file)) ||
|
|
380
|
+
filePathFromInput ||
|
|
381
|
+
normalizePathForDisplay(filePathFromTitle);
|
|
382
|
+
const diffText = typeof patchMetadata?.diff === "string"
|
|
383
|
+
? patchMetadata.diff
|
|
384
|
+
: input && typeof input.patchText === "string"
|
|
385
|
+
? input.patchText
|
|
386
|
+
: "";
|
|
387
|
+
if (!filePath) {
|
|
388
|
+
return { fileData: null, fileChange: null };
|
|
389
|
+
}
|
|
390
|
+
const fileChange = patchMetadata?.filediff
|
|
391
|
+
? {
|
|
392
|
+
file: filePath,
|
|
393
|
+
additions: patchMetadata.filediff.additions || 0,
|
|
394
|
+
deletions: patchMetadata.filediff.deletions || 0,
|
|
395
|
+
}
|
|
396
|
+
: diffText
|
|
397
|
+
? (() => {
|
|
398
|
+
const changes = countDiffChangesFromText(diffText);
|
|
399
|
+
return {
|
|
400
|
+
file: filePath,
|
|
401
|
+
additions: changes.additions,
|
|
402
|
+
deletions: changes.deletions,
|
|
403
|
+
};
|
|
404
|
+
})()
|
|
405
|
+
: null;
|
|
406
|
+
return {
|
|
407
|
+
fileData: diffText ? prepareCodeFile(diffText, filePath, "edit") : null,
|
|
408
|
+
fileChange,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return { fileData: null, fileChange: null };
|
|
412
|
+
}
|
|
329
413
|
hashString(str) {
|
|
330
414
|
let hash = 0;
|
|
331
415
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -2,6 +2,7 @@ import * as path from "path";
|
|
|
2
2
|
import { config } from "../config.js";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
4
|
import { t } from "../i18n/index.js";
|
|
5
|
+
import { getCurrentProject } from "../settings/manager.js";
|
|
5
6
|
const TELEGRAM_MESSAGE_LIMIT = 4096;
|
|
6
7
|
function splitText(text, maxLength) {
|
|
7
8
|
const parts = [];
|
|
@@ -21,6 +22,27 @@ function splitText(text, maxLength) {
|
|
|
21
22
|
}
|
|
22
23
|
return parts;
|
|
23
24
|
}
|
|
25
|
+
export function normalizePathForDisplay(filePath) {
|
|
26
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
27
|
+
const project = getCurrentProject();
|
|
28
|
+
if (!project?.worktree) {
|
|
29
|
+
return normalizedPath;
|
|
30
|
+
}
|
|
31
|
+
const normalizedWorktree = project.worktree.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
32
|
+
if (!normalizedWorktree) {
|
|
33
|
+
return normalizedPath;
|
|
34
|
+
}
|
|
35
|
+
const pathForCompare = process.platform === "win32" ? normalizedPath.toLowerCase() : normalizedPath;
|
|
36
|
+
const worktreeForCompare = process.platform === "win32" ? normalizedWorktree.toLowerCase() : normalizedWorktree;
|
|
37
|
+
if (pathForCompare === worktreeForCompare) {
|
|
38
|
+
return ".";
|
|
39
|
+
}
|
|
40
|
+
const worktreePrefix = `${worktreeForCompare}/`;
|
|
41
|
+
if (pathForCompare.startsWith(worktreePrefix)) {
|
|
42
|
+
return normalizedPath.slice(normalizedWorktree.length + 1);
|
|
43
|
+
}
|
|
44
|
+
return normalizedPath;
|
|
45
|
+
}
|
|
24
46
|
export function formatSummary(text) {
|
|
25
47
|
if (!text || text.trim().length === 0) {
|
|
26
48
|
return [];
|
|
@@ -50,9 +72,10 @@ function getToolDetails(tool, input) {
|
|
|
50
72
|
case "read":
|
|
51
73
|
case "edit":
|
|
52
74
|
case "write":
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
75
|
+
case "apply_patch":
|
|
76
|
+
const filePath = input.path || input.filePath;
|
|
77
|
+
if (typeof filePath === "string")
|
|
78
|
+
return normalizePathForDisplay(filePath);
|
|
56
79
|
break;
|
|
57
80
|
case "bash":
|
|
58
81
|
if (typeof input.command === "string")
|
|
@@ -88,6 +111,8 @@ function getToolIcon(tool) {
|
|
|
88
111
|
return "✍️";
|
|
89
112
|
case "edit":
|
|
90
113
|
return "✏️";
|
|
114
|
+
case "apply_patch":
|
|
115
|
+
return "🩹";
|
|
91
116
|
case "bash":
|
|
92
117
|
return "💻";
|
|
93
118
|
case "glob":
|
|
@@ -133,6 +158,37 @@ function formatTodos(todos) {
|
|
|
133
158
|
}
|
|
134
159
|
return result;
|
|
135
160
|
}
|
|
161
|
+
function formatDiffLineInfo(filediff) {
|
|
162
|
+
const parts = [];
|
|
163
|
+
if (filediff.additions && filediff.additions > 0)
|
|
164
|
+
parts.push(`+${filediff.additions}`);
|
|
165
|
+
if (filediff.deletions && filediff.deletions > 0)
|
|
166
|
+
parts.push(`-${filediff.deletions}`);
|
|
167
|
+
return parts.length > 0 ? ` (${parts.join(" ")})` : "";
|
|
168
|
+
}
|
|
169
|
+
function countDiffChangesFromText(text) {
|
|
170
|
+
let additions = 0;
|
|
171
|
+
let deletions = 0;
|
|
172
|
+
for (const line of text.split("\n")) {
|
|
173
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
174
|
+
additions++;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (line.startsWith("-") && !line.startsWith("---")) {
|
|
178
|
+
deletions++;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { additions, deletions };
|
|
182
|
+
}
|
|
183
|
+
function extractFirstUpdatedFileFromTitle(title) {
|
|
184
|
+
for (const rawLine of title.split("\n")) {
|
|
185
|
+
const line = rawLine.trim();
|
|
186
|
+
if (line.length >= 3 && line[1] === " " && /[AMDURC]/.test(line[0])) {
|
|
187
|
+
return line.slice(2).trim();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return "";
|
|
191
|
+
}
|
|
136
192
|
export function formatToolInfo(toolInfo) {
|
|
137
193
|
const { tool, input, title } = toolInfo;
|
|
138
194
|
logger.debug(`[Formatter] formatToolInfo: tool=${tool}, hasMetadata=${!!toolInfo.metadata}, hasFilediff=${!!toolInfo.metadata?.filediff}`);
|
|
@@ -151,22 +207,41 @@ export function formatToolInfo(toolInfo) {
|
|
|
151
207
|
if (tool === "bash" && input && typeof input.command === "string") {
|
|
152
208
|
details = input.command;
|
|
153
209
|
}
|
|
210
|
+
if (tool === "apply_patch") {
|
|
211
|
+
const filediff = toolInfo.metadata && "filediff" in toolInfo.metadata
|
|
212
|
+
? toolInfo.metadata.filediff
|
|
213
|
+
: undefined;
|
|
214
|
+
if (filediff?.file) {
|
|
215
|
+
details = normalizePathForDisplay(filediff.file);
|
|
216
|
+
}
|
|
217
|
+
else if (title) {
|
|
218
|
+
const fileFromTitle = extractFirstUpdatedFileFromTitle(title);
|
|
219
|
+
if (fileFromTitle) {
|
|
220
|
+
details = normalizePathForDisplay(fileFromTitle);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
154
224
|
const detailsStr = details ? ` ${details}` : "";
|
|
155
225
|
let lineInfo = "";
|
|
156
226
|
if (tool === "write" && input && "content" in input && typeof input.content === "string") {
|
|
157
227
|
const lines = countLines(input.content);
|
|
158
228
|
lineInfo = ` (+${lines})`;
|
|
159
229
|
}
|
|
160
|
-
if (tool === "edit"
|
|
230
|
+
if ((tool === "edit" || tool === "apply_patch") &&
|
|
231
|
+
toolInfo.metadata &&
|
|
232
|
+
"filediff" in toolInfo.metadata) {
|
|
161
233
|
const filediff = toolInfo.metadata.filediff;
|
|
162
|
-
logger.debug("[Formatter]
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
234
|
+
logger.debug("[Formatter] Diff metadata:", JSON.stringify(toolInfo.metadata, null, 2));
|
|
235
|
+
lineInfo = formatDiffLineInfo(filediff);
|
|
236
|
+
}
|
|
237
|
+
if (tool === "apply_patch" && !lineInfo) {
|
|
238
|
+
const diffText = toolInfo.metadata && typeof toolInfo.metadata.diff === "string"
|
|
239
|
+
? toolInfo.metadata.diff
|
|
240
|
+
: input && typeof input.patchText === "string"
|
|
241
|
+
? input.patchText
|
|
242
|
+
: "";
|
|
243
|
+
if (diffText) {
|
|
244
|
+
lineInfo = formatDiffLineInfo(countDiffChangesFromText(diffText));
|
|
170
245
|
}
|
|
171
246
|
}
|
|
172
247
|
return `${toolIcon} ${description}${tool}${detailsStr}${lineInfo}`;
|
|
@@ -209,18 +284,19 @@ function formatDiff(diff) {
|
|
|
209
284
|
return formattedLines.join("\n");
|
|
210
285
|
}
|
|
211
286
|
export function prepareCodeFile(content, filePath, operation) {
|
|
287
|
+
const displayPath = normalizePathForDisplay(filePath);
|
|
212
288
|
let processedContent = content;
|
|
213
289
|
if (operation === "edit") {
|
|
214
290
|
processedContent = formatDiff(content);
|
|
215
291
|
}
|
|
216
292
|
const sizeKb = Buffer.byteLength(processedContent, "utf8") / 1024;
|
|
217
293
|
if (sizeKb > config.files.maxFileSizeKb) {
|
|
218
|
-
logger.debug(`[Formatter] File too large: ${
|
|
294
|
+
logger.debug(`[Formatter] File too large: ${displayPath} (${sizeKb.toFixed(2)} KB > ${config.files.maxFileSizeKb} KB)`);
|
|
219
295
|
return null;
|
|
220
296
|
}
|
|
221
297
|
const header = operation === "write"
|
|
222
|
-
? t("tool.file_header.write", { path:
|
|
223
|
-
: t("tool.file_header.edit", { path:
|
|
298
|
+
? t("tool.file_header.write", { path: displayPath })
|
|
299
|
+
: t("tool.file_header.edit", { path: displayPath });
|
|
224
300
|
const fullContent = header + processedContent;
|
|
225
301
|
const buffer = Buffer.from(fullContent, "utf8");
|
|
226
302
|
const basename = path.basename(filePath);
|