opencode-gbk-tools 0.1.22 → 0.1.24

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.
@@ -16238,6 +16238,48 @@ function tool(input) {
16238
16238
  }
16239
16239
  tool.schema = external_exports;
16240
16240
 
16241
+ // src/lib/model-context.ts
16242
+ var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
16243
+ var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
16244
+ var MAX_BASE_OUTPUT_CHARS = 32e3;
16245
+ var MIN_PRESSURED_OUTPUT_CHARS = 1500;
16246
+ var sessionStates = /* @__PURE__ */ new Map();
16247
+ function getSessionState(sessionID) {
16248
+ if (!sessionID) return null;
16249
+ return sessionStates.get(sessionID) ?? null;
16250
+ }
16251
+ function getCompactionPressureFactor(compactionCount) {
16252
+ if (compactionCount >= 3) return 0.35;
16253
+ if (compactionCount === 2) return 0.5;
16254
+ if (compactionCount === 1) return 0.75;
16255
+ return 1;
16256
+ }
16257
+ function getBaseMaxOutputChars(contextTokens, fallback) {
16258
+ if (contextTokens === null) return fallback;
16259
+ const computed = Math.round(contextTokens * 0.01 * 4);
16260
+ return Math.max(MIN_BASE_MAX_OUTPUT_CHARS, Math.min(MAX_BASE_OUTPUT_CHARS, computed));
16261
+ }
16262
+ function buildTruncationSuffix(sessionID, maxChars) {
16263
+ const state = getSessionState(sessionID);
16264
+ if (!state || state.compactionCount === 0) {
16265
+ return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650`;
16266
+ }
16267
+ return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u538B\u7F29 ${state.compactionCount} \u6B21\uFF0C\u5DF2\u81EA\u52A8\u6536\u7D27\u5DE5\u5177\u8F93\u51FA\u9884\u7B97`;
16268
+ }
16269
+ function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
16270
+ const state = getSessionState(sessionID);
16271
+ const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
16272
+ const pressured = Math.round(base * getCompactionPressureFactor(state?.compactionCount ?? 0));
16273
+ return Math.max(MIN_PRESSURED_OUTPUT_CHARS, pressured);
16274
+ }
16275
+ function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
16276
+ const maxChars = getMaxOutputChars(sessionID, fallback);
16277
+ if (content.length <= maxChars) return content;
16278
+ const truncated = content.slice(0, maxChars);
16279
+ return `${truncated}
16280
+ \x1B[2m... (${buildTruncationSuffix(sessionID, maxChars)})\x1B[0m`;
16281
+ }
16282
+
16241
16283
  // src/lib/gbk-file.ts
16242
16284
  var import_iconv_lite = __toESM(require_lib(), 1);
16243
16285
  import crypto from "crypto";
@@ -16307,29 +16349,40 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
16307
16349
  var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
16308
16350
  var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
16309
16351
  var gbkLineIndexCache = /* @__PURE__ */ new Map();
