@j0hanz/filesystem-mcp 2.8.1 → 2.9.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.
Files changed (116) hide show
  1. package/README.md +33 -27
  2. package/dist/cli-help.d.ts.map +1 -1
  3. package/dist/cli-help.js +10 -1
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +10 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/concurrency.d.ts +4 -4
  9. package/dist/core/concurrency.d.ts.map +1 -1
  10. package/dist/core/concurrency.js +1 -1
  11. package/dist/core/concurrency.js.map +1 -1
  12. package/dist/core/config.d.ts +2 -0
  13. package/dist/core/config.d.ts.map +1 -1
  14. package/dist/core/config.js.map +1 -1
  15. package/dist/core/errors.d.ts.map +1 -1
  16. package/dist/core/errors.js +7 -1
  17. package/dist/core/errors.js.map +1 -1
  18. package/dist/core/file-uri.d.ts +12 -3
  19. package/dist/core/file-uri.d.ts.map +1 -1
  20. package/dist/core/file-uri.js +35 -7
  21. package/dist/core/file-uri.js.map +1 -1
  22. package/dist/core/fmt.d.ts +2 -0
  23. package/dist/core/fmt.d.ts.map +1 -1
  24. package/dist/core/fmt.js +16 -0
  25. package/dist/core/fmt.js.map +1 -1
  26. package/dist/core/fs.d.ts +16 -1
  27. package/dist/core/fs.d.ts.map +1 -1
  28. package/dist/core/fs.js +127 -32
  29. package/dist/core/fs.js.map +1 -1
  30. package/dist/core/glob.d.ts +15 -0
  31. package/dist/core/glob.d.ts.map +1 -1
  32. package/dist/core/glob.js +119 -14
  33. package/dist/core/glob.js.map +1 -1
  34. package/dist/core/path-completer.d.ts.map +1 -1
  35. package/dist/core/path-completer.js +5 -3
  36. package/dist/core/path-completer.js.map +1 -1
  37. package/dist/core/path-utils.d.ts +42 -6
  38. package/dist/core/path-utils.d.ts.map +1 -1
  39. package/dist/core/path-utils.js +56 -10
  40. package/dist/core/path-utils.js.map +1 -1
  41. package/dist/core/path.d.ts +111 -7
  42. package/dist/core/path.d.ts.map +1 -1
  43. package/dist/core/path.js +453 -65
  44. package/dist/core/path.js.map +1 -1
  45. package/dist/core/read.d.ts +6 -0
  46. package/dist/core/read.d.ts.map +1 -1
  47. package/dist/core/read.js +26 -3
  48. package/dist/core/read.js.map +1 -1
  49. package/dist/core/schema.d.ts +9 -6
  50. package/dist/core/schema.d.ts.map +1 -1
  51. package/dist/core/schema.js +22 -19
  52. package/dist/core/schema.js.map +1 -1
  53. package/dist/core/search.d.ts +6 -0
  54. package/dist/core/search.d.ts.map +1 -1
  55. package/dist/core/search.js +161 -33
  56. package/dist/core/search.js.map +1 -1
  57. package/dist/core/sensitive.d.ts.map +1 -1
  58. package/dist/core/sensitive.js +64 -15
  59. package/dist/core/sensitive.js.map +1 -1
  60. package/dist/core/store.d.ts +1 -0
  61. package/dist/core/store.d.ts.map +1 -1
  62. package/dist/core/store.js +3 -0
  63. package/dist/core/store.js.map +1 -1
  64. package/dist/core/util.d.ts +12 -1
  65. package/dist/core/util.d.ts.map +1 -1
  66. package/dist/core/util.js +16 -1
  67. package/dist/core/util.js.map +1 -1
  68. package/dist/resources.d.ts.map +1 -1
  69. package/dist/resources.js +20 -11
  70. package/dist/resources.js.map +1 -1
  71. package/dist/server.js +1 -1
  72. package/dist/server.js.map +1 -1
  73. package/dist/tools/create.d.ts.map +1 -1
  74. package/dist/tools/create.js +121 -43
  75. package/dist/tools/create.js.map +1 -1
  76. package/dist/tools/define.d.ts +8 -4
  77. package/dist/tools/define.d.ts.map +1 -1
  78. package/dist/tools/define.js +36 -9
  79. package/dist/tools/define.js.map +1 -1
  80. package/dist/tools/delete.d.ts.map +1 -1
  81. package/dist/tools/delete.js +50 -11
  82. package/dist/tools/delete.js.map +1 -1
  83. package/dist/tools/diff.js +1 -1
  84. package/dist/tools/diff.js.map +1 -1
  85. package/dist/tools/edit.d.ts.map +1 -1
  86. package/dist/tools/edit.js +14 -12
  87. package/dist/tools/edit.js.map +1 -1
  88. package/dist/tools/find-files.d.ts.map +1 -1
  89. package/dist/tools/find-files.js +15 -9
  90. package/dist/tools/find-files.js.map +1 -1
  91. package/dist/tools/list.d.ts.map +1 -1
  92. package/dist/tools/list.js +141 -86
  93. package/dist/tools/list.js.map +1 -1
  94. package/dist/tools/move.d.ts.map +1 -1
  95. package/dist/tools/move.js +72 -26
  96. package/dist/tools/move.js.map +1 -1
  97. package/dist/tools/patch.js +13 -6
  98. package/dist/tools/patch.js.map +1 -1
  99. package/dist/tools/read.d.ts.map +1 -1
  100. package/dist/tools/read.js +113 -48
  101. package/dist/tools/read.js.map +1 -1
  102. package/dist/tools/replace-text.d.ts.map +1 -1
  103. package/dist/tools/replace-text.js +50 -35
  104. package/dist/tools/replace-text.js.map +1 -1
  105. package/dist/tools/search-text.d.ts.map +1 -1
  106. package/dist/tools/search-text.js +15 -33
  107. package/dist/tools/search-text.js.map +1 -1
  108. package/dist/tools/stat.d.ts.map +1 -1
  109. package/dist/tools/stat.js +26 -8
  110. package/dist/tools/stat.js.map +1 -1
  111. package/dist/transport/http.d.ts.map +1 -1
  112. package/dist/transport/http.js +1 -0
  113. package/dist/transport/http.js.map +1 -1
  114. package/dist/transport/stdio.js +1 -1
  115. package/dist/transport/stdio.js.map +1 -1
  116. package/package.json +5 -5
@@ -4,9 +4,10 @@ import * as z from 'zod/v4';
4
4
  import { processInParallel } from "../core/concurrency.js";
5
5
  import { ErrorCode, FsError } from "../core/errors.js";
6
6
  import { buildFileResourceLinkFor, buildFileResourceUri } from "../core/file-uri.js";
7
- import { detectMimeFromContent, detectMimeType } from "../core/mime.js";
8
- import { defaultFalseBoolean, singleOrBatchAccessPaths, singleOrBatchPathsInput, validateReadRange, } from "../core/schema.js";
9
- import { DEFAULT_CONTINUATION_CHUNK_SIZE, DEFAULT_SEARCH_TIMEOUT_MS, getMaxTextFileSize, PARALLEL_CONCURRENCY, READ_MANY_MAX_TOTAL_BYTES, } from "../core/util.js";
7
+ import { detectMimeFromContent, detectMimeType, isKnownBinaryExtension, } from "../core/mime.js";
8
+ import { BINARY_FILE_MESSAGE, isBinaryRefusal, } from "../core/read.js";
9
+ import { defaultFalseBoolean, mapSingleOrBatchPaths, singleOrBatchPathsInput, validateReadRange, } from "../core/schema.js";
10
+ import { base64EncodedBytes, DEFAULT_CONTINUATION_CHUNK_SIZE, getMaxTextFileSize, PARALLEL_CONCURRENCY, READ_MANY_MAX_TOTAL_BYTES, } from "../core/util.js";
10
11
  import { isTotalFailure, runOverPaths } from "./batch.js";
