aws-runtime-bridge 1.9.40 → 1.9.41

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.
Files changed (110) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +31 -4
  2. package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
  3. package/dist/adapter/AcodeSdkAdapter.js +382 -57
  4. package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
  5. package/dist/adapter/ClaudeSdkAdapter.js +1 -0
  6. package/dist/adapter/OpencodeSdkAdapter.d.ts +19 -0
  7. package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
  8. package/dist/adapter/OpencodeSdkAdapter.js +62 -0
  9. package/dist/adapter/types.d.ts +21 -6
  10. package/dist/adapter/types.d.ts.map +1 -1
  11. package/dist/adapter/types.js +10 -1
  12. package/dist/index.js +11 -0
  13. package/dist/routes/ai-sources.js +4 -1
  14. package/dist/routes/dashboard.d.ts.map +1 -1
  15. package/dist/routes/dashboard.js +1 -1
  16. package/dist/routes/runtime-binding.d.ts.map +1 -1
  17. package/dist/routes/runtime-binding.js +6 -3
  18. package/dist/routes/sessions.js +89 -4
  19. package/dist/routes/sub-agents.js +15 -1
  20. package/dist/routes/terminal.d.ts +3 -0
  21. package/dist/routes/terminal.d.ts.map +1 -1
  22. package/dist/routes/terminal.js +122 -5
  23. package/dist/services/acode-package.d.ts +8 -1
  24. package/dist/services/acode-package.d.ts.map +1 -1
  25. package/dist/services/acode-package.js +33 -4
  26. package/dist/services/aws-client-agent-mcp.d.ts.map +1 -1
  27. package/dist/services/aws-client-agent-mcp.js +11 -4
  28. package/dist/services/fileSnapshotStore.js +1 -1
  29. package/dist/services/legacy-path-migration.d.ts +3 -0
  30. package/dist/services/legacy-path-migration.d.ts.map +1 -0
  31. package/dist/services/legacy-path-migration.js +66 -0
  32. package/dist/services/lifecycle-state.d.ts.map +1 -1
  33. package/dist/services/lifecycle-state.js +1 -1
  34. package/dist/services/runtime-binding.d.ts +5 -0
  35. package/dist/services/runtime-binding.d.ts.map +1 -1
  36. package/dist/services/runtime-binding.js +33 -1
  37. package/dist/services/session-output.d.ts +7 -1
  38. package/dist/services/session-output.d.ts.map +1 -1
  39. package/dist/services/session-output.js +16 -2
  40. package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
  41. package/package/acode/dist/built-in-file-tools.js +504 -3
  42. package/package/acode/dist/compaction.d.ts +43 -7
  43. package/package/acode/dist/compaction.d.ts.map +1 -1
  44. package/package/acode/dist/compaction.js +286 -31
  45. package/package/acode/dist/runtime.d.ts +120 -0
  46. package/package/acode/dist/runtime.d.ts.map +1 -1
  47. package/package/acode/dist/runtime.js +921 -71
  48. package/package/acode/dist/sub-agent-manager.d.ts +96 -1
  49. package/package/acode/dist/sub-agent-manager.d.ts.map +1 -1
  50. package/package/acode/dist/sub-agent-manager.js +293 -3
  51. package/package/acode/dist/sub-agent-store.d.ts +8 -1
  52. package/package/acode/dist/sub-agent-store.d.ts.map +1 -1
  53. package/package/acode/dist/sub-agent-store.js +55 -0
  54. package/package/acode/dist/sub-agent-types.d.ts +4 -0
  55. package/package/acode/dist/sub-agent-types.d.ts.map +1 -1
  56. package/package/acode/dist/types.d.ts +19 -0
  57. package/package/acode/dist/types.d.ts.map +1 -1
  58. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +9 -0
  59. package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
  60. package/package/aws-client-agent-mcp/dist/agent-client.js +69 -10
  61. package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
  62. package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
  63. package/package/aws-client-agent-mcp/dist/config.js +4 -0
  64. package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
  65. package/package/aws-client-agent-mcp/dist/constants.d.ts +2 -0
  66. package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -1
  67. package/package/aws-client-agent-mcp/dist/constants.js +3 -1
  68. package/package/aws-client-agent-mcp/dist/constants.js.map +1 -1
  69. package/package/aws-client-agent-mcp/dist/context-manager.d.ts +4 -1
  70. package/package/aws-client-agent-mcp/dist/context-manager.d.ts.map +1 -1
  71. package/package/aws-client-agent-mcp/dist/context-manager.js +6 -2
  72. package/package/aws-client-agent-mcp/dist/context-manager.js.map +1 -1
  73. package/package/aws-client-agent-mcp/dist/context-manager.test.js +5 -0
  74. package/package/aws-client-agent-mcp/dist/context-manager.test.js.map +1 -1
  75. package/package/aws-client-agent-mcp/dist/http-client.d.ts +5 -0
  76. package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
  77. package/package/aws-client-agent-mcp/dist/http-client.js +15 -1
  78. package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
  79. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +92 -34
  80. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
  81. package/package/aws-client-agent-mcp/dist/mcp-server.js +606 -208
  82. package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
  83. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +151 -51
  84. package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
  85. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +7 -0
  86. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
  87. package/package/aws-client-agent-mcp/dist/mcp-tools.js +18 -0
  88. package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
  89. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +32 -9
  90. package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +1 -1
  91. package/package/aws-client-agent-mcp/dist/memory-store.js +58 -19
  92. package/package/aws-client-agent-mcp/dist/memory-store.js.map +1 -1
  93. package/package/aws-client-agent-mcp/dist/memory-tools.js +3 -3
  94. package/package/aws-client-agent-mcp/dist/memory-tools.js.map +1 -1
  95. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +13 -0
  96. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts.map +1 -1
  97. package/package/aws-client-agent-mcp/dist/message-buffer.js +23 -0
  98. package/package/aws-client-agent-mcp/dist/message-buffer.js.map +1 -1
  99. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +13 -0
  100. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts.map +1 -1
  101. package/package/aws-client-agent-mcp/dist/server-memory-store.js +18 -0
  102. package/package/aws-client-agent-mcp/dist/server-memory-store.js.map +1 -1
  103. package/package/aws-client-agent-mcp/dist/types.d.ts +9 -0
  104. package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
  105. package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
  106. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +34 -1
  107. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
  108. package/package/aws-client-agent-mcp/dist/websocket-client.js +146 -18
  109. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
  110. package/package.json +1 -1