16352
+ var ANSI_RED = "\x1B[31m";
16353
+ var ANSI_GREEN = "\x1B[32m";
16354
+ var ANSI_DIM = "\x1B[2m";
16355
+ var ANSI_RESET = "\x1B[0m";
16356
+ var MAX_DIFF_LINES = 80;
16310
16357
  function buildGbkLineDiffPreview(filePath, encoding, beforeText, afterText) {
16311
16358
  const beforeLines = normalizeNewlines(beforeText).split("\n");
16312
16359
  const afterLines = normalizeNewlines(afterText).split("\n");
16313
16360
  const maxLines = Math.max(beforeLines.length, afterLines.length);
16314
- const lines = [
16315
- `--- ${path2.basename(filePath)} (${encoding})`,
16316
- `+++ ${path2.basename(filePath)} (${encoding})`
16361
+ const header = [
16362
+ `${ANSI_DIM}--- ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`,
16363
+ `${ANSI_DIM}+++ ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`
16317
16364
  ];
16365
+ const body = [];
16318
16366
  for (let index = 0; index < maxLines; index += 1) {
16319
16367
  const before = beforeLines[index];
16320
16368
  const after = afterLines[index];
16321
16369
  if (before !== void 0 && after !== void 0 && before === after) {
16322
- lines.push(` ${before}`);
16370
+ body.push(` ${before}`);
16323
16371
  continue;
16324
16372
  }
16325
16373
  if (before !== void 0) {
16326
- lines.push(`-${before}`);
16374
+ body.push(`${ANSI_RED}-${before}${ANSI_RESET}`);
16327
16375
  }
16328
16376
  if (after !== void 0) {
16329
- lines.push(`+${after}`);
16377
+ body.push(`${ANSI_GREEN}+${after}${ANSI_RESET}`);
16330
16378
  }
16331
16379
  }
16332
- return lines.join("\n");
16380
+ if (header.length + body.length <= MAX_DIFF_LINES) {
16381
+ return "\n" + [...header, ...body].join("\n");
16382
+ }
16383
+ const changedOnly = body.filter((l) => l.startsWith(ANSI_RED) || l.startsWith(ANSI_GREEN));
16384
+ const notice = `${ANSI_DIM}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET}`;
16385
+ return "\n" + [...header, notice, ...changedOnly].join("\n");
16333
16386
  }
16334
16387
  function toSafeNumber(value) {
16335
16388
  return typeof value === "bigint" ? Number(value) : value;
@@ -16353,10 +16406,10 @@ function assertInsertArguments(input) {
16353
16406
  throw createGbkError("GBK_INVALID_ARGUMENT", "content \u4E0D\u80FD\u4E3A\u7A7A");
16354
16407
  }
16355
16408
  if (input.replaceAll !== void 0) {
16356
- throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD\uFFFD? replaceAll");
16409
+ throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? replaceAll");
16357
16410
  }
16358
16411
  if (input.startLine !== void 0 || input.endLine !== void 0 || input.startAnchor !== void 0 || input.endAnchor !== void 0) {
16359
- throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD\uFFFD? startLine/endLine/startAnchor/endAnchor");
16412
+ throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? startLine/endLine/startAnchor/endAnchor");
16360
16413
  }
16361
16414
  }
16362
16415
  function findOccurrenceIndex(text, token, occurrence) {
@@ -16380,9 +16433,9 @@ function findOccurrenceIndex(text, token, occurrence) {
16380
16433
  searchFrom = index + token.length;
16381
16434
  }
16382
16435
  if (count === 0) {
16383
- throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD\uFFFD?: ${token}`);
16436
+ throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${token}`);
16384
16437
  }
16385
- throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD\uFFFD? ${count} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD\uFFFD? ${occurrence} \u5904`);
16438
+ throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD? ${count} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${occurrence} \u5904`);
16386
16439
  }
16387
16440
  function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
16388
16441
  const alignedContent = newlineStyle === "crlf" ? content.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : newlineStyle === "lf" ? content.replace(/\r\n/g, "\n") : content;
@@ -16391,7 +16444,7 @@ function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newli
16391
16444
  const alreadyExists = mode === "insertAfter" ? text.slice(insertionPoint, insertionPoint + alignedContent.length) === alignedContent : text.slice(Math.max(0, insertionPoint - alignedContent.length), insertionPoint) === alignedContent;