11
12
  import { defineTool } from "./define.js";
12
13
  /**
@@ -14,6 +15,8 @@ import { defineTool } from "./define.js";
14
15
  * never asks for more. Not restated as `.max()`: that reports it twice.
15
16
  */
16
17
  const MAX_LINE_NUMBER = 2_147_483_647;
18
+ /** One spelling of the resource-content digest every read result that carries a hash uses. */
19
+ const sha256Hex = (data) => createHash('sha256').update(data).digest('hex');
17
20
  const rangeField = (description, count = false) => {
18
21
  const field = z.int32().min(1, { message: 'Min: 1' });
19
22
  return (count ? field.max(100000, { message: 'Max: 100,000' }) : field)
@@ -24,35 +27,34 @@ const readRangeFields = {
24
27
  head: rangeField('Return first N lines', true),
25
28
  tail: rangeField('Return last N lines', true),
26
29
  startLine: rangeField('Start line (1-indexed)'),
27
- endLine: rangeField('End line (1-indexed)'),
30
+ endLine: rangeField('End line (1-indexed); requires startLine'),
28
31
  };
32
+ /** A slice read: only a full read returns media or a binary resource. */
33
+ function hasLineRange(args) {
34
+ return (args.head !== undefined ||
35
+ args.tail !== undefined ||
36
+ args.startLine !== undefined ||
37
+ args.endLine !== undefined);
38
+ }
29
39
  const ReadFileInputSchema = singleOrBatchPathsInput({
30
40
  includeHash: defaultFalseBoolean('Include SHA-256 hash of the returned content in the response'),
41
+ binary: defaultFalseBoolean('Return a binary file that is not an image or audio whole, as a base64 embedded resource. Full reads only.'),
31
42
  ...readRangeFields,
32
- })
33
- .superRefine((value, ctx) => {
43
+ }).superRefine((value, ctx) => {
34
44
  validateReadRange({
35
45
  head: value.head,
36
46
  tail: value.tail,
37
47
  startLine: value.startLine,
38
48
  endLine: value.endLine,
39
49
  }, ctx);
40
- })
41
- // Mirror `validateReadRange` on the wire. Without this the four line params
42
- // published as four independent optional integers, so `{ path, head, tail }`
43
- // passed the advertised schema and was rejected only at call time.
44
- //
45
- // `oneOf` is restated because `.meta()` replaces the entry
46
- // `singleOrBatchPathsInput` set rather than merging into it — dropping it here
47
- // would silently un-publish the path/paths rule.
48
- .meta({
49
- // The line-param exclusivity that used to sit here as a five-branch
50
- // `not/anyOf` is one sentence in the description instead: validateReadRange
51
- // rejects every conflicting combination by name at runtime, so the wire copy
52
- // was paying for a second statement of a rule the model reads better in
53
- // prose.
54
- oneOf: [{ required: ['path'] }, { required: ['paths'] }],
55
- dependentRequired: { endLine: ['startLine'] },
50
+ if (value.binary && hasLineRange(value)) {
51
+ ctx.addIssue({
52
+ code: 'custom',
53
+ path: ['binary'],
54
+ message: "Cannot use 'binary' with 'head'/'tail'/'startLine'/'endLine'. A binary file is read whole.",
55
+ input: value,
56
+ });
57
+ }
56
58
  });
57
59
  const READ_TOOL_LABEL = 'Read';
58
60
  function buildReadSpec(args, signal) {
@@ -99,12 +101,23 @@ function buildReadContinuation(result, requestedPath) {
99
101
  hint: `More lines remain from ${String(nextStart)}. Read next chunk with these args.`,
100
102
  };
101
103
  }
102
- async function collectFileBudget(filePaths, maxTotalSize, maxSize, ctx) {
104
+ /**
105
+ * What a file costs the batch: one whose bytes ship as base64 costs that size.
106
+ * Only a full read ships base64; a slice of an svg is text.
107
+ */
108
+ function budgetBytes(path, size, { fullRead, binary }) {
109
+ if (!fullRead)
110
+ return size;
111
+ const { kind } = detectMimeType(path);
112
+ const base64 = kind === 'image' || kind === 'audio' || (binary && isKnownBinaryExtension(path));
113
+ return base64 ? base64EncodedBytes(size) : size;
114
+ }
115
+ async function collectFileBudget(filePaths, maxTotalSize, maxSize, ctx, mode) {
103
116
  const indexed = filePaths.map((path, index) => ({ path, index }));
104
117
  const { results } = await processInParallel(indexed, async ({ path, index }) => {
105
118
  try {
106
119
  const out = await ctx.fs.stat(path);
107
- return { index, size: Math.min(out.stats.size, maxSize) };
120
+ return { index, size: budgetBytes(path, Math.min(out.stats.size, maxSize), mode) };
108
121
  }
109
122
  catch (err) {
110
123
  ctx.log('debug', `collectFileBudget: stat failed for "${path}": ${String(err)}`, 'read');
@@ -139,11 +152,11 @@ function buildPerPathReadValue(result, options) {
139
152
  const continuation = result.hasMoreLines && result.readMode !== 'tail'
140
153
  ? buildReadContinuation(result, options.requestedPath)
141
154
  : undefined;
142
- const contentHash = options.includeHash
143
- ? createHash('sha256').update(result.content, 'utf-8').digest('hex')
144
- : undefined;
155
+ const contentHash = options.includeHash ? sha256Hex(result.content) : undefined;
156
+ const canLink = result.fileSize === undefined || result.fileSize <= getMaxTextFileSize();
145
157
  return {
146
158
  content: result.content,
159
+ ...(result.fileSize !== undefined ? { fileSize: result.fileSize } : {}),
147
160
  mimeType: mimeInfo.mimeType,
148
161
  kind: mimeInfo.kind,
149
162
  ...(continuation ? { continuation } : {}),
@@ -155,7 +168,7 @@ function buildPerPathReadValue(result, options) {
155
168
  ...(result.startLine !== undefined ? { startLine: result.startLine } : {}),
156
169
  ...(result.endLine !== undefined ? { endLine: result.endLine } : {}),
157
170
  ...(contentHash !== undefined ? { contentHash } : {}),
158
- resourceUri: buildFileResourceUri(result.path),
171
+ ...(canLink ? { resourceUri: buildFileResourceUri(result.path) } : {}),
159
172
  modified: result.modified,
160
173
  };
161
174
  }
@@ -180,17 +193,37 @@ function readTrailer(v) {
180
193
  lines.push(`// sha256: ${v.contentHash}`);
181
194
  return lines;
182
195
  }
196
+ /**
197
+ * `binary: true` after the text path refused the file as binary. readRaw
198
+ * re-validates the path (roots, denylist) and enforces the same size cap.
199
+ * A file refused by its extension can still probe as text: it ships as the
200
+ * extension says, octet-stream.
201
+ */
202
+ async function readBinaryResource(filePath, args, ctx) {
203
+ const raw = await ctx.fs.readRaw(filePath, { signal: ctx.signal });
204
+ const asText = raw.kind === 'text';
205
+ const kind = asText ? 'binary' : raw.kind;
206
+ const mimeType = asText ? 'application/octet-stream' : raw.mimeType;
207
+ const size = raw.content.length;
208
+ return {
209
+ content: `[binary ${kind} content: ${String(size)} bytes (${mimeType}); returned as an embedded resource block]`,
210
+ mimeType,
211
+ kind,
212
+ size,
213
+ resourceUri: buildFileResourceUri(raw.validPath),
214
+ modified: raw.modified,
215
+ blobData: raw.content.toString('base64'),
216
+ ...(args.includeHash ? { contentHash: sha256Hex(raw.content) } : {}),
217
+ };
218
+ }
183
219
  async function readOnePath(filePath, args, ctx) {
184
220
  // Image/audio full read: return a media content block instead of throwing
185
221
  // INVALID_INPUT ("Binary file detected."). Line-range reads are
186
222
  // text-oriented and stay rejected. `readRaw` enforces the same size cap as
187
223
  // the text path (getMaxTextFileSize), so a too-large image surfaces TOO_LARGE
188
- // rather than blowing memory. svg carries kind:'image' but is XML text —
189
- // readRaw.isBinary is false for it, so it falls through to the text path.
190
- const isRangeRead = args.head !== undefined ||
191
- args.tail !== undefined ||
192
- args.startLine !== undefined ||
193
- args.endLine !== undefined;
224
+ // rather than blowing memory. svg is kind 'image' in EXT_MAP, so readRaw
225
+ // reports it binary and it returns as an image block.
226
+ const isRangeRead = hasLineRange(args);
194
227
  if (!isRangeRead) {
195
228
  const mime = detectMimeType(filePath);
196
229
  if (mime.kind === 'image' || mime.kind === 'audio') {
@@ -200,7 +233,11 @@ async function readOnePath(filePath, args, ctx) {
200
233
  content: `[binary ${mime.kind} content: ${String(raw.content.length)} bytes; returned as a ${mime.kind} content block]`,
201
234
  mimeType: raw.mimeType,
202
235
  kind: mime.kind,
236
+ size: raw.content.length,
237
+ resourceUri: buildFileResourceUri(raw.validPath),
238
+ modified: raw.modified,
203
239
  mediaData: raw.content.toString('base64'),
240
+ ...(args.includeHash ? { contentHash: sha256Hex(raw.content) } : {}),
204
241
  };
205
242
  }
206
243
  }
@@ -208,12 +245,26 @@ async function readOnePath(filePath, args, ctx) {
208
245
  const spec = buildReadSpec(args, ctx.signal);
209
246
  // The read re-validates and re-stats: the budget pass's stat is only a
210
247
  // size estimate, never a substitute for the guarded open.
211
- const result = await ctx.fs.readFile(filePath, spec);
248
+ let result;
249
+ try {
250
+ result = await ctx.fs.readFile(filePath, spec);
251
+ }
252
+ catch (error) {
253
+ if (!isBinaryRefusal(error))
254
+ throw error;
255
+ // The schema refuses binary with a range, so this is always a full read.
256
+ if (args.binary)
257
+ return await readBinaryResource(filePath, args, ctx);
258
+ throw new FsError(ErrorCode.INVALID_INPUT, isRangeRead
259
+ ? `${BINARY_FILE_MESSAGE} It has no lines; read it whole with binary: true to get it as a base64 embedded resource.`
260
+ : `${BINARY_FILE_MESSAGE} Pass binary: true to get it as a base64 embedded resource.`, filePath, error);
261
+ }
212
262
  return buildPerPathReadValue(result, {
213
263
  includeHash: args.includeHash,
214
264
  // The continuation is args the caller pastes back, so it echoes the path
215
- // they wrote. `result.path` is the resolved absolute one — on Windows that
216
- // is a backslash-doubling JSON string that also spells out the server root.
265
+ // they wrote, or the root-resolved one a relative path was rewritten to.
266
+ // `result.path` is the real path — on Windows that is a backslash-doubling
267
+ // JSON string that also spells out the server root.
217
268
  requestedPath: filePath,
218
269
  });
219
270
  }
@@ -221,10 +272,10 @@ export const READ = defineTool({
221
272
  name: 'read',
222
273
  title: 'Read File',
223
274
  description: 'Read text files, like cat: whole, or one slice via head, tail, or startLine/endLine. ' +
224
- 'Images and audio return as media; other binary files are rejected.',
275
+ 'Images and audio return as media; pass binary: true to get any other binary file whole as a base64 embedded resource.',
225
276
  input: ReadFileInputSchema,
226
277
  readOnlyHint: true,
227
- timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
278
+ deadline: true,
228
279
  defaultErrorCode: ErrorCode.NOT_FILE,
229
280
  progress: (args) => {
230
281
  const isBatch = args.paths !== undefined;
@@ -245,10 +296,10 @@ export const READ = defineTool({
245
296
  }
246
297
  return { label: READ_TOOL_LABEL, subject: name, ...(scope ? { scope } : {}) };
247
298
  },
248
- accessPaths: singleOrBatchAccessPaths,
299
+ mapPaths: mapSingleOrBatchPaths,
249
300
  run: async (args, ctx) => {
250
301
  const items = args.paths !== undefined
251
- ? await collectFileBudget(args.paths, READ_MANY_MAX_TOTAL_BYTES, getMaxTextFileSize(), ctx)
302
+ ? await collectFileBudget(args.paths, READ_MANY_MAX_TOTAL_BYTES, getMaxTextFileSize(), ctx, { fullRead: !hasLineRange(args), binary: args.binary })
252
303
  : [{ path: args.path ?? '' }];
253
304
  const { results: ordered, summary } = await runOverPaths(items, ctx, ErrorCode.NOT_FILE, ({ path, skip }) => {
254
305
  if (skip)
@@ -260,6 +311,13 @@ export const READ = defineTool({
260
311
  if ('error' in result)
261
312
  continue;
262
313
  const v = result.value;
314
+ if (v.blobData !== undefined && v.resourceUri !== undefined && v.mimeType !== undefined) {
315
+ resources.push({
316
+ type: 'resource',
317
+ resource: { uri: v.resourceUri, mimeType: v.mimeType, blob: v.blobData },
318
+ });
319
+ continue;
320
+ }
263
321
  // Image/audio full read: emit the media content block alongside the
264
322
  // structured value. The base64 lives in v.mediaData (set in readOnePath).
265
323
  if (v.mediaData && v.mimeType && (v.kind === 'image' || v.kind === 'audio')) {
@@ -268,13 +326,13 @@ export const READ = defineTool({
268
326
  : { type: 'audio', data: v.mediaData, mimeType: v.mimeType });
269
327
  continue;
270
328
  }
271
- if (!v.resourceUri || !v.content)
329
+ if (!v.resourceUri || v.content === undefined)
272
330
  continue;
273
331
  // `result.path` is the path as *requested*; `v.resourceUri` was built from
274
332
  // the *validated* one. Rebuilding from the request would emit a second URI
275
333
  // for the same file whenever the two differ in case — subscribe by one and
276
334
  // unsubscribe by the other and the watcher never goes away.
277
- resources.push(buildFileResourceLinkFor(v.resourceUri, basename(result.path), v.mimeType ?? 'application/octet-stream', Buffer.byteLength(v.content, 'utf8'), v.modified));
335
+ resources.push(buildFileResourceLinkFor(v.resourceUri, basename(result.path), v.mimeType ?? 'application/octet-stream', v.fileSize ?? Buffer.byteLength(v.content, 'utf8'), v.modified));
278
336
  }
279
337
  const [firstOrdered] = ordered;
280
338
  const body = (v) => {
@@ -307,7 +365,7 @@ export const READ = defineTool({
307
365
  const structuredResults = ordered.map((result) => {
308
366
  if ('error' in result)
309
367
  return result;
310
- const { content: _content, mediaData: _mediaData, ...value } = result.value;
368
+ const { content: _content, fileSize: _fileSize, mediaData: _mediaData, blobData: _blobData, ...value } = result.value;
311
369
  return { ...result, value };
312
370
  });
313
371
  return {
@@ -317,9 +375,16 @@ export const READ = defineTool({
317
375
  ...(resources.length > 0 ? { resources } : {}),
318
376
  };
319
377
  },
320
- // Media cannot be sliced, so head/tail is no remedy for it.
321
- oversizeRemedy: (result) => result.resources?.some((b) => b.type === 'image' || b.type === 'audio')
322
- ? 'This media file is too large to return over the stdio transport; connect over HTTP, or raise it as a smaller file.'
323
- : 'Read a slice with head, tail, or startLine/endLine.',
378
+ // Media and binary resources cannot be sliced, so head/tail is no remedy.
379
+ oversizeRemedy: (result) => {
380
+ const types = new Set(result.resources?.map((b) => b.type));
381
+ if (types.has('image') || types.has('audio')) {
382
+ return 'This media file is too large to return over the stdio transport; connect over HTTP, or raise it as a smaller file.';
383
+ }
384
+ if (types.has('resource')) {
385
+ return 'This binary file is too large to return over the stdio transport; connect over HTTP.';
386
+ }
387
+ return 'Read a slice with head, tail, or startLine/endLine.';
388
+ },
324
389
  });
325
390
  //# sourceMappingURL=read.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { createHash } from 'node:crypto';\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { processInParallel } from '../core/concurrency.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { buildFileResourceLinkFor, buildFileResourceUri } from '../core/file-uri.ts';\nimport { detectMimeFromContent, detectMimeType, type FileKind } from '../core/mime.ts';\nimport type { ReadFileResult, ReadSpec } from '../core/read.ts';\nimport {\n defaultFalseBoolean,\n singleOrBatchAccessPaths,\n singleOrBatchPathsInput,\n validateReadRange,\n} from '../core/schema.ts';\nimport {\n DEFAULT_CONTINUATION_CHUNK_SIZE,\n DEFAULT_SEARCH_TIMEOUT_MS,\n getMaxTextFileSize,\n PARALLEL_CONCURRENCY,\n READ_MANY_MAX_TOTAL_BYTES,\n} from '../core/util.ts';\nimport type { BatchResult } from './batch.ts';\nimport { isTotalFailure, runOverPaths } from './batch.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\n/**\n * `z.int32()`'s own ceiling on startLine/endLine, named so a continuation\n * never asks for more. Not restated as `.max()`: that reports it twice.\n */\nconst MAX_LINE_NUMBER = 2_147_483_647;\n\nconst rangeField = (description: string, count = false) => {\n const field = z.int32().min(1, { message: 'Min: 1' });\n return (count ? field.max(100000, { message: 'Max: 100,000' }) : field)\n .optional()\n .describe(description);\n};\n\nconst readRangeFields = {\n head: rangeField('Return first N lines', true),\n tail: rangeField('Return last N lines', true),\n startLine: rangeField('Start line (1-indexed)'),\n endLine: rangeField('End line (1-indexed)'),\n};\n\nconst ReadFileInputSchema = singleOrBatchPathsInput({\n includeHash: defaultFalseBoolean('Include SHA-256 hash of the returned content in the response'),\n ...readRangeFields,\n})\n .superRefine((value, ctx) => {\n validateReadRange(\n {\n head: value.head,\n tail: value.tail,\n startLine: value.startLine,\n endLine: value.endLine,\n },\n ctx,\n );\n })\n // Mirror `validateReadRange` on the wire. Without this the four line params\n // published as four independent optional integers, so `{ path, head, tail }`\n // passed the advertised schema and was rejected only at call time.\n //\n // `oneOf` is restated because `.meta()` replaces the entry\n // `singleOrBatchPathsInput` set rather than merging into it — dropping it here\n // would silently un-publish the path/paths rule.\n .meta({\n // The line-param exclusivity that used to sit here as a five-branch\n // `not/anyOf` is one sentence in the description instead: validateReadRange\n // rejects every conflicting combination by name at runtime, so the wire copy\n // was paying for a second statement of a rule the model reads better in\n // prose.\n oneOf: [{ required: ['path'] }, { required: ['paths'] }],\n dependentRequired: { endLine: ['startLine'] },\n });\n\ninterface ReadContinuation {\n tool: 'read';\n args: { path: string; startLine: number; endLine: number };\n hint: string;\n}\n\n// File bytes ride content blocks, never the structured metadata.\ninterface ReadPerPathValue {\n mimeType?: string;\n kind?: FileKind;\n resourceUri?: string;\n /** ISO-8601 mtime at read time; also rides the resource_link. */\n modified?: string;\n continuation?: ReadContinuation;\n totalLines?: number;\n linesRead?: number;\n hasMoreLines?: boolean;\n head?: number;\n tail?: number;\n startLine?: number;\n endLine?: number;\n contentHash?: string;\n}\n\ntype ReadFileInput = z.infer<typeof ReadFileInputSchema>;\n\nconst READ_TOOL_LABEL = 'Read';\n\nfunction buildReadSpec(args: ReadFileInput, signal?: AbortSignal): ReadSpec {\n const signalPart = signal ? { signal } : {};\n const { head, tail, startLine, endLine } = args;\n\n if (head !== undefined) return { kind: 'head', lines: head, ...signalPart };\n if (tail !== undefined) return { kind: 'tail', lines: tail, ...signalPart };\n if (startLine !== undefined || endLine !== undefined) {\n return {\n kind: 'range',\n start: startLine ?? 1,\n ...(endLine !== undefined ? { end: endLine } : {}),\n ...signalPart,\n };\n }\n return { kind: 'full', ...signalPart };\n}\n\n// No `totalLines`: only `readFull` counts them and a full read never leaves\n// more behind, so a continuation cannot know the total without a second pass.\nfunction buildReadContinuation(\n result: ReadFileResult,\n requestedPath: string,\n): ReadContinuation | undefined {\n if (!result.hasMoreLines) return undefined;\n const linesRead = result.linesRead ?? 0;\n const nextStart = (result.startLine ?? 1) + linesRead;\n // Args the schema would reject are no continuation; clamp the end into it.\n if (nextStart > MAX_LINE_NUMBER) return undefined;\n let chunkSize: number;\n if (result.head !== undefined) {\n chunkSize = result.head;\n } else if (result.startLine !== undefined && result.endLine !== undefined) {\n chunkSize = result.endLine - result.startLine + 1;\n } else {\n chunkSize = DEFAULT_CONTINUATION_CHUNK_SIZE;\n }\n const nextEnd = Math.min(nextStart + chunkSize - 1, MAX_LINE_NUMBER);\n return {\n tool: 'read',\n args: { path: requestedPath, startLine: nextStart, endLine: nextEnd },\n hint: `More lines remain from ${String(nextStart)}. Read next chunk with these args.`,\n };\n}\n\n/**\n * The published metadata plus the bytes this call read. `content` and\n * `mediaData` exist only between `readOnePath` and the content blocks `run`\n * builds from them — they are stripped before the structured half is returned,\n * which is why they are not in `ReadPerPathValue`.\n */\ntype PerPathReadValue = ReadPerPathValue & {\n content?: string;\n mediaData?: string;\n};\n\ninterface BatchFileInfo {\n index: number;\n size: number;\n}\n\ninterface BudgetItem {\n path: string;\n skip?: FsError;\n}\n\nasync function collectFileBudget(\n filePaths: readonly string[],\n maxTotalSize: number,\n maxSize: number,\n ctx: Pick<ToolCtx, 'fs' | 'signal' | 'log'>,\n): Promise<BudgetItem[]> {\n const indexed = filePaths.map((path, index) => ({ path, index }));\n const { results } = await processInParallel(\n indexed,\n async ({ path, index }): Promise<BatchFileInfo | undefined> => {\n try {\n const out = await ctx.fs.stat(path);\n return { index, size: Math.min(out.stats.size, maxSize) };\n } catch (err: unknown) {\n ctx.log('debug', `collectFileBudget: stat failed for \"${path}\": ${String(err)}`, 'read');\n return undefined;\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n const byIndex = new Map<number, BatchFileInfo>();\n for (const { value: item } of results) {\n if (item) byIndex.set(item.index, item);\n }\n\n let total = 0;\n return filePaths.map((path, i): BudgetItem => {\n const info = byIndex.get(i);\n // A failed stat is not skipped, so its read surfaces the\n // real error, not a misleading TOO_LARGE.\n if (info === undefined) return { path };\n // Skip this file only; a later, smaller file that still fits is read.\n if (total + info.size > maxTotalSize) {\n return {\n path,\n skip: new FsError(\n ErrorCode.TOO_LARGE,\n `Skipped: this file alone would push the batch past maxTotalSize (${String(maxTotalSize)} bytes). Read it on its own with path instead of paths.`,\n path,\n ),\n };\n }\n total += info.size;\n return { path };\n });\n}\n\nfunction buildPerPathReadValue(\n result: ReadFileResult,\n options: { includeHash?: boolean; requestedPath: string },\n): PerPathReadValue {\n const mimeInfo = detectMimeFromContent(result.path, result.content);\n const continuation =\n result.hasMoreLines && result.readMode !== 'tail'\n ? buildReadContinuation(result, options.requestedPath)\n : undefined;\n const contentHash = options.includeHash\n ? createHash('sha256').update(result.content, 'utf-8').digest('hex')\n : undefined;\n\n return {\n content: result.content,\n mimeType: mimeInfo.mimeType,\n kind: mimeInfo.kind,\n ...(continuation ? { continuation } : {}),\n ...(result.totalLines !== undefined ? { totalLines: result.totalLines } : {}),\n ...(result.linesRead !== undefined ? { linesRead: result.linesRead } : {}),\n ...(result.hasMoreLines ? { hasMoreLines: true } : {}),\n ...(result.head !== undefined ? { head: result.head } : {}),\n ...(result.tail !== undefined ? { tail: result.tail } : {}),\n ...(result.startLine !== undefined ? { startLine: result.startLine } : {}),\n ...(result.endLine !== undefined ? { endLine: result.endLine } : {}),\n ...(contentHash !== undefined ? { contentHash } : {}),\n resourceUri: buildFileResourceUri(result.path),\n modified: result.modified,\n };\n}\n\n/**\n * The two facts the model cannot act on without: that lines were dropped, and\n * the exact args to get the next chunk. Both used to live only in the structured\n * half, which no longer reaches the model. Each line is `//` prefixed and set\n * off by a blank line so it cannot be read as file bytes — do not drop either\n * guard.\n */\nfunction readTrailer(v: PerPathReadValue): string[] {\n const lines: string[] = [];\n if (v.continuation) {\n lines.push(\n `// truncated: ${v.continuation.hint} Continue: read ${JSON.stringify(v.continuation.args)}`,\n );\n } else if (v.hasMoreLines && v.linesRead !== undefined) {\n // A tail read gets no continuation — there are no args that read *backwards*\n // — so say what was shown rather than leaving the truncation silent.\n lines.push(`// truncated: showing last ${String(v.linesRead)} lines`);\n }\n if (v.contentHash !== undefined) lines.push(`// sha256: ${v.contentHash}`);\n return lines;\n}\n\nasync function readOnePath(\n filePath: string,\n args: ReadFileInput,\n ctx: ToolCtx,\n): Promise<PerPathReadValue> {\n // Image/audio full read: return a media content block instead of throwing\n // INVALID_INPUT (\"Binary file detected.\"). Line-range reads are\n // text-oriented and stay rejected. `readRaw` enforces the same size cap as\n // the text path (getMaxTextFileSize), so a too-large image surfaces TOO_LARGE\n // rather than blowing memory. svg carries kind:'image' but is XML text —\n // readRaw.isBinary is false for it, so it falls through to the text path.\n const isRangeRead =\n args.head !== undefined ||\n args.tail !== undefined ||\n args.startLine !== undefined ||\n args.endLine !== undefined;\n if (!isRangeRead) {\n const mime = detectMimeType(filePath);\n if (mime.kind === 'image' || mime.kind === 'audio') {\n const raw = await ctx.fs.readRaw(filePath, { signal: ctx.signal });\n if (raw.isBinary) {\n return {\n content: `[binary ${mime.kind} content: ${String(raw.content.length)} bytes; returned as a ${mime.kind} content block]`,\n mimeType: raw.mimeType,\n kind: mime.kind,\n mediaData: raw.content.toString('base64'),\n };\n }\n }\n }\n\n const spec = buildReadSpec(args, ctx.signal);\n // The read re-validates and re-stats: the budget pass's stat is only a\n // size estimate, never a substitute for the guarded open.\n const result = await ctx.fs.readFile(filePath, spec);\n\n return buildPerPathReadValue(result, {\n includeHash: args.includeHash,\n // The continuation is args the caller pastes back, so it echoes the path\n // they wrote. `result.path` is the resolved absolute one — on Windows that\n // is a backslash-doubling JSON string that also spells out the server root.\n requestedPath: filePath,\n });\n}\n\nexport const READ = defineTool<typeof ReadFileInputSchema, BatchResult<ReadPerPathValue>>({\n name: 'read',\n title: 'Read File',\n description:\n 'Read text files, like cat: whole, or one slice via head, tail, or startLine/endLine. ' +\n 'Images and audio return as media; other binary files are rejected.',\n input: ReadFileInputSchema,\n readOnlyHint: true,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n defaultErrorCode: ErrorCode.NOT_FILE,\n progress: (args) => {\n const isBatch = args.paths !== undefined;\n const name = isBatch ? `${String(args.paths?.length ?? 0)} files` : basename(args.path ?? '');\n if (isBatch) {\n return { label: READ_TOOL_LABEL, subject: name };\n }\n let scope: string | undefined;\n if (args.startLine !== undefined) {\n const end = args.endLine ?? '...';\n scope = `${args.startLine}-${String(end)}`;\n } else if (args.head !== undefined) {\n scope = `head ${args.head}`;\n } else if (args.tail !== undefined) {\n scope = `tail ${args.tail}`;\n }\n return { label: READ_TOOL_LABEL, subject: name, ...(scope ? { scope } : {}) };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n const items: BudgetItem[] =\n args.paths !== undefined\n ? await collectFileBudget(args.paths, READ_MANY_MAX_TOTAL_BYTES, getMaxTextFileSize(), ctx)\n : [{ path: args.path ?? '' }];\n const { results: ordered, summary } = await runOverPaths(\n items,\n ctx,\n ErrorCode.NOT_FILE,\n ({ path, skip }) => {\n if (skip) throw skip;\n return readOnePath(path, args, ctx);\n },\n );\n\n const resources: ContentBlock[] = [];\n for (const result of ordered) {\n if ('error' in result) continue;\n const v = result.value;\n // Image/audio full read: emit the media content block alongside the\n // structured value. The base64 lives in v.mediaData (set in readOnePath).\n if (v.mediaData && v.mimeType && (v.kind === 'image' || v.kind === 'audio')) {\n resources.push(\n v.kind === 'image'\n ? { type: 'image', data: v.mediaData, mimeType: v.mimeType }\n : { type: 'audio', data: v.mediaData, mimeType: v.mimeType },\n );\n continue;\n }\n if (!v.resourceUri || !v.content) continue;\n // `result.path` is the path as *requested*; `v.resourceUri` was built from\n // the *validated* one. Rebuilding from the request would emit a second URI\n // for the same file whenever the two differ in case — subscribe by one and\n // unsubscribe by the other and the watcher never goes away.\n resources.push(\n buildFileResourceLinkFor(\n v.resourceUri,\n basename(result.path),\n v.mimeType ?? 'application/octet-stream',\n Buffer.byteLength(v.content, 'utf8'),\n v.modified,\n ),\n );\n }\n\n const [firstOrdered] = ordered;\n const body = (v: PerPathReadValue): string => {\n const content = v.content ?? 'read failed';\n const trailer = readTrailer(v);\n if (trailer.length === 0) return content;\n // Exactly one blank line between the bytes and the trailer, whether or not\n // the file ended in a newline.\n return `${content}${content.endsWith('\\n') ? '\\n' : '\\n\\n'}${trailer.join('\\n')}`;\n };\n const text =\n ordered.length === 1 && firstOrdered !== undefined\n ? 'error' in firstOrdered\n ? firstOrdered.error.message\n : body(firstOrdered.value)\n : ordered\n .map((r) => {\n const header = `// ${r.path}`;\n if ('value' in r) return `${header}\\n${body(r.value)}`;\n return `${header}\\n// Error: ${r.error.message}`;\n })\n .join('\\n\\n');\n\n // The bytes ship once. `text` above already carries every file's content\n // verbatim (and image/audio bytes ride the media content block), so\n // repeating them under `results[].value` doubled both the wire payload and\n // the model's token cost for every read. The structured half keeps the\n // metadata a client cannot recover from the text: paths, line counts,\n // hashes, continuations, resourceUri.\n const structuredResults = ordered.map((result) => {\n if ('error' in result) return result;\n const { content: _content, mediaData: _mediaData, ...value } = result.value;\n return { ...result, value };\n });\n\n return {\n structured: { results: structuredResults, summary },\n text,\n isError: isTotalFailure(summary),\n ...(resources.length > 0 ? { resources } : {}),\n };\n },\n // Media cannot be sliced, so head/tail is no remedy for it.\n oversizeRemedy: (result) =>\n result.resources?.some((b) => b.type === 'image' || b.type === 'audio')\n ? 'This media file is too large to return over the stdio transport; connect over HTTP, or raise it as a smaller file.'\n : 'Read a slice with head, tail, or startLine/endLine.',\n});\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { createHash } from 'node:crypto';\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { processInParallel } from '../core/concurrency.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { buildFileResourceLinkFor, buildFileResourceUri } from '../core/file-uri.ts';\nimport {\n detectMimeFromContent,\n detectMimeType,\n type FileKind,\n isKnownBinaryExtension,\n} from '../core/mime.ts';\nimport {\n BINARY_FILE_MESSAGE,\n isBinaryRefusal,\n type ReadFileResult,\n type ReadSpec,\n} from '../core/read.ts';\nimport {\n defaultFalseBoolean,\n mapSingleOrBatchPaths,\n singleOrBatchPathsInput,\n validateReadRange,\n} from '../core/schema.ts';\nimport {\n base64EncodedBytes,\n DEFAULT_CONTINUATION_CHUNK_SIZE,\n getMaxTextFileSize,\n PARALLEL_CONCURRENCY,\n READ_MANY_MAX_TOTAL_BYTES,\n} from '../core/util.ts';\nimport type { BatchResult } from './batch.ts';\nimport { isTotalFailure, runOverPaths } from './batch.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\n/**\n * `z.int32()`'s own ceiling on startLine/endLine, named so a continuation\n * never asks for more. Not restated as `.max()`: that reports it twice.\n */\nconst MAX_LINE_NUMBER = 2_147_483_647;\n\n/** One spelling of the resource-content digest every read result that carries a hash uses. */\nconst sha256Hex = (data: string | Buffer): string =>\n createHash('sha256').update(data).digest('hex');\n\nconst rangeField = (description: string, count = false) => {\n const field = z.int32().min(1, { message: 'Min: 1' });\n return (count ? field.max(100000, { message: 'Max: 100,000' }) : field)\n .optional()\n .describe(description);\n};\n\nconst readRangeFields = {\n head: rangeField('Return first N lines', true),\n tail: rangeField('Return last N lines', true),\n startLine: rangeField('Start line (1-indexed)'),\n endLine: rangeField('End line (1-indexed); requires startLine'),\n};\n\n/** A slice read: only a full read returns media or a binary resource. */\nfunction hasLineRange(args: {\n head?: number | undefined;\n tail?: number | undefined;\n startLine?: number | undefined;\n endLine?: number | undefined;\n}): boolean {\n return (\n args.head !== undefined ||\n args.tail !== undefined ||\n args.startLine !== undefined ||\n args.endLine !== undefined\n );\n}\n\nconst ReadFileInputSchema = singleOrBatchPathsInput({\n includeHash: defaultFalseBoolean('Include SHA-256 hash of the returned content in the response'),\n binary: defaultFalseBoolean(\n 'Return a binary file that is not an image or audio whole, as a base64 embedded resource. Full reads only.',\n ),\n ...readRangeFields,\n}).superRefine((value, ctx) => {\n validateReadRange(\n {\n head: value.head,\n tail: value.tail,\n startLine: value.startLine,\n endLine: value.endLine,\n },\n ctx,\n );\n if (value.binary && hasLineRange(value)) {\n ctx.addIssue({\n code: 'custom',\n path: ['binary'],\n message:\n \"Cannot use 'binary' with 'head'/'tail'/'startLine'/'endLine'. A binary file is read whole.\",\n input: value,\n });\n }\n});\n\ninterface ReadContinuation {\n tool: 'read';\n args: { path: string; startLine: number; endLine: number };\n hint: string;\n}\n\n// File bytes ride content blocks, never the structured metadata.\ninterface ReadPerPathValue {\n mimeType?: string;\n kind?: FileKind;\n resourceUri?: string;\n /** Bytes in the file; set when the bytes ride a media or resource block. */\n size?: number;\n /** ISO-8601 mtime at read time; also rides the resource_link. */\n modified?: string;\n continuation?: ReadContinuation;\n totalLines?: number;\n linesRead?: number;\n hasMoreLines?: boolean;\n head?: number;\n tail?: number;\n startLine?: number;\n endLine?: number;\n contentHash?: string;\n}\n\ntype ReadFileInput = z.infer<typeof ReadFileInputSchema>;\n\nconst READ_TOOL_LABEL = 'Read';\n\nfunction buildReadSpec(args: ReadFileInput, signal?: AbortSignal): ReadSpec {\n const signalPart = signal ? { signal } : {};\n const { head, tail, startLine, endLine } = args;\n\n if (head !== undefined) return { kind: 'head', lines: head, ...signalPart };\n if (tail !== undefined) return { kind: 'tail', lines: tail, ...signalPart };\n if (startLine !== undefined || endLine !== undefined) {\n return {\n kind: 'range',\n start: startLine ?? 1,\n ...(endLine !== undefined ? { end: endLine } : {}),\n ...signalPart,\n };\n }\n return { kind: 'full', ...signalPart };\n}\n\n// No `totalLines`: only `readFull` counts them and a full read never leaves\n// more behind, so a continuation cannot know the total without a second pass.\nfunction buildReadContinuation(\n result: ReadFileResult,\n requestedPath: string,\n): ReadContinuation | undefined {\n if (!result.hasMoreLines) return undefined;\n const linesRead = result.linesRead ?? 0;\n const nextStart = (result.startLine ?? 1) + linesRead;\n // Args the schema would reject are no continuation; clamp the end into it.\n if (nextStart > MAX_LINE_NUMBER) return undefined;\n let chunkSize: number;\n if (result.head !== undefined) {\n chunkSize = result.head;\n } else if (result.startLine !== undefined && result.endLine !== undefined) {\n chunkSize = result.endLine - result.startLine + 1;\n } else {\n chunkSize = DEFAULT_CONTINUATION_CHUNK_SIZE;\n }\n const nextEnd = Math.min(nextStart + chunkSize - 1, MAX_LINE_NUMBER);\n return {\n tool: 'read',\n args: { path: requestedPath, startLine: nextStart, endLine: nextEnd },\n hint: `More lines remain from ${String(nextStart)}. Read next chunk with these args.`,\n };\n}\n\n/**\n * The published metadata plus the bytes this call read. `content`, `mediaData`\n * and `blobData` exist only between `readOnePath` and the content blocks `run`\n * builds from them — they are stripped before the structured half is returned,\n * which is why they are not in `ReadPerPathValue`.\n */\ntype PerPathReadValue = ReadPerPathValue & {\n content?: string;\n fileSize?: number;\n mediaData?: string;\n blobData?: string;\n};\n\ninterface BatchFileInfo {\n index: number;\n size: number;\n}\n\ninterface BudgetItem {\n path: string;\n skip?: FsError;\n}\n\ninterface BudgetMode {\n fullRead: boolean;\n binary: boolean;\n}\n\n/**\n * What a file costs the batch: one whose bytes ship as base64 costs that size.\n * Only a full read ships base64; a slice of an svg is text.\n */\nfunction budgetBytes(path: string, size: number, { fullRead, binary }: BudgetMode): number {\n if (!fullRead) return size;\n const { kind } = detectMimeType(path);\n const base64 = kind === 'image' || kind === 'audio' || (binary && isKnownBinaryExtension(path));\n return base64 ? base64EncodedBytes(size) : size;\n}\n\nasync function collectFileBudget(\n filePaths: readonly string[],\n maxTotalSize: number,\n maxSize: number,\n ctx: Pick<ToolCtx, 'fs' | 'signal' | 'log'>,\n mode: BudgetMode,\n): Promise<BudgetItem[]> {\n const indexed = filePaths.map((path, index) => ({ path, index }));\n const { results } = await processInParallel(\n indexed,\n async ({ path, index }): Promise<BatchFileInfo | undefined> => {\n try {\n const out = await ctx.fs.stat(path);\n return { index, size: budgetBytes(path, Math.min(out.stats.size, maxSize), mode) };\n } catch (err: unknown) {\n ctx.log('debug', `collectFileBudget: stat failed for \"${path}\": ${String(err)}`, 'read');\n return undefined;\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n const byIndex = new Map<number, BatchFileInfo>();\n for (const { value: item } of results) {\n if (item) byIndex.set(item.index, item);\n }\n\n let total = 0;\n return filePaths.map((path, i): BudgetItem => {\n const info = byIndex.get(i);\n // A failed stat is not skipped, so its read surfaces the\n // real error, not a misleading TOO_LARGE.\n if (info === undefined) return { path };\n // Skip this file only; a later, smaller file that still fits is read.\n if (total + info.size > maxTotalSize) {\n return {\n path,\n skip: new FsError(\n ErrorCode.TOO_LARGE,\n `Skipped: this file alone would push the batch past maxTotalSize (${String(maxTotalSize)} bytes). Read it on its own with path instead of paths.`,\n path,\n ),\n };\n }\n total += info.size;\n return { path };\n });\n}\n\nfunction buildPerPathReadValue(\n result: ReadFileResult,\n options: { includeHash?: boolean; requestedPath: string },\n): PerPathReadValue {\n const mimeInfo = detectMimeFromContent(result.path, result.content);\n const continuation =\n result.hasMoreLines && result.readMode !== 'tail'\n ? buildReadContinuation(result, options.requestedPath)\n : undefined;\n const contentHash = options.includeHash ? sha256Hex(result.content) : undefined;\n\n const canLink = result.fileSize === undefined || result.fileSize <= getMaxTextFileSize();\n\n return {\n content: result.content,\n ...(result.fileSize !== undefined ? { fileSize: result.fileSize } : {}),\n mimeType: mimeInfo.mimeType,\n kind: mimeInfo.kind,\n ...(continuation ? { continuation } : {}),\n ...(result.totalLines !== undefined ? { totalLines: result.totalLines } : {}),\n ...(result.linesRead !== undefined ? { linesRead: result.linesRead } : {}),\n ...(result.hasMoreLines ? { hasMoreLines: true } : {}),\n ...(result.head !== undefined ? { head: result.head } : {}),\n ...(result.tail !== undefined ? { tail: result.tail } : {}),\n ...(result.startLine !== undefined ? { startLine: result.startLine } : {}),\n ...(result.endLine !== undefined ? { endLine: result.endLine } : {}),\n ...(contentHash !== undefined ? { contentHash } : {}),\n ...(canLink ? { resourceUri: buildFileResourceUri(result.path) } : {}),\n modified: result.modified,\n };\n}\n\n/**\n * The two facts the model cannot act on without: that lines were dropped, and\n * the exact args to get the next chunk. Both used to live only in the structured\n * half, which no longer reaches the model. Each line is `//` prefixed and set\n * off by a blank line so it cannot be read as file bytes — do not drop either\n * guard.\n */\nfunction readTrailer(v: PerPathReadValue): string[] {\n const lines: string[] = [];\n if (v.continuation) {\n lines.push(\n `// truncated: ${v.continuation.hint} Continue: read ${JSON.stringify(v.continuation.args)}`,\n );\n } else if (v.hasMoreLines && v.linesRead !== undefined) {\n // A tail read gets no continuation — there are no args that read *backwards*\n // — so say what was shown rather than leaving the truncation silent.\n lines.push(`// truncated: showing last ${String(v.linesRead)} lines`);\n }\n if (v.contentHash !== undefined) lines.push(`// sha256: ${v.contentHash}`);\n return lines;\n}\n\n/**\n * `binary: true` after the text path refused the file as binary. readRaw\n * re-validates the path (roots, denylist) and enforces the same size cap.\n * A file refused by its extension can still probe as text: it ships as the\n * extension says, octet-stream.\n */\nasync function readBinaryResource(\n filePath: string,\n args: ReadFileInput,\n ctx: ToolCtx,\n): Promise<PerPathReadValue> {\n const raw = await ctx.fs.readRaw(filePath, { signal: ctx.signal });\n const asText = raw.kind === 'text';\n const kind: FileKind = asText ? 'binary' : raw.kind;\n const mimeType = asText ? 'application/octet-stream' : raw.mimeType;\n const size = raw.content.length;\n return {\n content: `[binary ${kind} content: ${String(size)} bytes (${mimeType}); returned as an embedded resource block]`,\n mimeType,\n kind,\n size,\n resourceUri: buildFileResourceUri(raw.validPath),\n modified: raw.modified,\n blobData: raw.content.toString('base64'),\n ...(args.includeHash ? { contentHash: sha256Hex(raw.content) } : {}),\n };\n}\n\nasync function readOnePath(\n filePath: string,\n args: ReadFileInput,\n ctx: ToolCtx,\n): Promise<PerPathReadValue> {\n // Image/audio full read: return a media content block instead of throwing\n // INVALID_INPUT (\"Binary file detected.\"). Line-range reads are\n // text-oriented and stay rejected. `readRaw` enforces the same size cap as\n // the text path (getMaxTextFileSize), so a too-large image surfaces TOO_LARGE\n // rather than blowing memory. svg is kind 'image' in EXT_MAP, so readRaw\n // reports it binary and it returns as an image block.\n const isRangeRead = hasLineRange(args);\n if (!isRangeRead) {\n const mime = detectMimeType(filePath);\n if (mime.kind === 'image' || mime.kind === 'audio') {\n const raw = await ctx.fs.readRaw(filePath, { signal: ctx.signal });\n if (raw.isBinary) {\n return {\n content: `[binary ${mime.kind} content: ${String(raw.content.length)} bytes; returned as a ${mime.kind} content block]`,\n mimeType: raw.mimeType,\n kind: mime.kind,\n size: raw.content.length,\n resourceUri: buildFileResourceUri(raw.validPath),\n modified: raw.modified,\n mediaData: raw.content.toString('base64'),\n ...(args.includeHash ? { contentHash: sha256Hex(raw.content) } : {}),\n };\n }\n }\n }\n\n const spec = buildReadSpec(args, ctx.signal);\n // The read re-validates and re-stats: the budget pass's stat is only a\n // size estimate, never a substitute for the guarded open.\n let result: ReadFileResult;\n try {\n result = await ctx.fs.readFile(filePath, spec);\n } catch (error: unknown) {\n if (!isBinaryRefusal(error)) throw error;\n // The schema refuses binary with a range, so this is always a full read.\n if (args.binary) return await readBinaryResource(filePath, args, ctx);\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n isRangeRead\n ? `${BINARY_FILE_MESSAGE} It has no lines; read it whole with binary: true to get it as a base64 embedded resource.`\n : `${BINARY_FILE_MESSAGE} Pass binary: true to get it as a base64 embedded resource.`,\n filePath,\n error,\n );\n }\n\n return buildPerPathReadValue(result, {\n includeHash: args.includeHash,\n // The continuation is args the caller pastes back, so it echoes the path\n // they wrote, or the root-resolved one a relative path was rewritten to.\n // `result.path` is the real path — on Windows that is a backslash-doubling\n // JSON string that also spells out the server root.\n requestedPath: filePath,\n });\n}\n\nexport const READ = defineTool<typeof ReadFileInputSchema, BatchResult<ReadPerPathValue>>({\n name: 'read',\n title: 'Read File',\n description:\n 'Read text files, like cat: whole, or one slice via head, tail, or startLine/endLine. ' +\n 'Images and audio return as media; pass binary: true to get any other binary file whole as a base64 embedded resource.',\n input: ReadFileInputSchema,\n readOnlyHint: true,\n deadline: true,\n defaultErrorCode: ErrorCode.NOT_FILE,\n progress: (args) => {\n const isBatch = args.paths !== undefined;\n const name = isBatch ? `${String(args.paths?.length ?? 0)} files` : basename(args.path ?? '');\n if (isBatch) {\n return { label: READ_TOOL_LABEL, subject: name };\n }\n let scope: string | undefined;\n if (args.startLine !== undefined) {\n const end = args.endLine ?? '...';\n scope = `${args.startLine}-${String(end)}`;\n } else if (args.head !== undefined) {\n scope = `head ${args.head}`;\n } else if (args.tail !== undefined) {\n scope = `tail ${args.tail}`;\n }\n return { label: READ_TOOL_LABEL, subject: name, ...(scope ? { scope } : {}) };\n },\n mapPaths: mapSingleOrBatchPaths,\n run: async (args, ctx) => {\n const items: BudgetItem[] =\n args.paths !== undefined\n ? await collectFileBudget(\n args.paths,\n READ_MANY_MAX_TOTAL_BYTES,\n getMaxTextFileSize(),\n ctx,\n { fullRead: !hasLineRange(args), binary: args.binary },\n )\n : [{ path: args.path ?? '' }];\n const { results: ordered, summary } = await runOverPaths(\n items,\n ctx,\n ErrorCode.NOT_FILE,\n ({ path, skip }) => {\n if (skip) throw skip;\n return readOnePath(path, args, ctx);\n },\n );\n\n const resources: ContentBlock[] = [];\n for (const result of ordered) {\n if ('error' in result) continue;\n const v = result.value;\n if (v.blobData !== undefined && v.resourceUri !== undefined && v.mimeType !== undefined) {\n resources.push({\n type: 'resource',\n resource: { uri: v.resourceUri, mimeType: v.mimeType, blob: v.blobData },\n });\n continue;\n }\n // Image/audio full read: emit the media content block alongside the\n // structured value. The base64 lives in v.mediaData (set in readOnePath).\n if (v.mediaData && v.mimeType && (v.kind === 'image' || v.kind === 'audio')) {\n resources.push(\n v.kind === 'image'\n ? { type: 'image', data: v.mediaData, mimeType: v.mimeType }\n : { type: 'audio', data: v.mediaData, mimeType: v.mimeType },\n );\n continue;\n }\n if (!v.resourceUri || v.content === undefined) continue;\n // `result.path` is the path as *requested*; `v.resourceUri` was built from\n // the *validated* one. Rebuilding from the request would emit a second URI\n // for the same file whenever the two differ in case — subscribe by one and\n // unsubscribe by the other and the watcher never goes away.\n resources.push(\n buildFileResourceLinkFor(\n v.resourceUri,\n basename(result.path),\n v.mimeType ?? 'application/octet-stream',\n v.fileSize ?? Buffer.byteLength(v.content, 'utf8'),\n v.modified,\n ),\n );\n }\n\n const [firstOrdered] = ordered;\n const body = (v: PerPathReadValue): string => {\n const content = v.content ?? 'read failed';\n const trailer = readTrailer(v);\n if (trailer.length === 0) return content;\n // Exactly one blank line between the bytes and the trailer, whether or not\n // the file ended in a newline.\n return `${content}${content.endsWith('\\n') ? '\\n' : '\\n\\n'}${trailer.join('\\n')}`;\n };\n const text =\n ordered.length === 1 && firstOrdered !== undefined\n ? 'error' in firstOrdered\n ? firstOrdered.error.message\n : body(firstOrdered.value)\n : ordered\n .map((r) => {\n const header = `// ${r.path}`;\n if ('value' in r) return `${header}\\n${body(r.value)}`;\n return `${header}\\n// Error: ${r.error.message}`;\n })\n .join('\\n\\n');\n\n // The bytes ship once. `text` above already carries every file's content\n // verbatim (and image/audio bytes ride the media content block), so\n // repeating them under `results[].value` doubled both the wire payload and\n // the model's token cost for every read. The structured half keeps the\n // metadata a client cannot recover from the text: paths, line counts,\n // hashes, continuations, resourceUri.\n const structuredResults = ordered.map((result) => {\n if ('error' in result) return result;\n const {\n content: _content,\n fileSize: _fileSize,\n mediaData: _mediaData,\n blobData: _blobData,\n ...value\n } = result.value;\n return { ...result, value };\n });\n\n return {\n structured: { results: structuredResults, summary },\n text,\n isError: isTotalFailure(summary),\n ...(resources.length > 0 ? { resources } : {}),\n };\n },\n // Media and binary resources cannot be sliced, so head/tail is no remedy.\n oversizeRemedy: (result) => {\n const types = new Set(result.resources?.map((b) => b.type));\n if (types.has('image') || types.has('audio')) {\n return 'This media file is too large to return over the stdio transport; connect over HTTP, or raise it as a smaller file.';\n }\n if (types.has('resource')) {\n return 'This binary file is too large to return over the stdio transport; connect over HTTP.';\n }\n return 'Read a slice with head, tail, or startLine/endLine.';\n },\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"replace-text.d.ts","sourceRoot":"","sources":["../../src/tools/replace-text.ts"],"names":[],"mappings":"AAklBA,eAAO,MAAM,YAAY,mCA4EvB,CAAC"}
1
+ {"version":3,"file":"replace-text.d.ts","sourceRoot":"","sources":["../../src/tools/replace-text.ts"],"names":[],"mappings":"AAslBA,eAAO,MAAM,YAAY,mCA6FvB,CAAC"}