@@ -1,7 +1,36 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { promises as fs } from "node:fs";
2
+ import { promises as fs, createReadStream } from "node:fs";
3
3
  import path from "node:path";
4
+ import readline from "node:readline";
4
5
  import { runShellCommand, } from "./builtins/shellCommandRunner.js";
6
+ // ── read_file pagination & truncation constants ──────────────────────────────
7
+ const DEFAULT_READ_LIMIT = 2000;
8
+ const MAX_LINE_LENGTH = 2000;
9
+ const MAX_READ_BYTES = 50 * 1024; // 50 KB
10
+ const BINARY_SAMPLE_BYTES = 4096;
11
+ const BINARY_NON_PRINTABLE_RATIO = 0.3;
12
+ const BINARY_EXTENSIONS = new Set([
13
+ ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".webp", ".tiff", ".tif",
14
+ ".zip", ".gz", ".tar", ".rar", ".7z", ".bz2", ".xz", ".lz",
15
+ ".exe", ".dll", ".so", ".dylib", ".bin", ".o", ".a",
16
+ ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
17
+ ".mp3", ".mp4", ".avi", ".mov", ".wav", ".flv", ".mkv", ".ogg",
18
+ ".woff", ".woff2", ".ttf", ".otf", ".eot",
19
+ ".class", ".jar", ".war", ".ear",
20
+ ".pyc", ".pyo", ".node",
21
+ ".sqlite", ".db", ".mdb",
22
+ ".wasm",
23
+ ]);
24
+ // ─────────────────────────────────────────────────────────────────────────────
25
+ // ── grep search constants ────────────────────────────────────────────────────
26
+ const MAX_GREP_FILES = 1000;
27
+ const MAX_GREP_FILE_SIZE = 1024 * 1024; // 1 MB – skip larger files
28
+ const MAX_GREP_OUTPUT_BYTES = 256 * 1024; // 256 KB – cap total output
29
+ const DEFAULT_GREP_MAX_RESULTS = 1000;
30
+ const GREP_SKIP_DIRS = new Set([
31
+ ".git", "node_modules", "dist", "build", ".next", ".nuxt",
32
+ ".cache", ".turbo", ".output", "coverage", ".nyc_output",
33
+ ]);
5
34
  function toDisplayPath(targetPath) {
6
35
  return targetPath.replace(/\\/g, "/");
7
36
  }
@@ -58,6 +87,42 @@ function readOptionalPositiveIntegerArg(args, names, fallback) {
58
87
  }
59
88
  return fallback;
60
89
  }