16392
16445
  if (alreadyExists) {
16393
16446
  if (ifExists === "error") {
16394
- throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD\uFFFD?");
16447
+ throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
16395
16448
  }
16396
16449
  if (ifExists === "skip") {
16397
16450
  return {
@@ -16432,7 +16485,7 @@ function normalizeOptionalPositiveInteger(value, name) {
16432
16485
  }
16433
16486
  function assertNotBinary(buffer) {
16434
16487
  if (buffer.includes(0)) {
16435
- throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD\uFFFD? GBK \u6587\u672C\u5904\u7406");
16488
+ throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
16436
16489
  }
16437
16490
  }
16438
16491
  function detectNewlineStyle(text) {
@@ -16513,14 +16566,14 @@ function applyAnchors(text, startAnchor, endAnchor) {
16513
16566
  if (startAnchor) {
16514
16567
  const found = text.indexOf(startAnchor);
16515
16568
  if (found === -1) {
16516
- throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD\uFFFD?: ${startAnchor}`);
16569
+ throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD?: ${startAnchor}`);
16517
16570
  }
16518
16571
  rangeStart = found + startAnchor.length;
16519
16572
  }
16520
16573
  if (endAnchor) {
16521
16574
  const found = text.indexOf(endAnchor, rangeStart);
16522
16575
  if (found === -1) {
16523
- throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD\uFFFD?: ${endAnchor}`);
16576
+ throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD?: ${endAnchor}`);
16524
16577
  }
16525
16578
  rangeEnd = found;
16526
16579
  }
@@ -16573,9 +16626,9 @@ function getNearestContext(content, oldString) {
16573
16626
  }
16574
16627
  function buildNoMatchMessage(content, oldString) {
16575
16628
  return [
16576
- "\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD\uFFFD?",
16577
- "oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD\uFFFD?/\u5C3E\u968F\u7A7A\u884C\u4E0A\u5B58\u5728\u8F7B\u5FAE\u5DEE\u5F02\uFFFD\uFFFD?",
16578
- "\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD\uFFFD?",
16629
+ "\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD?",
16630
+ "oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD?/\u5C3E\u968F\u7A7A\u884C\u4E0A\u5B58\u5728\u8F7B\u5FAE\u5DEE\u5F02\uFFFD?",
16631
+ "\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD?",
16579
16632
  getNearestContext(content, oldString)
16580
16633
  ].join("\n");
16581
16634
  }
@@ -16698,10 +16751,10 @@ async function resolveReadableGbkFile(input) {
16698
16751
  try {
16699
16752
  stat = await fs2.stat(candidatePath);
16700
16753
  } catch (error45) {
16701
- throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD\uFFFD?: ${candidatePath}`, error45);
16754
+ throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
16702
16755
  }
16703
16756
  if (stat.isDirectory()) {
16704
- throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD\uFFFD?: ${candidatePath}`);
16757
+ throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
16705
16758
  }
16706
16759
  return {
16707
16760
  filePath: candidatePath,
@@ -16898,7 +16951,7 @@ function replaceScopedTextContent(scopeText, oldString, newString, replaceAll, n
16898
16951
  } else if (occurrencesBefore === 0) {
16899
16952
  throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scopeText, oldString));
16900
16953
  } else if (occurrencesBefore > 1) {
16901
- throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD\uFFFD?: ${oldString}`);
16954
+ throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${oldString}`);
16902
16955
  }
16903
16956
  const alignedNewString = alignTextToNewlineStyle(newString, newlineStyle);
16904
16957
  return {
@@ -17003,7 +17056,7 @@ async function replaceLargeGbkFileByAnchor(input) {
17003
17056
  const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
17004
17057
  if (alreadyExists) {
17005
17058
  if (input.ifExists === "error") {
17006
- throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD\uFFFD?");
17059
+ throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
17007
17060
  }
17008
17061
  if (input.ifExists === "skip") {
17009
17062
  skipped = true;
@@ -17050,7 +17103,7 @@ async function replaceLargeGbkFileByAnchor(input) {
17050
17103
  const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
17051
17104
  if (alreadyExists) {
17052
17105
  if (input.ifExists === "error") {
17053
- throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD\uFFFD?");
17106
+ throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
17054
17107
  }
17055
17108
  if (input.ifExists === "skip") {
17056
17109
  skipped = true;
@@ -17064,10 +17117,10 @@ async function replaceLargeGbkFileByAnchor(input) {
17064
17117
  }
17065
17118
  }
17066
17119
  if (!inserted && totalMatches === 0) {
17067
- throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD\uFFFD?: ${input.anchor}`);
17120
+ throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${input.anchor}`);
17068
17121
  }
17069
17122
  if (!inserted && totalMatches > 0) {
17070
- throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD\uFFFD? ${totalMatches} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD\uFFFD? ${input.occurrence} \u5904`);
17123
+ throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD? ${totalMatches} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${input.occurrence} \u5904`);
17071
17124
  }
17072
17125
  await finalizeInserted();
17073
17126
  await handle.close();
@@ -17130,10 +17183,10 @@ async function replaceLargeGbkFileText(input) {
17130
17183
  });
17131
17184
  await flushText("", true);
17132
17185
  if (occurrencesBefore === 0) {
17133
- throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD\uFFFD?: ${input.oldString}`);
17186
+ throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD?: ${input.oldString}`);
17134
17187
  }
17135
17188
  if (!input.replaceAll && occurrencesBefore > 1) {
17136
- throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD\uFFFD?: ${input.oldString}`);
17189
+ throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${input.oldString}`);
17137
17190
  }
17138
17191
  await handle.close();
17139
17192
  const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
@@ -17282,7 +17335,7 @@ async function replaceGbkFileText(input) {
17282
17335
  } else if (occurrencesBefore === 0) {
17283
17336
  throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, effectiveOldString));
17284
17337
  } else if (occurrencesBefore > 1) {
17285
- throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD\uFFFD?: ${effectiveOldString}`);
17338
+ throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${effectiveOldString}`);
17286
17339
  }
17287
17340
  const fileNewlineStyle = detectNewlineStyle(current.content);
17288
17341
  const alignedNewString = fileNewlineStyle === "crlf" ? input.newString.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : fileNewlineStyle === "lf" ? input.newString.replace(/\r\n/g, "\n") : input.newString;
@@ -17373,8 +17426,8 @@ Insert mode:
17373
17426
  diffPreview
17374
17427
  }
17375
17428
  });