90
+ /**
91
+ * 检测文件是否为二进制文件。
92
+ * 主流程:先查扩展名黑名单 -> 再采样前 4KB 检测 NUL 字节或高比例不可见字符。
93
+ */
94
+ async function isBinaryFile(filePath) {
95
+ const ext = path.extname(filePath).toLowerCase();
96
+ if (BINARY_EXTENSIONS.has(ext)) {
97
+ return true;
98
+ }
99
+ const handle = await fs.open(filePath, "r");
100
+ try {
101
+ const buffer = Buffer.alloc(BINARY_SAMPLE_BYTES);
102
+ const { bytesRead } = await handle.read(buffer, 0, BINARY_SAMPLE_BYTES, 0);
103
+ if (bytesRead === 0) {
104
+ return false;
105
+ }
106
+ const sample = buffer.subarray(0, bytesRead);
107
+ // NUL byte = definitely binary
108
+ if (sample.includes(0)) {
109
+ return true;
110
+ }
111
+ // >30% non-printable characters = likely binary
112
+ let nonPrintable = 0;
113
+ for (let i = 0; i < bytesRead; i++) {
114
+ const byte = sample[i];
115
+ // Allow: tab(0x09), LF(0x0a), CR(0x0d), printable ASCII (0x20-0x7e), UTF-8 high bytes (0x80-0xff)
116
+ if (byte < 0x09 || (byte > 0x0d && byte < 0x20)) {
117
+ nonPrintable++;
118
+ }
119
+ }
120
+ return nonPrintable / bytesRead > BINARY_NON_PRINTABLE_RATIO;
121
+ }
122
+ finally {
123
+ await handle.close();
124
+ }
125
+ }
61
126
  function ensureInsideWorkspace(workspaceRoot, targetPath) {
62
127
  const resolvedTargetPath = path.resolve(targetPath);
63
128
  const relativePath = path.relative(workspaceRoot, resolvedTargetPath);
@@ -178,6 +243,249 @@ async function readFileInsideWorkspace(workingDirectory, filePath) {
178
243
  content: await fs.readFile(realTargetPath, "utf-8"),
179
244
  };
180
245
  }
246
+ /**
247
+ * 分页流式读取工作区内文本文件,带行号前缀、双重截断上限和续读提示。
248
+ *
249
+ * 主流程:
250
+ * 1. 路径解析与安全校验(复用 resolveWorkspaceTarget + ensureInsideWorkspace + realpath)
251
+ * 2. 二进制检测(扩展名黑名单 + 4KB 采样)
252
+ * 3. createReadStream + readline 逐行流式读取,跳过 offset 前行
253
+ * 4. 收集 limit 行,同时持续计数总行数(用于底部提示)
254
+ * 5. 双重上限:行数 2000 + 字节 50KB,先触发先截断
255
+ * 6. 拼装行号前缀 + 底部续读提示
256
+ *
257
+ * 不修改 readFileInsideWorkspace,edit_file 仍使用全量读取。
258
+ */
259
+ async function readFileWithPagination(workingDirectory, filePath, offset, limit) {
260
+ const target = await resolveWorkspaceTarget(workingDirectory, filePath);
261
+ const realTargetPath = ensureInsideWorkspace(target.workspaceRoot, await fs.realpath(target.targetPath));
262
+ const stat = await fs.stat(realTargetPath);
263
+ if (!stat.isFile()) {
264
+ throw new Error(`Path is not a file: ${realTargetPath}`);
265
+ }
266
+ // ── 二进制检测 ──
267
+ if (await isBinaryFile(realTargetPath)) {
268
+ return {
269
+ workspaceRoot: target.workspaceRoot,
270
+ targetPath: realTargetPath,
271
+ content: "[Binary file, content skipped]",
272
+ isBinary: true,
273
+ truncated: false,
274
+ totalLines: 0,
275
+ shownFromLine: 0,
276
+ shownToLine: 0,
277
+ };
278
+ }
279
+ // ── 流式逐行读取 ──
280
+ const stream = createReadStream(realTargetPath, { encoding: "utf-8" });
281
+ const rl = readline.createInterface({
282
+ input: stream,
283
+ crlfDelay: Infinity,
284
+ });
285
+ try {
286
+ const outputLines = [];
287
+ let lineNumber = 0; // 0-indexed 内部计数
288
+ let totalLines = 0;
289
+ let bytes = 0;
290
+ let truncatedByLines = false;
291
+ let truncatedByBytes = false;
292
+ const startIndex = offset - 1; // 转为 0-indexed
293
+ for await (const text of rl) {
294
+ totalLines++;
295
+ // 跳过 offset 前的行
296
+ if (lineNumber < startIndex) {
297
+ lineNumber++;
298
+ continue;
299
+ }
300
+ // 已达 limit 上限:停止收集但继续计数
301
+ if (outputLines.length >= limit) {
302
+ truncatedByLines = true;
303
+ lineNumber++;
304
+ continue;
305
+ }
306
+ // 单行截断
307
+ let line = text;
308
+ if (line.length > MAX_LINE_LENGTH) {
309
+ line =
310
+ line.slice(0, MAX_LINE_LENGTH) +
311
+ `... (line truncated to ${MAX_LINE_LENGTH} chars)`;
312
+ }
313
+ const numberedLine = `${lineNumber + 1}: ${line}`;
314
+ const lineBytes = Buffer.byteLength(numberedLine, "utf-8") + 1; // +1 for \n
315
+ // 字节上限:停止读取(totalLines 不再准确)
316
+ if (bytes + lineBytes > MAX_READ_BYTES) {
317
+ truncatedByBytes = true;
318
+ break;
319
+ }
320
+ outputLines.push(numberedLine);
321
+ bytes += lineBytes;
322
+ lineNumber++;
323
+ }
324
+ // offset 超出文件总行数(空文件除外)
325
+ if (totalLines > 0 &&
326
+ outputLines.length === 0 &&
327
+ !truncatedByLines &&
328
+ !truncatedByBytes &&
329
+ startIndex >= totalLines) {
330
+ throw new Error(`offset ${offset} exceeds total line count ${totalLines} in file: ${realTargetPath}`);
331
+ }
332
+ const shownFromLine = outputLines.length > 0 ? offset : 0;
333
+ const shownToLine = outputLines.length > 0 ? offset + outputLines.length - 1 : 0;
334
+ // ── 底部续读提示 ──
335
+ let footer;
336
+ if (truncatedByBytes) {
337
+ footer = `Output capped at 50 KB. Showing lines ${shownFromLine}-${shownToLine}. Use offset=${shownToLine + 1} to continue.`;
338
+ }
339
+ else if (truncatedByLines) {
340
+ footer = `Showing lines ${shownFromLine}-${shownToLine} of ${totalLines}. Use offset=${shownToLine + 1} to continue.`;
341
+ }
342
+ else {
343
+ footer = `End of file - total ${totalLines} lines`;
344
+ }
345
+ const content = outputLines.length > 0
346
+ ? outputLines.join("\n") + "\n" + footer
347
+ : footer;
348
+ return {
349
+ workspaceRoot: target.workspaceRoot,
350
+ targetPath: realTargetPath,
351
+ content,
352
+ isBinary: false,
353
+ truncated: truncatedByLines || truncatedByBytes,
354
+ totalLines: truncatedByBytes ? -1 : totalLines,
355
+ shownFromLine,
356
+ shownToLine,
357
+ };
358
+ }
359
+ finally {
360
+ rl.close();
361
+ stream.destroy();
362
+ }
363
+ }
364
+ // ── grep helpers ──────────────────────────────────────────────────────────────
365
+ /**
366
+ * 将 glob 通配符转换为 RegExp(匹配文件 basename)。
367
+ * 支持:* (不跨 / ), ? (单个非 / 字符), {a,b} (分组), [abc] (字符类)。
368
+ */
369
+ function globToRegex(pattern) {
370
+ let regex = "";
371
+ let i = 0;
372
+ while (i < pattern.length) {
373
+ const char = pattern[i];
374
+ if (char === "*") {
375
+ regex += "[^/]*";
376
+ }
377
+ else if (char === "?") {
378
+ regex += "[^/]";
379
+ }
380
+ else if (char === "{") {
381
+ const end = pattern.indexOf("}", i);
382
+ if (end >= 0) {
383
+ const content = pattern.slice(i + 1, end);
384
+ regex += `(${content.split(",").join("|")})`;
385
+ i = end;
386
+ }
387
+ else {
388
+ regex += "\\{";
389
+ }
390
+ }
391
+ else if (char === "[") {
392
+ const end = pattern.indexOf("]", i);
393
+ if (end >= 0) {
394
+ regex += pattern.slice(i, end + 1);
395
+ i = end;
396
+ }
397
+ else {
398
+ regex += "\\[";
399
+ }
400
+ }
401
+ else if ("+^$.()|\\".includes(char)) {
402
+ regex += "\\" + char;
403
+ }
404
+ else {
405
+ regex += char;
406
+ }
407
+ i++;
408
+ }
409
+ return new RegExp(`^${regex}$`);
410
+ }
411
+ /**
412
+ * 递归遍历目录,返回所有匹配 include/exclude 的文件路径。
413
+ * 主流程:readdir -> 跳过 GREP_SKIP_DIRS 和隐藏目录 -> 递归子目录 -> 过滤文件名。
414
+ */
415
+ async function walkDirectory(dir, includeRegex, excludeRegex, maxFiles) {
416
+ const results = [];
417
+ async function walk(currentDir) {
418
+ if (results.length >= maxFiles)
419
+ return;
420
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
421
+ for (const entry of entries) {
422
+ if (results.length >= maxFiles)
423
+ return;
424
+ if (entry.name.startsWith(".") && entry.isDirectory())
425
+ continue;
426
+ const fullPath = path.join(currentDir, entry.name);
427
+ if (entry.isDirectory()) {
428
+ if (GREP_SKIP_DIRS.has(entry.name))
429
+ continue;
430
+ await walk(fullPath);
431
+ }
432
+ else if (entry.isFile()) {
433
+ if (includeRegex && !includeRegex.test(entry.name))
434
+ continue;
435
+ if (excludeRegex && excludeRegex.test(entry.name))
436
+ continue;
437
+ results.push(fullPath);
438
+ }
439
+ }
440
+ }
441
+ await walk(dir);
442
+ return results;
443
+ }
444
+ /**
445
+ * 在单个文件中搜索正则匹配,返回匹配行(含行号)或计数。
446
+ * 主流程:文件大小检查 -> 二进制检测 -> 流式逐行读取 -> 正则匹配 -> 收集结果。
447
+ */
448
+ async function searchInFile(filePath, workspaceRoot, options) {
449
+ const stat = await fs.stat(filePath);
450
+ if (stat.size > MAX_GREP_FILE_SIZE) {
451
+ return { matches: [], count: 0 };
452
+ }
453
+ if (await isBinaryFile(filePath)) {
454
+ return { matches: [], count: 0 };
455
+ }
456
+ const relativePath = path.relative(workspaceRoot, filePath).replace(/\\/g, "/");
457
+ const matches = [];
458
+ let count = 0;
459
+ const stream = createReadStream(filePath, { encoding: "utf-8" });
460
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
461
+ try {
462
+ let lineNumber = 0;
463
+ for await (const text of rl) {
464
+ lineNumber++;
465
+ if (options.regex.test(text)) {
466
+ count++;
467
+ if (options.collectContent) {
468
+ let content = text;
469
+ if (content.length > MAX_LINE_LENGTH) {
470
+ content =
471
+ content.slice(0, MAX_LINE_LENGTH) +
472
+ `... (line truncated to ${MAX_LINE_LENGTH} chars)`;
473
+ }
474
+ matches.push({ file: relativePath, line: lineNumber, content });
475
+ if (matches.length >= options.maxResults)
476
+ break;
477
+ }
478
+ if (options.stopOnFirstMatch)
479
+ break;
480
+ }
481
+ }
482
+ }
483
+ finally {
484
+ rl.close();
485
+ stream.destroy();
486
+ }
487
+ return { matches, count };
488
+ }
181
489
  const MAX_COMMAND_TIMEOUT_MS = 10 * 60_000;