17376
- if (diffPreview) return diffPreview;
17377
- return JSON.stringify(result, null, 2);
17429
+ if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
17430
+ return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
17378
17431
  }
17379
17432
  });
17380
17433
  export {
@@ -16329,7 +16329,7 @@ function normalizeOptionalPositiveInteger(value, name) {
16329
16329
  }
16330
16330
  function assertNotBinary(buffer) {
16331
16331
  if (buffer.includes(0)) {
16332
- throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD\uFFFD? GBK \u6587\u672C\u5904\u7406");
16332
+ throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
16333
16333
  }
16334
16334
  }
16335
16335
  function splitLinesWithNumbers(text, offset = 1, limit = 2e3) {
@@ -16420,10 +16420,10 @@ async function resolveReadableGbkFile(input) {
16420
16420
  try {
16421
16421
  stat = await fs2.stat(candidatePath);
16422
16422
  } catch (error45) {
16423
- throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD\uFFFD?: ${candidatePath}`, error45);
16423
+ throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
16424
16424
  }
16425
16425
  if (stat.isDirectory()) {
16426
- throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD\uFFFD?: ${candidatePath}`);
16426
+ throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
16427
16427
  }
16428
16428
  return {
16429
16429
  filePath: candidatePath,
@@ -16313,7 +16313,7 @@ function assertEncodingSupported(encoding) {
16313
16313
  }
16314
16314
  function assertNotBinary(buffer) {
16315
16315
  if (buffer.includes(0)) {
16316
- throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD\uFFFD? GBK \u6587\u672C\u5904\u7406");
16316
+ throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
16317
16317
  }
16318
16318
  }
16319
16319
  async function resolveReadableGbkFile(input) {
@@ -16324,10 +16324,10 @@ async function resolveReadableGbkFile(input) {
16324
16324
  try {
16325
16325
  stat = await fs2.stat(candidatePath);
16326
16326
  } catch (error45) {
16327
- throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD\uFFFD?: ${candidatePath}`, error45);
16327
+ throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
16328
16328
  }
16329
16329
  if (stat.isDirectory()) {
16330
- throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD\uFFFD?: ${candidatePath}`);
16330
+ throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
16331
16331
  }
16332
16332
  return {
16333
16333
  filePath: candidatePath,
@@ -16370,10 +16370,10 @@ async function writeGbkFile(input) {
16370
16370
  try {
16371
16371
  const stat = await fs2.stat(candidatePath);
16372
16372
  if (stat.isDirectory()) {
16373
- throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD\uFFFD?: ${candidatePath}`);
16373
+ throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
16374
16374
  }
16375
16375
  if (!overwrite) {
16376
- throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD\uFFFD?: ${candidatePath}`);
16376
+ throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD?: ${candidatePath}`);
16377
16377
  }
16378
16378
  } catch (error45) {
16379
16379
  if (error45 instanceof Error && "code" in error45) {
@@ -16238,6 +16238,48 @@ function tool(input) {
16238
16238
  }
16239
16239
  tool.schema = external_exports;
16240
16240
 
16241
+ // src/lib/model-context.ts
16242
+ var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
16243
+ var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
16244
+ var MAX_BASE_OUTPUT_CHARS = 32e3;
16245
+ var MIN_PRESSURED_OUTPUT_CHARS = 1500;
16246
+ var sessionStates = /* @__PURE__ */ new Map();
16247
+ function getSessionState(sessionID) {
16248
+ if (!sessionID) return null;
16249
+ return sessionStates.get(sessionID) ?? null;
16250
+ }
16251
+ function getCompactionPressureFactor(compactionCount) {
16252
+ if (compactionCount >= 3) return 0.35;
16253
+ if (compactionCount === 2) return 0.5;
16254
+ if (compactionCount === 1) return 0.75;
16255
+ return 1;
16256
+ }
16257
+ function getBaseMaxOutputChars(contextTokens, fallback) {
16258
+ if (contextTokens === null) return fallback;
16259
+ const computed = Math.round(contextTokens * 0.01 * 4);
16260
+ return Math.max(MIN_BASE_MAX_OUTPUT_CHARS, Math.min(MAX_BASE_OUTPUT_CHARS, computed));
16261
+ }
16262
+ function buildTruncationSuffix(sessionID, maxChars) {
16263
+ const state = getSessionState(sessionID);
16264
+ if (!state || state.compactionCount === 0) {
16265
+ return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650`;
16266
+ }
16267
+ return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u538B\u7F29 ${state.compactionCount} \u6B21\uFF0C\u5DF2\u81EA\u52A8\u6536\u7D27\u5DE5\u5177\u8F93\u51FA\u9884\u7B97`;
16268
+ }
16269
+ function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
16270
+ const state = getSessionState(sessionID);
16271
+ const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
16272
+ const pressured = Math.round(base * getCompactionPressureFactor(state?.compactionCount ?? 0));
16273
+ return Math.max(MIN_PRESSURED_OUTPUT_CHARS, pressured);
16274
+ }
16275
+ function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
16276
+ const maxChars = getMaxOutputChars(sessionID, fallback);
16277
+ if (content.length <= maxChars) return content;
16278
+ const truncated = content.slice(0, maxChars);
16279
+ return `${truncated}
16280
+ \x1B[2m... (${buildTruncationSuffix(sessionID, maxChars)})\x1B[0m`;
16281
+ }
16282
+
16241
16283
  // src/lib/text-file.ts
16242
16284
  var import_iconv_lite2 = __toESM(require_lib(), 1);
16243
16285
  import crypto2 from "crypto";
@@ -16577,29 +16619,40 @@ function assertInsertArguments(input) {
16577
16619
  throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\u6301 startLine/endLine/startAnchor/endAnchor");
16578
16620
  }
16579
16621
  }
16622
+ var ANSI_RED = "\x1B[31m";
16623
+ var ANSI_GREEN = "\x1B[32m";
16624
+ var ANSI_DIM = "\x1B[2m";
16625
+ var ANSI_RESET = "\x1B[0m";
16626
+ var MAX_DIFF_LINES = 80;
16580
16627
  function buildLineDiffPreview(filePath, encoding, beforeText, afterText) {
16581
16628
  const beforeLines = normalizeNewlines(beforeText).split("\n");
16582
16629
  const afterLines = normalizeNewlines(afterText).split("\n");
16583
16630
  const maxLines = Math.max(beforeLines.length, afterLines.length);
16584
- const lines = [
16585
- `--- ${path3.basename(filePath)} (${encoding})`,
16586
- `+++ ${path3.basename(filePath)} (${encoding})`
16631
+ const header = [
16632
+ `${ANSI_DIM}--- ${path3.basename(filePath)} (${encoding})${ANSI_RESET}`,
16633
+ `${ANSI_DIM}+++ ${path3.basename(filePath)} (${encoding})${ANSI_RESET}`
16587
16634
  ];
16635
+ const body = [];
16588
16636
  for (let index = 0; index < maxLines; index += 1) {
16589
16637
  const before = beforeLines[index];
16590
16638
  const after = afterLines[index];
16591
16639
  if (before !== void 0 && after !== void 0 && before === after) {
16592
- lines.push(` ${before}`);
16640
+ body.push(` ${before}`);
16593
16641
  continue;
16594
16642
  }
16595
16643
  if (before !== void 0) {
16596
- lines.push(`-${before}`);
16644
+ body.push(`${ANSI_RED}-${before}${ANSI_RESET}`);
16597
16645
  }
16598
16646
  if (after !== void 0) {
16599
- lines.push(`+${after}`);
16647
+ body.push(`${ANSI_GREEN}+${after}${ANSI_RESET}`);
16600
16648
  }
16601
16649
  }
16602
- return lines.join("\n");
16650
+ if (header.length + body.length <= MAX_DIFF_LINES) {
16651
+ return "\n" + [...header, ...body].join("\n");
16652
+ }
16653
+ const changedOnly = body.filter((l) => l.startsWith(ANSI_RED) || l.startsWith(ANSI_GREEN));
16654
+ const notice = `${ANSI_DIM}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET}`;
16655
+ return "\n" + [...header, notice, ...changedOnly].join("\n");
16603
16656
  }
16604
16657
  function buildInsertOutput(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
16605
16658
  const alignedContent = alignTextToNewlineStyle(content, newlineStyle);
@@ -16975,7 +17028,7 @@ async function replaceTextFileText(input) {
16975
17028
  bytesRead: loaded.bytesRead,
16976
17029
  bytesWritten: buffer.byteLength,
16977
17030
  newlineStyle: detectNewlineStyle(outputText),
16978
- diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding, scope.selectedText, replaced)
17031
+ diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding, input.oldString, alignedNewString)
16979
17032
  };
16980
17033
  }
16981
17034
 
@@ -17030,8 +17083,8 @@ var text_edit_default = tool({
17030
17083
  diffPreview
17031
17084
  }
17032
17085
  });
17033
- if (diffPreview) return diffPreview;
17034
- return JSON.stringify(result, null, 2);
17086
+ if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
17087
+ return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
17035
17088
  }
17036
17089
  });
17037
17090
  export {