182
490
  const DEFAULT_COMMAND_TIMEOUT_MS = MAX_COMMAND_TIMEOUT_MS;
183
491
  const DEFAULT_COMMAND_INACTIVITY_TIMEOUT_MS = 60_000;
@@ -273,7 +581,12 @@ function readFileTool(workingDirectory) {
273
581
  kind: "builtin",
274
582
  toolName: "read_file",
275
583
  exposedName: "read_file",
276
- description: "Read a UTF-8 text file inside the current workspace.",
584
+ description: "Read a UTF-8 text file inside the current workspace. " +
585
+ "Returns content with line numbers in the format '<line>: <content>'. " +
586
+ "Supports offset (1-indexed line number to start from) and limit (max lines to return, default 2000). " +
587
+ "Output is capped at 2000 lines or 50 KB, whichever is reached first. " +
588
+ "Individual lines longer than 2000 characters are truncated. " +
589
+ "Avoid tiny repeated slices (e.g. 30-line chunks); read a larger window if more context is needed.",
277
590
  inputSchema: {
278
591
  type: "object",
279
592
  properties: {
@@ -281,19 +594,34 @@ function readFileTool(workingDirectory) {
281
594
  type: "string",
282
595
  description: "Workspace-relative file path to read.",
283
596
  },
597
+ offset: {
598
+ type: "number",
599
+ description: "Line number to start reading from (1-indexed). Defaults to 1.",
600
+ },
601
+ limit: {
602
+ type: "number",
603
+ description: "Maximum number of lines to return. Defaults to 2000.",
604
+ },
284
605
  },
285
606
  required: ["file_path"],
286
607
  additionalProperties: false,
287
608
  },
288
609
  async execute(args) {
289
610
  const filePath = readStringArg(args, ["file_path", "filePath"], "file_path");
290
- const result = await readFileInsideWorkspace(workingDirectory, filePath);
611
+ const offset = readOptionalPositiveIntegerArg(args, ["offset"], 1);
612
+ const limit = readOptionalPositiveIntegerArg(args, ["limit"], DEFAULT_READ_LIMIT);
613
+ const result = await readFileWithPagination(workingDirectory, filePath, offset, limit);
291
614
  return {
292
615
  ok: true,
293
616
  tool: "read_file",
294
617
  workspacePath: toDisplayPath(result.workspaceRoot),
295
618
  filePath: toDisplayPath(result.targetPath),
296
619
  content: result.content,
620
+ isBinary: result.isBinary,
621
+ truncated: result.truncated,
622
+ totalLines: result.totalLines,
623
+ shownFromLine: result.shownFromLine,
624
+ shownToLine: result.shownToLine,
297
625
  };
298
626
  },
299
627
  };
@@ -371,12 +699,185 @@ function bashTool(workingDirectory, agentId) {
371
699
  },
372
700
  };
373
701
  }
702
+ function grepTool(workingDirectory) {
703
+ return {
704
+ kind: "builtin",
705
+ toolName: "grep",
706
+ exposedName: "grep",
707
+ description: "Search file contents using regular expressions within the workspace. " +
708
+ "Returns matched lines with file paths and line numbers. " +
709
+ "Supports include/exclude glob patterns, case-insensitive matching, and three output modes " +
710
+ "(content, files_with_matches, count). Searches recursively through directories, " +
711
+ "skipping binary files, hidden directories, and common build/dependency directories (node_modules, .git, dist, etc.).",
712
+ inputSchema: {
713
+ type: "object",
714
+ properties: {
715
+ pattern: {
716
+ type: "string",
717
+ description: "Regular expression pattern to search for in file contents.",
718
+ },
719
+ path: {
720
+ type: "string",
721
+ description: "Workspace-relative file or directory path to search in. Defaults to the workspace root.",
722
+ },
723
+ include: {
724
+ type: "string",
725
+ description: "Glob pattern to filter files by name (e.g. '*.ts', '*.{js,ts}'). Only matching files are searched.",
726
+ },
727
+ exclude: {
728
+ type: "string",
729
+ description: "Glob pattern to exclude files by name (e.g. '*.test.ts'). Matching files are skipped.",
730
+ },
731
+ case_insensitive: {
732
+ type: "boolean",
733
+ description: "Case-insensitive matching. Default false.",
734
+ },
735
+ output_mode: {
736
+ type: "string",
737
+ enum: ["content", "files_with_matches", "count"],
738
+ description: "Output format: 'content' returns matched lines with line numbers (default), " +
739
+ "'files_with_matches' returns only file paths with matches, " +
740
+ "'count' returns match counts per file.",
741
+ },
742
+ max_results: {
743
+ type: "number",
744
+ description: "Maximum number of matched lines to return (content mode). Default 1000.",
745
+ },
746
+ },
747
+ required: ["pattern"],
748
+ additionalProperties: false,
749
+ },
750
+ /**
751
+ * grep 工具执行主流程:
752
+ * 1. 解析参数(pattern, path, include/exclude, output_mode 等)
753
+ * 2. 编译正则(含 case_insensitive 标志)
754
+ * 3. 解析搜索路径并校验 workspace 边界
755
+ * 4. 收集待搜索文件列表(单文件或递归遍历目录)
756
+ * 5. 逐文件搜索(流式读取 + 正则匹配)
757
+ * 6. 根据 output_mode 构建响应
758
+ */
759
+ async execute(args) {
760
+ const pattern = readStringArg(args, ["pattern"], "pattern");
761
+ const searchPath = readOptionalStringArg(args, ["path"]) || ".";
762
+ const includeGlob = readOptionalStringArg(args, ["include"]);
763
+ const excludeGlob = readOptionalStringArg(args, ["exclude"]);
764
+ const caseInsensitive = args.case_insensitive === true;
765
+ const outputMode = (() => {
766
+ const mode = args.output_mode;
767
+ if (mode === "files_with_matches" || mode === "count")
768
+ return mode;
769
+ return "content";
770
+ })();
771
+ const maxResults = readOptionalPositiveIntegerArg(args, ["max_results"], DEFAULT_GREP_MAX_RESULTS);
772
+ // ── 编译正则 ──
773
+ const flags = caseInsensitive ? "i" : "";
774
+ let regex;
775
+ try {
776
+ regex = new RegExp(pattern, flags);
777
+ }
778
+ catch (error) {
779
+ throw new Error(`Invalid regex pattern: ${error instanceof Error ? error.message : String(error)}`);
780
+ }
781
+ const includeRegex = includeGlob ? globToRegex(includeGlob) : null;
782
+ const excludeRegex = excludeGlob ? globToRegex(excludeGlob) : null;
783
+ // ── 解析搜索路径(复用 workspace 安全校验) ──
784
+ const target = await resolveWorkspaceTarget(workingDirectory, searchPath);
785
+ const realTargetPath = ensureInsideWorkspace(target.workspaceRoot, await fs.realpath(target.targetPath));
786
+ const targetStat = await fs.stat(realTargetPath);
787
+ // ── 收集文件列表 ──
788
+ let files;
789
+ if (targetStat.isFile()) {
790
+ files = [realTargetPath];
791
+ }
792
+ else if (targetStat.isDirectory()) {
793
+ files = await walkDirectory(realTargetPath, includeRegex, excludeRegex, MAX_GREP_FILES);
794
+ }
795
+ else {
796
+ throw new Error(`Path is neither a file nor a directory: ${realTargetPath}`);
797
+ }
798
+ // ── 逐文件搜索 ──
799
+ const allMatches = [];
800
+ const fileCounts = [];
801
+ const matchedFiles = [];
802
+ let totalMatches = 0;
803
+ let outputBytes = 0;
804
+ let truncated = false;
805
+ for (const filePath of files) {
806
+ // content 模式:全局 maxResults 上限
807
+ if (outputMode === "content" && allMatches.length >= maxResults) {
808
+ truncated = true;
809
+ break;
810
+ }
811
+ const searchOptions = {
812
+ regex,
813
+ maxResults: outputMode === "content"
814
+ ? maxResults - allMatches.length
815
+ : Number.MAX_SAFE_INTEGER,
816
+ collectContent: outputMode === "content",
817
+ stopOnFirstMatch: outputMode === "files_with_matches",
818
+ };
819
+ const result = await searchInFile(filePath, target.workspaceRoot, searchOptions);
820
+ if (result.count > 0) {
821
+ const relativePath = path
822
+ .relative(target.workspaceRoot, filePath)
823
+ .replace(/\\/g, "/");
824
+ matchedFiles.push(relativePath);
825
+ totalMatches += result.count;
826
+ if (outputMode === "content") {
827
+ for (const match of result.matches) {
828
+ const matchBytes = Buffer.byteLength(match.content, "utf-8") + 64;
829
+ if (outputBytes + matchBytes > MAX_GREP_OUTPUT_BYTES) {
830
+ truncated = true;
831
+ break;
832
+ }
833
+ outputBytes += matchBytes;
834
+ allMatches.push(match);
835
+ }
836
+ if (truncated)
837
+ break;
838
+ // max_results 截断:收集完本文件匹配后检查是否已达上限
839
+ if (allMatches.length >= maxResults) {
840
+ truncated = true;
841
+ break;
842
+ }
843
+ }
844
+ else if (outputMode === "count") {
845
+ fileCounts.push({ file: relativePath, count: result.count });
846
+ }
847
+ }
848
+ }
849
+ // ── 构建响应 ──
850
+ const response = {
851
+ ok: true,
852
+ tool: "grep",
853
+ pattern,
854
+ searchPath: toDisplayPath(target.targetPath),
855
+ outputMode,
856
+ filesSearched: files.length,
857
+ filesMatched: matchedFiles.length,
858
+ totalMatches,
859
+ truncated,
860
+ };
861
+ if (outputMode === "content") {
862
+ response.matches = allMatches;
863
+ }
864
+ else if (outputMode === "files_with_matches") {
865
+ response.matches = matchedFiles;
866
+ }
867
+ else {
868
+ response.matches = fileCounts;
869
+ }
870
+ return response;
871
+ },
872
+ };
873
+ }
374
874
  export function createBuiltInFileTools(workingDirectory, agentId) {
375
875
  const resolvedAgentId = agentId || "unknown";
376
876
  return [
377
877
  readFileTool(workingDirectory),
378
878
  writeFileTool(workingDirectory),
379
879
  editFileTool(workingDirectory),
880
+ grepTool(workingDirectory),
380
881
  bashTool(workingDirectory, resolvedAgentId),
381
882
  ];
382
883
  }
@@ -14,8 +14,13 @@
14
14
  */
15
15
  /** 压缩缓冲区:保留这么多 token 的空闲空间,避免压缩过程中溢出 */
16
16
  export declare const COMPACTION_BUFFER = 20000;
17
- /** 基于实际累积 token 的触发比例:当累积量达到上下文窗口的此比例时触发压缩 */
17
+ /**
18
+ * 基础压缩触发比例(兜底默认值,仅用于 contextLimit <= 0 的异常场景)。
19
+ * 正常情况下通过 {@link getCompactionTriggerRatio} 按窗口大小动态分级。
20
+ */
18
21
  export declare const COMPACTION_TRIGGER_RATIO = 0.55;
22
+ /** 按上下文窗口大小返回压缩触发比例(大窗口更高,充分利用空间)。 */
23
+ export declare function getCompactionTriggerRatio(contextLimit: number): number;
19
24
  /** Prune 保护线默认值:保留最近 PRUNE_PROTECT token 的工具输出完整。
20
25
  * 注意:实际使用时会按 contextLimit 比例调整(见 pruneToolOutputs),
21
26
  * 避免在小上下文窗口(如 60k)下保护线过高导致 prune 永不触发。
@@ -49,6 +54,10 @@ export interface CompactionResult {
49
54
  sizeBeforeKB: number;
50
55
  /** 压缩后对话大小(KB) */
51
56
  sizeAfterKB: number;
57
+ /** 压缩前估算 token 数 */
58
+ tokensBefore: number;
59
+ /** 压缩后估算 token 数 */
60
+ tokensAfter: number;
52
61
  /** 压缩前消息数 */
53
62
  messageCountBefore: number;
54
63
  /** 压缩后消息数 */
@@ -85,9 +94,9 @@ export type LLMSummarizer = (input: {
85
94
  contextLimit: number;
86
95
  }) => Promise<string>;
87
96
  /**
88
- * 计算压缩触发阈值:取 min(contextLimit × 55%, hardLimit - reserved)。
97
+ * 计算压缩触发阈值:取 min(contextLimit × 动态比例, hardLimit - reserved)。
89
98
  *
90
- * - ratioBased = contextLimit × COMPACTION_TRIGGER_RATIO(基于窗口比例的软阈值)
99
+ * - ratioBased = contextLimit × getCompactionTriggerRatio(contextLimit)(按窗口大小动态分级)
91
100
  * - hardLimit = inputLimit ?? contextLimit(provider 显式 inputLimit 优先)
92
101
  * - reserved = min(COMPACTION_BUFFER, maxOutput)(buffer 不超过输出上限)
93
102
  *
@@ -109,13 +118,19 @@ export declare function lookupModelLimits(modelName: string, configOverrides?: {
109
118
  maxOutput: number;
110
119
  };
111
120
  /**
112
- * 粗略估算文本的 token 数。
113
- * 不使用真实 tokenizer(太慢),基于字符数乘经验系数。
114
- * 对纯 ASCII 约 4 字符/token,对中文约 1.5-2 字符/token,混合取 3 字符/token。
121
+ * 中英文分离的文本 token 估算。
122
+ * 对纯 ASCII 约 4 字符/token,对中文约 1.5 字符/token。
123
+ * 参考:context-manager.ts 的同名方法。
124
+ */
125
+ export declare function estimateTextTokens(text: string): number;
126
+ /**
127
+ * 粗略估算文本的 token 数(保留向后兼容)。
128
+ * 使用 estimateTextTokens 的中英文分离 + 安全填充。
115
129
  */
116
130
  export declare function estimateTokens(text: string): number;
117
131
  /**
118
132
  * 估算整个对话的 token 数。
133
+ * 使用块级识别 + 中英文分离 + 安全填充。
119
134
  */
120
135
  export declare function estimateConversationTokens(messages: readonly ChatMessageLike[]): number;
121
136
  /**
@@ -137,7 +152,7 @@ export declare function isOverflow(messages: readonly ChatMessageLike[], context
137
152
  * provider 每次请求都会返回实际 token 计数(input + output),
138
153
  * 这个计数比基于文本的估算(estimateConversationTokens)要准确得多。
139
154
  *
140
- * 触发条件:累积 tokens >= contextLimit * COMPACTION_TRIGGER_RATIO
155
+ * 触发条件:累积 tokens >= contextLimit * getCompactionTriggerRatio(contextLimit)
141
156
  * 使用显式传入的 contextLimit,不依赖模型名查找表。
142
157
  *
143
158
  * @param accumulatedInput provider 实际累积的 input tokens
@@ -185,6 +200,19 @@ export declare function summarizeConversation(messages: ChatMessageLike[], optio
185
200
  llmSummarizer?: LLMSummarizer;
186
201
  contextLimit?: number;
187
202
  }): Promise<number>;
203
+ /**
204
+ * Snip:删除最旧的一组消息(从第一个非 system 消息到下一个 user 消息之前)。
205
+ *
206
+ * 作为压缩的最终手段——当 prune 和 summarize 都无法释放足够空间时使用。
207
+ * 能确保:
208
+ * 1. 不删除 system 消息
209
+ * 2. 删除的组不跨 user 边界(保证一个完整轮次)
210
+ * 3. 删除后至少保留 1 组非 system 消息
211
+ *
212
+ * @param messages 对话消息数组(会被原地修改,通过 splice 删除)
213
+ * @returns 删除的消息数
214
+ */
215
+ export declare function snipOldestMessageGroup(messages: ChatMessageLike[]): number;
188
216
  /**
189
217
  * 执行完整压缩流程:Prune → 若仍溢出则 Summarize。
190
218
  *
@@ -201,6 +229,14 @@ export declare function summarizeConversation(messages: ChatMessageLike[], optio
201
229
  export declare function performCompaction(messages: ChatMessageLike[], contextLimit: number, maxOutput?: number, options?: {
202
230
  llmSummarizer?: LLMSummarizer;
203
231
  onPhase?: (event: CompactionPhaseEvent) => void;
232
+ /**
233
+ * Provider 实际累积 token 用量(来自 AI 请求返回的 usage)。
234
+ * 文本估算(estimateConversationTokens)可能低估实际 token 数,
235
+ * 导致 prune 后 isOverflow 返回 false 而跳过 summarize,最终策略为 "none"。
236
+ * 传入此值后,post-prune overflow 检测使用 textEstimated 与 actualUsed 的较大值,
237
+ * 避免因估算偏差导致压缩失效。
238
+ */
239
+ actualUsedTokens?: number;
204
240
  }): Promise<CompactionResult>;
205
241
  export {};
206
242
  //# sourceMappingURL=compaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../src/compaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../src/compaction.ts"],"names":[],"mappings":"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"}