@j0hanz/filesystem-mcp 2.1.4 → 2.1.6

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 (148) hide show
  1. package/dist/cli.d.ts +2 -14
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +14 -22
  4. package/dist/cli.js.map +1 -1
  5. package/dist/core/cursor.d.ts +2 -14
  6. package/dist/core/cursor.d.ts.map +1 -1
  7. package/dist/core/cursor.js +25 -39
  8. package/dist/core/cursor.js.map +1 -1
  9. package/dist/core/diff.d.ts +6 -0
  10. package/dist/core/diff.d.ts.map +1 -0
  11. package/dist/core/diff.js +21 -0
  12. package/dist/core/diff.js.map +1 -0
  13. package/dist/core/errors.d.ts +2 -31
  14. package/dist/core/errors.d.ts.map +1 -1
  15. package/dist/core/errors.js +15 -86
  16. package/dist/core/errors.js.map +1 -1
  17. package/dist/core/file-uri.d.ts +18 -2
  18. package/dist/core/file-uri.d.ts.map +1 -1
  19. package/dist/core/file-uri.js +34 -6
  20. package/dist/core/file-uri.js.map +1 -1
  21. package/dist/core/fmt.js +5 -5
  22. package/dist/core/fmt.js.map +1 -1
  23. package/dist/core/fs.d.ts +4 -13
  24. package/dist/core/fs.d.ts.map +1 -1
  25. package/dist/core/fs.js +4 -41
  26. package/dist/core/fs.js.map +1 -1
  27. package/dist/core/glob.d.ts +1 -7
  28. package/dist/core/glob.d.ts.map +1 -1
  29. package/dist/core/glob.js +1 -11
  30. package/dist/core/glob.js.map +1 -1
  31. package/dist/core/input-required.d.ts +2 -10
  32. package/dist/core/input-required.d.ts.map +1 -1
  33. package/dist/core/input-required.js +3 -12
  34. package/dist/core/input-required.js.map +1 -1
  35. package/dist/core/path-completer.d.ts.map +1 -1
  36. package/dist/core/path-completer.js +3 -7
  37. package/dist/core/path-completer.js.map +1 -1
  38. package/dist/core/path-discovery.js +2 -2
  39. package/dist/core/path-discovery.js.map +1 -1
  40. package/dist/core/path.d.ts +10 -25
  41. package/dist/core/path.d.ts.map +1 -1
  42. package/dist/core/path.js +28 -66
  43. package/dist/core/path.js.map +1 -1
  44. package/dist/core/primitives.d.ts +8 -3
  45. package/dist/core/primitives.d.ts.map +1 -1
  46. package/dist/core/primitives.js +10 -5
  47. package/dist/core/primitives.js.map +1 -1
  48. package/dist/core/read.d.ts +0 -16
  49. package/dist/core/read.d.ts.map +1 -1
  50. package/dist/core/read.js +19 -56
  51. package/dist/core/read.js.map +1 -1
  52. package/dist/core/schema.d.ts +1 -32
  53. package/dist/core/schema.d.ts.map +1 -1
  54. package/dist/core/schema.js +7 -66
  55. package/dist/core/schema.js.map +1 -1
  56. package/dist/core/search.d.ts +16 -5
  57. package/dist/core/search.d.ts.map +1 -1
  58. package/dist/core/search.js +118 -108
  59. package/dist/core/search.js.map +1 -1
  60. package/dist/core/sensitive.d.ts.map +1 -1
  61. package/dist/core/sensitive.js +7 -15
  62. package/dist/core/sensitive.js.map +1 -1
  63. package/dist/core/store.d.ts +1 -3
  64. package/dist/core/store.d.ts.map +1 -1
  65. package/dist/core/store.js +1 -5
  66. package/dist/core/store.js.map +1 -1
  67. package/dist/core/watcher-registry.d.ts +1 -8
  68. package/dist/core/watcher-registry.d.ts.map +1 -1
  69. package/dist/core/watcher-registry.js +3 -12
  70. package/dist/core/watcher-registry.js.map +1 -1
  71. package/dist/index.js +1 -8
  72. package/dist/index.js.map +1 -1
  73. package/dist/prompts.d.ts.map +1 -1
  74. package/dist/prompts.js +7 -33
  75. package/dist/prompts.js.map +1 -1
  76. package/dist/resources.d.ts +1 -1
  77. package/dist/resources.d.ts.map +1 -1
  78. package/dist/resources.js +3 -9
  79. package/dist/resources.js.map +1 -1
  80. package/dist/server.d.ts +0 -3
  81. package/dist/server.d.ts.map +1 -1
  82. package/dist/server.js +1 -5
  83. package/dist/server.js.map +1 -1
  84. package/dist/tools/batch.d.ts +5 -69
  85. package/dist/tools/batch.d.ts.map +1 -1
  86. package/dist/tools/batch.js +7 -117
  87. package/dist/tools/batch.js.map +1 -1
  88. package/dist/tools/create.d.ts.map +1 -1
  89. package/dist/tools/create.js +8 -18
  90. package/dist/tools/create.js.map +1 -1
  91. package/dist/tools/define.d.ts +1 -4
  92. package/dist/tools/define.d.ts.map +1 -1
  93. package/dist/tools/define.js +6 -24
  94. package/dist/tools/define.js.map +1 -1
  95. package/dist/tools/delete-file.d.ts.map +1 -1
  96. package/dist/tools/delete-file.js +6 -6
  97. package/dist/tools/delete-file.js.map +1 -1
  98. package/dist/tools/diff.d.ts.map +1 -1
  99. package/dist/tools/diff.js +3 -10
  100. package/dist/tools/diff.js.map +1 -1
  101. package/dist/tools/edit.d.ts.map +1 -1
  102. package/dist/tools/edit.js +43 -87
  103. package/dist/tools/edit.js.map +1 -1
  104. package/dist/tools/index.d.ts +0 -1
  105. package/dist/tools/index.d.ts.map +1 -1
  106. package/dist/tools/index.js +0 -1
  107. package/dist/tools/index.js.map +1 -1
  108. package/dist/tools/list.js +3 -2
  109. package/dist/tools/list.js.map +1 -1
  110. package/dist/tools/move.d.ts.map +1 -1
  111. package/dist/tools/move.js +169 -119
  112. package/dist/tools/move.js.map +1 -1
  113. package/dist/tools/patch.d.ts.map +1 -1
  114. package/dist/tools/patch.js +5 -23
  115. package/dist/tools/patch.js.map +1 -1
  116. package/dist/tools/progress.d.ts +0 -1
  117. package/dist/tools/progress.d.ts.map +1 -1
  118. package/dist/tools/progress.js +2 -8
  119. package/dist/tools/progress.js.map +1 -1
  120. package/dist/tools/read.d.ts.map +1 -1
  121. package/dist/tools/read.js +21 -25
  122. package/dist/tools/read.js.map +1 -1
  123. package/dist/tools/replace-in-files.d.ts.map +1 -1
  124. package/dist/tools/replace-in-files.js +25 -44
  125. package/dist/tools/replace-in-files.js.map +1 -1
  126. package/dist/tools/search-content.d.ts.map +1 -1
  127. package/dist/tools/search-content.js +17 -49
  128. package/dist/tools/search-content.js.map +1 -1
  129. package/dist/tools/search-files.d.ts.map +1 -1
  130. package/dist/tools/search-files.js +1 -2
  131. package/dist/tools/search-files.js.map +1 -1
  132. package/dist/tools/stat.d.ts.map +1 -1
  133. package/dist/tools/stat.js +5 -6
  134. package/dist/tools/stat.js.map +1 -1
  135. package/dist/transport/http-policy.d.ts +6 -0
  136. package/dist/transport/http-policy.d.ts.map +1 -1
  137. package/dist/transport/http-policy.js +2 -2
  138. package/dist/transport/http-policy.js.map +1 -1
  139. package/dist/transport/http.d.ts.map +1 -1
  140. package/dist/transport/http.js +4 -11
  141. package/dist/transport/http.js.map +1 -1
  142. package/dist/transport/stdio.js +1 -1
  143. package/dist/transport/stdio.js.map +1 -1
  144. package/dist/transport.d.ts +1 -3
  145. package/dist/transport.d.ts.map +1 -1
  146. package/dist/transport.js +5 -2
  147. package/dist/transport.js.map +1 -1
  148. package/package.json +1 -1
package/dist/core/read.js CHANGED
@@ -57,7 +57,7 @@ import { ErrorCode, formatUnknownErrorMessage, FsError, isFsError } from './erro
57
57
  import { isBinarySample, isKnownBinaryExtension, MIME_SAMPLE_SIZE } from './mime.js';
58
58
  import { Logger } from './observability.js';
59
59
  import { getMaxTextFileSize } from './util.js';
60
- export const STREAM_CHUNK_SIZE = 64 * 1024;
60
+ const STREAM_CHUNK_SIZE = 64 * 1024;
61
61
  const READ_ONLY_FILE_FLAG = 'r';
62
62
  function assertPositiveIntegerOption(name, value, message) {
63
63
  if (value === undefined ||
@@ -118,25 +118,11 @@ async function isProbablyBinary(filePath, existingHandle, signal) {
118
118
  }
119
119
  }
120
120
  function buildBaseOptions(spec) {
121
- if (spec.maxSize !== undefined) {
122
- assertPositiveIntegerOption('maxSize', spec.maxSize, 'maxSize must be at least 1');
123
- }
124
- const maxTextFileSize = getMaxTextFileSize();
125
121
  return {
126
- encoding: spec.encoding ?? 'utf-8',
127
- maxSize: Math.min(spec.maxSize ?? maxTextFileSize, maxTextFileSize),
128
- skipBinary: spec.skipBinary ?? false,
122
+ maxSize: getMaxTextFileSize(),
129
123
  ...(spec.signal ? { signal: spec.signal } : {}),
130
124
  };
131
125
  }
132
- function normalizeHeadSpec(spec, base) {
133
- assertPositiveIntegerOption('lines', spec.lines, 'lines must be at least 1');
134
- return { ...base, kind: 'head', lines: spec.lines };
135
- }
136
- function normalizeTailSpec(spec, base) {
137
- assertPositiveIntegerOption('lines', spec.lines, 'lines must be at least 1');
138
- return { ...base, kind: 'tail', lines: spec.lines };
139
- }
140
126
  function normalizeRangeSpec(spec, base) {
141
127
  assertPositiveIntegerOption('start', spec.start, 'start must be at least 1');
142
128
  if (spec.end !== undefined) {
@@ -157,9 +143,9 @@ export function normalizeSpec(spec) {
157
143
  spec.signal?.throwIfAborted();
158
144
  switch (spec.kind) {
159
145
  case 'head':
160
- return normalizeHeadSpec(spec, base);
161
146
  case 'tail':
162
- return normalizeTailSpec(spec, base);
147
+ assertPositiveIntegerOption('lines', spec.lines, 'lines must be at least 1');
148
+ return { ...base, kind: spec.kind, lines: spec.lines };
163
149
  case 'range':
164
150
  return normalizeRangeSpec(spec, base);
165
151
  case 'full':
@@ -170,17 +156,8 @@ export function normalizeSpec(spec) {
170
156
  }
171
157
  }
172
158
  }
173
- function buildReadContentOptions(normalized) {
174
- const result = {
175
- encoding: normalized.encoding,
176
- maxSize: normalized.maxSize,
177
- };
178
- if (normalized.signal)
179
- result.signal = normalized.signal;
180
- return result;
181
- }
182
159
  export function createTooLargeError(bytesRead, maxSize, requestedPath) {
183
- return new FsError(ErrorCode.TOO_LARGE, `File exceeds size limit (${bytesRead} > ${maxSize} bytes)`, requestedPath, { size: bytesRead, maxSize });
160
+ return new FsError(ErrorCode.TOO_LARGE, `File exceeds size limit (${bytesRead} > ${maxSize} bytes)`, requestedPath);
184
161
  }
185
162
  export async function readFileBufferWithLimit(handle, maxSize, requestedPath, signal) {
186
163
  const stream = handle.createReadStream({
@@ -256,11 +233,11 @@ async function* readLinesBounded(handle, options, filePath, startLine) {
256
233
  emitClose: false,
257
234
  ...(options.signal ? { signal: options.signal } : {}),
258
235
  });
259
- const decoder = new StringDecoder(options.encoding);
236
+ const decoder = new StringDecoder('utf-8');
260
237
  let pending = '';
261
238
  let pendingBytes = 0;
262
239
  let lineNumber = 0;
263
- const tooLong = (bytes) => new FsError(ErrorCode.TOO_LARGE, `File too large (single line ${bytes} > ${options.maxSize} bytes). Use a narrower range or head.`, filePath, { size: bytes, maxSize: options.maxSize });
240
+ const tooLong = (bytes) => new FsError(ErrorCode.TOO_LARGE, `File too large (single line ${bytes} > ${options.maxSize} bytes). Use a narrower range or head.`, filePath);
264
241
  try {
265
242
  for await (const chunk of stream) {
266
243
  const buffer = chunk;
@@ -322,10 +299,9 @@ async function readRangeContent(handle, startLine, endLine, options, filePath) {
322
299
  const lines = [];
323
300
  let lineNumber = startLine - 1;
324
301
  let estimatedBytes = 0;
325
- const newlineBytes = Buffer.byteLength('\n', options.encoding);
302
+ const newlineBytes = Buffer.byteLength('\n', 'utf-8');
326
303
  const stopAt = endLine ?? Number.POSITIVE_INFINITY;
327
304
  let hasMoreLines = false;
328
- let stoppedByLimit = false;
329
305
  // Byte-bounded: an over-long line throws TOO_LARGE while still a partial
330
306
  // buffer, before it can be decoded into one huge string.
331
307
  const iterator = readLinesBounded(handle, options, filePath, startLine)[Symbol.asyncIterator]();
@@ -341,9 +317,8 @@ async function readRangeContent(handle, startLine, endLine, options, filePath) {
341
317
  break;
342
318
  }
343
319
  lines.push(line);
344
- estimatedBytes += Buffer.byteLength(line, options.encoding) + newlineBytes;
320
+ estimatedBytes += Buffer.byteLength(line, 'utf-8') + newlineBytes;
345
321
  if (estimatedBytes > options.maxSize) {
346
- stoppedByLimit = true;
347
322
  hasMoreLines = await peekHasMore(iterator);
348
323
  break;
349
324
  }
@@ -358,7 +333,6 @@ async function readRangeContent(handle, startLine, endLine, options, filePath) {
358
333
  }
359
334
  return {
360
335
  content: lines.join('\n'),
361
- truncated: stoppedByLimit || hasMoreLines,
362
336
  linesRead: lines.length,
363
337
  hasMoreLines,
364
338
  };
@@ -370,12 +344,11 @@ async function readTailContent(handle, tail, options, filePath) {
370
344
  if (fileSize === 0) {
371
345
  return {
372
346
  content: '',
373
- truncated: false,
374
347
  linesRead: 0,
375
348
  hasMoreLines: false,
376
349
  };
377
350
  }
378
- const encoding = options.encoding;
351
+ const encoding = 'utf-8';
379
352
  // Accumulate raw bytes from the end: decoding a chunk ending mid-codepoint
380
353
  // corrupts the trailing UTF-8 sequence into U+FFFD. 0x0A is single-byte and
381
354
  // never part of a multibyte sequence, so count newlines on the raw buffer and
@@ -428,7 +401,7 @@ async function readTailContent(handle, tail, options, filePath) {
428
401
  lines = lines.slice(1);
429
402
  }
430
403
  if (stoppedByLimit && lines.length < tail) {
431
- throw new FsError(ErrorCode.TOO_LARGE, `File too large (${totalLen} > ${options.maxSize} bytes, could not collect ${tail} lines). Use a narrower tail or head.`, filePath, { size: totalLen, maxSize: options.maxSize });
404
+ throw new FsError(ErrorCode.TOO_LARGE, `File too large (${totalLen} > ${options.maxSize} bytes, could not collect ${tail} lines). Use a narrower tail or head.`, filePath);
432
405
  }
433
406
  let hasMoreLines = stoppedByLimit || position > 0;
434
407
  if (lines.length > tail) {
@@ -438,14 +411,13 @@ async function readTailContent(handle, tail, options, filePath) {
438
411
  const content = lines.join('\n');
439
412
  return {
440
413
  content,
441
- truncated: hasMoreLines,
442
414
  linesRead: lines.length,
443
415
  hasMoreLines,
444
416
  };
445
417
  }
446
- async function readFullContent(handle, encoding, maxSize, requestedPath, signal) {
418
+ async function readFullContent(handle, maxSize, requestedPath, signal) {
447
419
  const buffer = await readFileBufferWithLimit(handle, maxSize, requestedPath, signal);
448
- const content = buffer.toString(encoding);
420
+ const content = buffer.toString('utf-8');
449
421
  return { content, totalLines: countLines(content) };
450
422
  }
451
423
  async function assertNotBinary(validPath, filePath, handle, normalized) {
@@ -458,15 +430,13 @@ async function assertNotBinary(validPath, filePath, handle, normalized) {
458
430
  function assertSizeWithinLimit(size, maxSize, filePath) {
459
431
  if (size <= maxSize)
460
432
  return;
461
- throw new FsError(ErrorCode.TOO_LARGE, `File too large (${size} > ${maxSize} bytes). Use head to preview.`, filePath, { size, maxSize });
433
+ throw new FsError(ErrorCode.TOO_LARGE, `File too large (${size} > ${maxSize} bytes). Use head to preview.`, filePath);
462
434
  }
463
435
  async function readHead(context, spec) {
464
- const contentOptions = buildReadContentOptions(spec);
465
- const { content, truncated, linesRead, hasMoreLines } = await readRangeContent(context.handle, 1, spec.lines, contentOptions, context.filePath);
436
+ const { content, linesRead, hasMoreLines } = await readRangeContent(context.handle, 1, spec.lines, spec, context.filePath);
466
437
  return {
467
438
  path: context.validPath,
468
439
  content,
469
- truncated,
470
440
  readMode: 'head',
471
441
  head: spec.lines,
472
442
  linesRead,
@@ -474,12 +444,10 @@ async function readHead(context, spec) {
474
444
  };
475
445
  }
476
446
  async function readRange(context, spec) {
477
- const contentOptions = buildReadContentOptions(spec);
478
- const { content, truncated, linesRead, hasMoreLines } = await readRangeContent(context.handle, spec.start, spec.end, contentOptions, context.filePath);
447
+ const { content, linesRead, hasMoreLines } = await readRangeContent(context.handle, spec.start, spec.end, spec, context.filePath);
479
448
  return {
480
449
  path: context.validPath,
481
450
  content,
482
- truncated,
483
451
  readMode: 'range',
484
452
  startLine: spec.start,
485
453
  ...(spec.end !== undefined ? { endLine: spec.end } : {}),
@@ -489,11 +457,10 @@ async function readRange(context, spec) {
489
457
  }
490
458
  async function readFull(context, spec) {
491
459
  assertSizeWithinLimit(context.stats.size, spec.maxSize, context.filePath);
492
- const { content, totalLines } = await readFullContent(context.handle, spec.encoding, spec.maxSize, context.filePath, spec.signal);
460
+ const { content, totalLines } = await readFullContent(context.handle, spec.maxSize, context.filePath, spec.signal);
493
461
  return {
494
462
  path: context.validPath,
495
463
  content,
496
- truncated: false,
497
464
  totalLines,
498
465
  readMode: 'full',
499
466
  linesRead: totalLines,
@@ -501,12 +468,10 @@ async function readFull(context, spec) {
501
468
  };
502
469
  }
503
470
  async function readTail(context, spec) {
504
- const contentOptions = buildReadContentOptions(spec);
505
- const { content, truncated, linesRead, hasMoreLines } = await readTailContent(context.handle, spec.lines, contentOptions, context.validPath);
471
+ const { content, linesRead, hasMoreLines } = await readTailContent(context.handle, spec.lines, spec, context.validPath);
506
472
  return {
507
473
  path: context.validPath,
508
474
  content,
509
- truncated,
510
475
  readMode: 'tail',
511
476
  tail: spec.lines,
512
477
  linesRead,
@@ -540,9 +505,7 @@ export async function readNormalized(filePath, validPath, stats, spec) {
540
505
  spec.signal?.throwIfAborted();
541
506
  assertFileStats(filePath, stats);
542
507
  const handle = __addDisposableResource(env_2, await openReadableFileHandle(validPath, spec.signal), true);
543
- if (spec.skipBinary) {
544
- await assertNotBinary(validPath, filePath, handle, spec);
545
- }
508
+ await assertNotBinary(validPath, filePath, handle, spec);
546
509
  spec.signal?.throwIfAborted();
547
510
  return await readByMode({ handle, validPath, filePath, stats, spec });
548
511
  }
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/core/read.ts"],"names":[],"mappings":"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","sourcesContent":["// File reading pipeline split out of fs.ts. fs.ts imports from here; never the reverse.\nimport type { Stats } from 'node:fs';\nimport { open as fsOpen } from 'node:fs/promises';\nimport type { FileHandle } from 'node:fs/promises';\nimport { StringDecoder } from 'node:string_decoder';\n\nimport { withAbort } from './concurrency.js';\nimport { ErrorCode, formatUnknownErrorMessage, FsError, isFsError } from './errors.js';\nimport { isBinarySample, isKnownBinaryExtension, MIME_SAMPLE_SIZE } from './mime.js';\nimport { Logger } from './observability.js';\nimport { getMaxTextFileSize } from './util.js';\n\nexport const STREAM_CHUNK_SIZE = 64 * 1024;\n\nconst READ_ONLY_FILE_FLAG = 'r';\n\nfunction assertPositiveIntegerOption(name: string, value: unknown, message?: string): void {\n if (\n value === undefined ||\n (typeof value === 'number' && Number.isSafeInteger(value) && value >= 1)\n )\n return;\n throw new FsError(ErrorCode.INVALID_INPUT, message ?? `${name} must be a positive integer`);\n}\n\nasync function openReadableFileHandle(filePath: string, signal?: AbortSignal): Promise<FileHandle> {\n const handlePromise = fsOpen(filePath, READ_ONLY_FILE_FLAG);\n if (!signal) return handlePromise;\n try {\n return await withAbort(handlePromise, signal);\n } catch (error) {\n void handlePromise\n .then((handle) => {\n void handle.close().catch((closeErr: unknown) => {\n Logger.warn(\n `Failed to close file handle for ${filePath} after abort: ${formatUnknownErrorMessage(closeErr)}`,\n );\n });\n })\n .catch(() => {\n /* ignore open error */\n });\n throw error;\n }\n}\n\nasync function readProbe(handle: FileHandle, signal?: AbortSignal): Promise<Buffer> {\n const buffer = Buffer.allocUnsafe(MIME_SAMPLE_SIZE);\n const { bytesRead } = await withAbort(handle.read(buffer, 0, MIME_SAMPLE_SIZE, 0), signal);\n\n if (bytesRead === 0) {\n return Buffer.alloc(0);\n }\n\n return buffer.subarray(0, bytesRead);\n}\n\nasync function isProbablyBinary(\n filePath: string,\n existingHandle?: FileHandle,\n signal?: AbortSignal,\n): Promise<boolean> {\n if (isKnownBinaryExtension(filePath)) {\n return true;\n }\n\n if (existingHandle) {\n const slice = await readProbe(existingHandle, signal);\n return isBinarySample(slice);\n }\n\n await using handle = await openReadableFileHandle(filePath, signal);\n const slice = await readProbe(handle, signal);\n return isBinarySample(slice);\n}\n\nexport type ReadSpec =\n | {\n kind: 'full';\n encoding?: BufferEncoding;\n maxSize?: number;\n skipBinary?: boolean;\n signal?: AbortSignal;\n }\n | {\n kind: 'head';\n lines: number;\n encoding?: BufferEncoding;\n maxSize?: number;\n skipBinary?: boolean;\n signal?: AbortSignal;\n }\n | {\n kind: 'tail';\n lines: number;\n encoding?: BufferEncoding;\n maxSize?: number;\n skipBinary?: boolean;\n signal?: AbortSignal;\n }\n | {\n kind: 'range';\n start: number;\n end?: number;\n encoding?: BufferEncoding;\n maxSize?: number;\n skipBinary?: boolean;\n signal?: AbortSignal;\n };\n\ninterface NormalizedBase {\n encoding: BufferEncoding;\n maxSize: number;\n skipBinary: boolean;\n signal?: AbortSignal;\n}\n\ntype NormalizedSpec =\n | (NormalizedBase & { kind: 'full' })\n | (NormalizedBase & { kind: 'head'; lines: number })\n | (NormalizedBase & { kind: 'tail'; lines: number })\n | (NormalizedBase & { kind: 'range'; start: number; end?: number });\n\ninterface ReadContentOptions {\n encoding: BufferEncoding;\n maxSize: number;\n signal?: AbortSignal;\n}\n\ninterface PartialReadResult {\n content: string;\n truncated: boolean;\n linesRead: number;\n hasMoreLines: boolean;\n}\n\nexport interface ReadFileResult {\n path: string;\n content: string;\n truncated: boolean;\n totalLines?: number;\n readMode: ReadSpec['kind'];\n head?: number;\n tail?: number;\n startLine?: number;\n endLine?: number;\n linesRead?: number;\n hasMoreLines?: boolean;\n}\n\nfunction buildBaseOptions(spec: ReadSpec): NormalizedBase {\n if (spec.maxSize !== undefined) {\n assertPositiveIntegerOption('maxSize', spec.maxSize, 'maxSize must be at least 1');\n }\n const maxTextFileSize = getMaxTextFileSize();\n return {\n encoding: spec.encoding ?? 'utf-8',\n maxSize: Math.min(spec.maxSize ?? maxTextFileSize, maxTextFileSize),\n skipBinary: spec.skipBinary ?? false,\n ...(spec.signal ? { signal: spec.signal } : {}),\n };\n}\n\nfunction normalizeHeadSpec(\n spec: Extract<ReadSpec, { kind: 'head' }>,\n base: NormalizedBase,\n): NormalizedSpec {\n assertPositiveIntegerOption('lines', spec.lines, 'lines must be at least 1');\n return { ...base, kind: 'head', lines: spec.lines };\n}\n\nfunction normalizeTailSpec(\n spec: Extract<ReadSpec, { kind: 'tail' }>,\n base: NormalizedBase,\n): NormalizedSpec {\n assertPositiveIntegerOption('lines', spec.lines, 'lines must be at least 1');\n return { ...base, kind: 'tail', lines: spec.lines };\n}\n\nfunction normalizeRangeSpec(\n spec: Extract<ReadSpec, { kind: 'range' }>,\n base: NormalizedBase,\n): NormalizedSpec {\n assertPositiveIntegerOption('start', spec.start, 'start must be at least 1');\n if (spec.end !== undefined) {\n assertPositiveIntegerOption('end', spec.end, 'end must be at least 1');\n if (spec.end < spec.start) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n 'end must be greater than or equal to start (default: 1)',\n );\n }\n }\n return {\n ...base,\n kind: 'range',\n start: spec.start,\n ...(spec.end !== undefined ? { end: spec.end } : {}),\n };\n}\n\nexport function normalizeSpec(spec: ReadSpec): NormalizedSpec {\n const base = buildBaseOptions(spec);\n spec.signal?.throwIfAborted();\n\n switch (spec.kind) {\n case 'head':\n return normalizeHeadSpec(spec, base);\n case 'tail':\n return normalizeTailSpec(spec, base);\n case 'range':\n return normalizeRangeSpec(spec, base);\n case 'full':\n return { ...base, kind: 'full' };\n default: {\n const _exhaustive: never = spec;\n return _exhaustive;\n }\n }\n}\n\nfunction buildReadContentOptions(normalized: NormalizedBase): ReadContentOptions {\n const result: ReadContentOptions = {\n encoding: normalized.encoding,\n maxSize: normalized.maxSize,\n };\n if (normalized.signal) result.signal = normalized.signal;\n return result;\n}\n\nexport function createTooLargeError(\n bytesRead: number,\n maxSize: number,\n requestedPath: string,\n): FsError {\n return new FsError(\n ErrorCode.TOO_LARGE,\n `File exceeds size limit (${bytesRead} > ${maxSize} bytes)`,\n requestedPath,\n { size: bytesRead, maxSize },\n );\n}\n\nexport async function readFileBufferWithLimit(\n handle: FileHandle,\n maxSize: number,\n requestedPath: string,\n signal?: AbortSignal,\n): Promise<Buffer> {\n const stream = handle.createReadStream({\n start: 0,\n highWaterMark: STREAM_CHUNK_SIZE,\n autoClose: false,\n emitClose: false,\n signal,\n });\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n\n try {\n for await (const chunk of stream) {\n const buffer = chunk as Buffer;\n totalSize += buffer.length;\n\n if (totalSize > maxSize) {\n stream.destroy();\n throw createTooLargeError(totalSize, maxSize, requestedPath);\n }\n\n chunks.push(buffer);\n }\n } finally {\n if (!stream.destroyed) {\n stream.on('error', (_err: unknown) => {\n /* suppress post-destroy error event */\n });\n stream.destroy();\n }\n }\n\n return Buffer.concat(chunks, totalSize);\n}\n\nexport const countLines = (content: string): number => {\n if (content.length === 0) return 0;\n const trimmed = content.endsWith('\\n') ? content.slice(0, -1) : content;\n return trimmed.split('\\n').length;\n};\n\nasync function peekHasMore(iterator: AsyncIterator<string>): Promise<boolean> {\n try {\n const { done } = await iterator.next();\n return !done;\n } catch (error) {\n // The peek only asks \"is there another line\", and the caller keeps nothing\n // it returns. An over-long line past the requested range still answers yes\n // — failing the whole read over a line outside it would reject e.g. lines\n // 1-2 of a file whose line 3 is one 50 KB blob.\n if (isFsError(error) && error.code === ErrorCode.TOO_LARGE) return true;\n throw error;\n }\n}\n\nconst LF = 0x0a;\n\nfunction stripCarriageReturn(line: string): string {\n return line.endsWith('\\r') ? line.slice(0, -1) : line;\n}\n\n/**\n * Line iterator bounded by bytes rather than by the decoded string, so a file\n * that is one enormous line cannot be materialized before the size check runs.\n * `handle.readLines` decodes the whole line first and can OOM on such a file.\n *\n * Yields lines from `startLine` onward, 1-indexed. Lines before `startLine` are\n * counted and discarded without accumulating, so an over-long line the caller\n * skipped past does not fail the read. Line endings match `readLines`: split on\n * `\\n`, with a preceding `\\r` stripped, so CRLF input decodes identically.\n */\nasync function* readLinesBounded(\n handle: FileHandle,\n options: ReadContentOptions,\n filePath: string,\n startLine: number,\n): AsyncGenerator<string, void, undefined> {\n const stream = handle.createReadStream({\n start: 0,\n highWaterMark: STREAM_CHUNK_SIZE,\n autoClose: false,\n emitClose: false,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n\n const decoder = new StringDecoder(options.encoding);\n let pending = '';\n let pendingBytes = 0;\n let lineNumber = 0;\n\n const tooLong = (bytes: number): FsError =>\n new FsError(\n ErrorCode.TOO_LARGE,\n `File too large (single line ${bytes} > ${options.maxSize} bytes). Use a narrower range or head.`,\n filePath,\n { size: bytes, maxSize: options.maxSize },\n );\n\n try {\n for await (const chunk of stream) {\n const buffer = chunk as Buffer;\n let offset = 0;\n\n // Search loop: each iteration finds the next LF and advances offset past\n // it. Written as while-with-assignment so the re-search is visible, rather\n // than buried in a for \"increment\" slot that re-runs indexOf.\n let nl = buffer.indexOf(LF, offset);\n while (nl !== -1) {\n const segment = buffer.subarray(offset, nl);\n const lineBytes = pendingBytes + segment.length;\n lineNumber++;\n // Decode even when skipping: the decoder carries multi-byte\n // continuation state into the first line the caller keeps.\n const decoded = decoder.write(segment);\n if (lineNumber >= startLine) {\n if (lineBytes > options.maxSize) throw tooLong(lineBytes);\n yield stripCarriageReturn(pending + decoded);\n }\n pending = '';\n pendingBytes = 0;\n offset = nl + 1;\n nl = buffer.indexOf(LF, offset);\n }\n\n const rest = buffer.subarray(offset);\n pendingBytes += rest.length;\n if (lineNumber + 1 < startLine) {\n decoder.write(rest); // still skipping; drop the text, keep decoder state\n } else {\n if (pendingBytes > options.maxSize) throw tooLong(pendingBytes);\n pending += decoder.write(rest);\n }\n }\n\n // Trailing line with no final newline. A file ending in `\\n` leaves\n // pendingBytes at 0 and emits nothing, matching readLines.\n if (pendingBytes > 0) {\n lineNumber++;\n if (lineNumber >= startLine) {\n if (pendingBytes > options.maxSize) throw tooLong(pendingBytes);\n yield pending + decoder.end();\n }\n }\n } finally {\n if (!stream.destroyed) {\n stream.on('error', (_err: unknown) => {\n /* suppress post-destroy error event */\n });\n stream.destroy();\n }\n }\n}\n\nasync function readRangeContent(\n handle: FileHandle,\n startLine: number,\n endLine: number | undefined,\n options: ReadContentOptions,\n filePath: string,\n): Promise<PartialReadResult> {\n options.signal?.throwIfAborted();\n\n const lines: string[] = [];\n let lineNumber = startLine - 1;\n let estimatedBytes = 0;\n const newlineBytes = Buffer.byteLength('\\n', options.encoding);\n const stopAt = endLine ?? Number.POSITIVE_INFINITY;\n\n let hasMoreLines = false;\n let stoppedByLimit = false;\n\n // Byte-bounded: an over-long line throws TOO_LARGE while still a partial\n // buffer, before it can be decoded into one huge string.\n const iterator = readLinesBounded(handle, options, filePath, startLine)[Symbol.asyncIterator]();\n\n try {\n for (;;) {\n const { value: line, done } = await iterator.next();\n if (done) {\n break;\n }\n lineNumber++;\n\n if (lineNumber > stopAt) {\n hasMoreLines = true;\n break;\n }\n\n lines.push(line);\n\n estimatedBytes += Buffer.byteLength(line, options.encoding) + newlineBytes;\n if (estimatedBytes > options.maxSize) {\n stoppedByLimit = true;\n hasMoreLines = await peekHasMore(iterator);\n break;\n }\n\n if (lineNumber === stopAt) {\n hasMoreLines = await peekHasMore(iterator);\n break;\n }\n }\n } finally {\n await iterator.return();\n }\n\n return {\n content: lines.join('\\n'),\n truncated: stoppedByLimit || hasMoreLines,\n linesRead: lines.length,\n hasMoreLines,\n };\n}\n\nasync function readTailContent(\n handle: FileHandle,\n tail: number,\n options: ReadContentOptions,\n filePath: string,\n): Promise<PartialReadResult> {\n options.signal?.throwIfAborted();\n\n const stats = await handle.stat();\n const fileSize = stats.size;\n if (fileSize === 0) {\n return {\n content: '',\n truncated: false,\n linesRead: 0,\n hasMoreLines: false,\n };\n }\n\n const encoding = options.encoding;\n // Accumulate raw bytes from the end: decoding a chunk ending mid-codepoint\n // corrupts the trailing UTF-8 sequence into U+FFFD. 0x0A is single-byte and\n // never part of a multibyte sequence, so count newlines on the raw buffer and\n // decode the whole bounded buffer once at the end.\n let position = fileSize;\n const chunks: Buffer[] = [];\n let totalLen = 0;\n let newlines = 0;\n let stoppedByLimit = false;\n\n while (position > 0) {\n options.signal?.throwIfAborted();\n const chunkSize = Math.min(position, STREAM_CHUNK_SIZE);\n const buffer = Buffer.allocUnsafe(chunkSize);\n const { bytesRead } = await handle.read(buffer, 0, chunkSize, position - chunkSize);\n if (bytesRead < chunkSize) {\n // The file shrank under us. Bytes from `position` on are still a\n // contiguous suffix, so keep those and stop — splicing this short chunk in\n // would leave a hole (and, with an alloc'd buffer, NULs) mid-content.\n // `position` stays put, so the result is reported as having more lines.\n break;\n }\n position -= chunkSize;\n\n for (const byte of buffer) {\n if (byte === 0x0a) newlines++;\n }\n\n chunks.unshift(buffer);\n totalLen += chunkSize;\n\n // One newline more than `tail`: the oldest segment in the buffer starts\n // mid-line whenever we stop before the file start, and gets dropped below.\n if (newlines > tail) break;\n if (totalLen > options.maxSize) {\n stoppedByLimit = true;\n break;\n }\n }\n\n const allBytes = Buffer.concat(chunks, totalLen);\n let lines = allBytes.toString(encoding).split('\\n');\n\n // A trailing newline produces a spurious empty final segment; drop it.\n if (lines.length > 0 && lines[lines.length - 1] === '') {\n lines = lines.slice(0, -1);\n }\n // Normalize CRLF.\n lines = lines.map((l) => (l.endsWith('\\r') ? l.slice(0, -1) : l));\n\n // We stopped before the file start, so the first segment is the tail of a\n // line whose beginning was never read. Drop it instead of reporting a\n // fragment as a complete line.\n if (position > 0 && lines.length > 0) {\n lines = lines.slice(1);\n }\n\n if (stoppedByLimit && lines.length < tail) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large (${totalLen} > ${options.maxSize} bytes, could not collect ${tail} lines). Use a narrower tail or head.`,\n filePath,\n { size: totalLen, maxSize: options.maxSize },\n );\n }\n\n let hasMoreLines = stoppedByLimit || position > 0;\n if (lines.length > tail) {\n hasMoreLines = true;\n lines = lines.slice(lines.length - tail);\n }\n\n const content = lines.join('\\n');\n return {\n content,\n truncated: hasMoreLines,\n linesRead: lines.length,\n hasMoreLines,\n };\n}\n\nasync function readFullContent(\n handle: FileHandle,\n encoding: BufferEncoding,\n maxSize: number,\n requestedPath: string,\n signal?: AbortSignal,\n): Promise<{ content: string; totalLines: number }> {\n const buffer = await readFileBufferWithLimit(handle, maxSize, requestedPath, signal);\n const content = buffer.toString(encoding);\n return { content, totalLines: countLines(content) };\n}\n\nasync function assertNotBinary(\n validPath: string,\n filePath: string,\n handle: FileHandle,\n normalized: NormalizedBase,\n): Promise<void> {\n normalized.signal?.throwIfAborted();\n const isBinary = await isProbablyBinary(validPath, handle, normalized.signal);\n if (!isBinary) return;\n throw new FsError(ErrorCode.INVALID_INPUT, 'Binary file detected.', filePath);\n}\n\nfunction assertSizeWithinLimit(size: number, maxSize: number, filePath: string): void {\n if (size <= maxSize) return;\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large (${size} > ${maxSize} bytes). Use head to preview.`,\n filePath,\n { size, maxSize },\n );\n}\n\ninterface ReadModeContext {\n handle: FileHandle;\n validPath: string;\n filePath: string;\n stats: Stats;\n spec: NormalizedSpec;\n}\n\nasync function readHead(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'head' }>,\n): Promise<ReadFileResult> {\n const contentOptions = buildReadContentOptions(spec);\n const { content, truncated, linesRead, hasMoreLines } = await readRangeContent(\n context.handle,\n 1,\n spec.lines,\n contentOptions,\n context.filePath,\n );\n\n return {\n path: context.validPath,\n content,\n truncated,\n readMode: 'head',\n head: spec.lines,\n linesRead,\n hasMoreLines,\n };\n}\n\nasync function readRange(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'range' }>,\n): Promise<ReadFileResult> {\n const contentOptions = buildReadContentOptions(spec);\n const { content, truncated, linesRead, hasMoreLines } = await readRangeContent(\n context.handle,\n spec.start,\n spec.end,\n contentOptions,\n context.filePath,\n );\n\n return {\n path: context.validPath,\n content,\n truncated,\n readMode: 'range',\n startLine: spec.start,\n ...(spec.end !== undefined ? { endLine: spec.end } : {}),\n linesRead,\n hasMoreLines,\n };\n}\n\nasync function readFull(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'full' }>,\n): Promise<ReadFileResult> {\n assertSizeWithinLimit(context.stats.size, spec.maxSize, context.filePath);\n const { content, totalLines } = await readFullContent(\n context.handle,\n spec.encoding,\n spec.maxSize,\n context.filePath,\n spec.signal,\n );\n\n return {\n path: context.validPath,\n content,\n truncated: false,\n totalLines,\n readMode: 'full',\n linesRead: totalLines,\n hasMoreLines: false,\n };\n}\n\nasync function readTail(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'tail' }>,\n): Promise<ReadFileResult> {\n const contentOptions = buildReadContentOptions(spec);\n const { content, truncated, linesRead, hasMoreLines } = await readTailContent(\n context.handle,\n spec.lines,\n contentOptions,\n context.validPath,\n );\n\n return {\n path: context.validPath,\n content,\n truncated,\n readMode: 'tail',\n tail: spec.lines,\n linesRead,\n hasMoreLines,\n };\n}\n\nasync function readByMode(context: ReadModeContext): Promise<ReadFileResult> {\n switch (context.spec.kind) {\n case 'head':\n return readHead(context, context.spec);\n case 'range':\n return readRange(context, context.spec);\n case 'full':\n return readFull(context, context.spec);\n case 'tail':\n return readTail(context, context.spec);\n default: {\n const _exhaustive: never = context.spec;\n return _exhaustive;\n }\n }\n}\n\nexport function assertFileStats(filePath: string, stats: Stats): void {\n if (!stats.isFile()) {\n throw new FsError(ErrorCode.NOT_FILE, 'Not a regular file', filePath);\n }\n}\n\nexport async function readNormalized(\n filePath: string,\n validPath: string,\n stats: Stats,\n spec: NormalizedSpec,\n): Promise<ReadFileResult> {\n spec.signal?.throwIfAborted();\n\n assertFileStats(filePath, stats);\n\n await using handle = await openReadableFileHandle(validPath, spec.signal);\n\n if (spec.skipBinary) {\n await assertNotBinary(validPath, filePath, handle, spec);\n }\n spec.signal?.throwIfAborted();\n\n return await readByMode({ handle, validPath, filePath, stats, spec });\n}\n\nexport async function readFileWithStats(\n filePath: string,\n validPath: string,\n stats: Stats,\n spec: ReadSpec | undefined,\n): Promise<ReadFileResult> {\n return readNormalized(filePath, validPath, stats, normalizeSpec(spec ?? { kind: 'full' }));\n}\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/core/read.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,yBAAyB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEpC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,SAAS,2BAA2B,CAAC,IAAY,EAAE,KAAc,EAAE,OAAgB;IACjF,IACE,KAAK,KAAK,SAAS;QACnB,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAExE,OAAO;IACT,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,OAAO,IAAI,GAAG,IAAI,6BAA6B,CAAC,CAAC;AAC9F,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,QAAgB,EAAE,MAAoB;IAC1E,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM;QAAE,OAAO,aAAa,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,KAAK,aAAa;aACf,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,QAAiB,EAAE,EAAE;gBAC9C,MAAM,CAAC,IAAI,CACT,mCAAmC,QAAQ,iBAAiB,yBAAyB,CAAC,QAAQ,CAAC,EAAE,CAClG,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,uBAAuB;QACzB,CAAC,CAAC,CAAC;QACL,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAkB,EAAE,MAAoB;IAC/D,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IACpD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAE3F,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,QAAgB,EAChB,cAA2B,EAC3B,MAAoB;;;QAEpB,IAAI,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;YACtD,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,MAAY,MAAM,kCAAG,MAAM,sBAAsB,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAA,CAAC;QACpE,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9C,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;;;;;;;;;;;CAC9B;AAsCD,SAAS,gBAAgB,CAAC,IAAc;IACtC,OAAO;QACL,OAAO,EAAE,kBAAkB,EAAE;QAC7B,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CACzB,IAA0C,EAC1C,IAAoB;IAEpB,2BAA2B,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;IAC7E,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC3B,2BAA2B,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QACvE,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,OAAO,CACf,SAAS,CAAC,aAAa,EACvB,yDAAyD,CAC1D,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO;QACL,GAAG,IAAI;QACP,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IAE9B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACT,2BAA2B,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;YAC7E,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QACzD,KAAK,OAAO;YACV,OAAO,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACnC,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,IAAI,CAAC;YAChC,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,OAAe,EACf,aAAqB;IAErB,OAAO,IAAI,OAAO,CAChB,SAAS,CAAC,SAAS,EACnB,4BAA4B,SAAS,MAAM,OAAO,SAAS,EAC3D,aAAa,CACd,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAkB,EAClB,OAAe,EACf,aAAqB,EACrB,MAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACrC,KAAK,EAAE,CAAC;QACR,aAAa,EAAE,iBAAiB;QAChC,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,KAAK;QAChB,MAAM;KACP,CAAC,CAAC;IAEH,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,KAAe,CAAC;YAC/B,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC;YAE3B,IAAI,SAAS,GAAG,OAAO,EAAE,CAAC;gBACxB,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,MAAM,mBAAmB,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;YAC/D,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAa,EAAE,EAAE;gBACnC,uCAAuC;YACzC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAe,EAAU,EAAE;IACpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACxE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AACpC,CAAC,CAAC;AAEF,KAAK,UAAU,WAAW,CAAC,QAA+B;IACxD,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2EAA2E;QAC3E,2EAA2E;QAC3E,0EAA0E;QAC1E,gDAAgD;QAChD,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QACxE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,EAAE,GAAG,IAAI,CAAC;AAEhB,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,SAAS,CAAC,CAAC,gBAAgB,CAC9B,MAAkB,EAClB,OAAuB,EACvB,QAAgB,EAChB,SAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACrC,KAAK,EAAE,CAAC;QACR,aAAa,EAAE,iBAAiB;QAChC,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,KAAK;QAChB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,MAAM,OAAO,GAAG,CAAC,KAAa,EAAW,EAAE,CACzC,IAAI,OAAO,CACT,SAAS,CAAC,SAAS,EACnB,+BAA+B,KAAK,MAAM,OAAO,CAAC,OAAO,wCAAwC,EACjG,QAAQ,CACT,CAAC;IAEJ,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,KAAe,CAAC;YAC/B,IAAI,MAAM,GAAG,CAAC,CAAC;YAEf,yEAAyE;YACzE,2EAA2E;YAC3E,8DAA8D;YAC9D,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YACpC,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAC5C,MAAM,SAAS,GAAG,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;gBAChD,UAAU,EAAE,CAAC;gBACb,4DAA4D;gBAC5D,2DAA2D;gBAC3D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvC,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;oBAC5B,IAAI,SAAS,GAAG,OAAO,CAAC,OAAO;wBAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;oBAC1D,MAAM,mBAAmB,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC;gBAC/C,CAAC;gBACD,OAAO,GAAG,EAAE,CAAC;gBACb,YAAY,GAAG,CAAC,CAAC;gBACjB,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC;gBAChB,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAClC,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACrC,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC;YAC5B,IAAI,UAAU,GAAG,CAAC,GAAG,SAAS,EAAE,CAAC;gBAC/B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,oDAAoD;YAC3E,CAAC;iBAAM,CAAC;gBACN,IAAI,YAAY,GAAG,OAAO,CAAC,OAAO;oBAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;gBAChE,OAAO,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,2DAA2D;QAC3D,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,UAAU,EAAE,CAAC;YACb,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;gBAC5B,IAAI,YAAY,GAAG,OAAO,CAAC,OAAO;oBAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;gBAChE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAa,EAAE,EAAE;gBACnC,uCAAuC;YACzC,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,MAAkB,EAClB,SAAiB,EACjB,OAA2B,EAC3B,OAAuB,EACvB,QAAgB;IAEhB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IAEjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,CAAC;IAC/B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,IAAI,MAAM,CAAC,iBAAiB,CAAC;IAEnD,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,yEAAyE;IACzE,yDAAyD;IACzD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;IAEhG,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACpD,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM;YACR,CAAC;YACD,UAAU,EAAE,CAAC;YAEb,IAAI,UAAU,GAAG,MAAM,EAAE,CAAC;gBACxB,YAAY,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR,CAAC;YAED,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEjB,cAAc,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,YAAY,CAAC;YAClE,IAAI,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;gBACrC,YAAY,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC3C,MAAM;YACR,CAAC;YAED,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;gBAC1B,YAAY,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC3C,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QACzB,SAAS,EAAE,KAAK,CAAC,MAAM;QACvB,YAAY;KACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,MAAkB,EAClB,IAAY,EACZ,OAAuB,EACvB,QAAgB;IAEhB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IAEjC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;IAC5B,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,CAAC;YACZ,YAAY,EAAE,KAAK;SACpB,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC;IACzB,2EAA2E;IAC3E,4EAA4E;IAC5E,8EAA8E;IAC9E,mDAAmD;IACnD,IAAI,QAAQ,GAAG,QAAQ,CAAC;IACxB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,OAAO,QAAQ,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;QACpF,IAAI,SAAS,GAAG,SAAS,EAAE,CAAC;YAC1B,iEAAiE;YACjE,2EAA2E;YAC3E,sEAAsE;YACtE,wEAAwE;YACxE,MAAM;QACR,CAAC;QACD,QAAQ,IAAI,SAAS,CAAC;QAEtB,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,IAAI,IAAI,KAAK,IAAI;gBAAE,QAAQ,EAAE,CAAC;QAChC,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvB,QAAQ,IAAI,SAAS,CAAC;QAEtB,wEAAwE;QACxE,2EAA2E;QAC3E,IAAI,QAAQ,GAAG,IAAI;YAAE,MAAM;QAC3B,IAAI,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;YAC/B,cAAc,GAAG,IAAI,CAAC;YACtB,MAAM;QACR,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpD,uEAAuE;IACvE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACvD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,kBAAkB;IAClB,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAElE,0EAA0E;IAC1E,sEAAsE;IACtE,+BAA+B;IAC/B,IAAI,QAAQ,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QAC1C,MAAM,IAAI,OAAO,CACf,SAAS,CAAC,SAAS,EACnB,mBAAmB,QAAQ,MAAM,OAAO,CAAC,OAAO,6BAA6B,IAAI,uCAAuC,EACxH,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,GAAG,cAAc,IAAI,QAAQ,GAAG,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACxB,YAAY,GAAG,IAAI,CAAC;QACpB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO;QACL,OAAO;QACP,SAAS,EAAE,KAAK,CAAC,MAAM;QACvB,YAAY;KACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,MAAkB,EAClB,OAAe,EACf,aAAqB,EACrB,MAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACrF,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,SAAiB,EACjB,QAAgB,EAChB,MAAkB,EAClB,UAA0B;IAE1B,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC9E,IAAI,CAAC,QAAQ;QAAE,OAAO;IACtB,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,OAAe,EAAE,QAAgB;IAC5E,IAAI,IAAI,IAAI,OAAO;QAAE,OAAO;IAC5B,MAAM,IAAI,OAAO,CACf,SAAS,CAAC,SAAS,EACnB,mBAAmB,IAAI,MAAM,OAAO,+BAA+B,EACnE,QAAQ,CACT,CAAC;AACJ,CAAC;AAUD,KAAK,UAAU,QAAQ,CACrB,OAAwB,EACxB,IAA+C;IAE/C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,gBAAgB,CACjE,OAAO,CAAC,MAAM,EACd,CAAC,EACD,IAAI,CAAC,KAAK,EACV,IAAI,EACJ,OAAO,CAAC,QAAQ,CACjB,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,SAAS;QACvB,OAAO;QACP,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,IAAI,CAAC,KAAK;QAChB,SAAS;QACT,YAAY;KACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,OAAwB,EACxB,IAAgD;IAEhD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,gBAAgB,CACjE,OAAO,CAAC,MAAM,EACd,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,GAAG,EACR,IAAI,EACJ,OAAO,CAAC,QAAQ,CACjB,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,SAAS;QACvB,OAAO;QACP,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,SAAS;QACT,YAAY;KACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,OAAwB,EACxB,IAA+C;IAE/C,qBAAqB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1E,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,eAAe,CACnD,OAAO,CAAC,MAAM,EACd,IAAI,CAAC,OAAO,EACZ,OAAO,CAAC,QAAQ,EAChB,IAAI,CAAC,MAAM,CACZ,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,SAAS;QACvB,OAAO;QACP,UAAU;QACV,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,KAAK;KACpB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,OAAwB,EACxB,IAA+C;IAE/C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,eAAe,CAChE,OAAO,CAAC,MAAM,EACd,IAAI,CAAC,KAAK,EACV,IAAI,EACJ,OAAO,CAAC,SAAS,CAClB,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,SAAS;QACvB,OAAO;QACP,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,IAAI,CAAC,KAAK;QAChB,SAAS;QACT,YAAY;KACb,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAwB;IAChD,QAAQ,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,KAAK,MAAM;YACT,OAAO,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,KAAK,OAAO;YACV,OAAO,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1C,KAAK,MAAM;YACT,OAAO,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,KAAK,MAAM;YACT,OAAO,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,OAAO,CAAC,IAAI,CAAC;YACxC,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,KAAY;IAC5D,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,oBAAoB,EAAE,QAAQ,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,SAAiB,EACjB,KAAY,EACZ,IAAoB;;;QAEpB,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QAE9B,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAEjC,MAAY,MAAM,kCAAG,MAAM,sBAAsB,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,OAAA,CAAC;QAE1E,MAAM,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QAE9B,OAAO,MAAM,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;;;;;;;;;;;CACvE;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB,EAChB,SAAiB,EACjB,KAAY,EACZ,IAA0B;IAE1B,OAAO,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAC7F,CAAC","sourcesContent":["// File reading pipeline split out of fs.ts. fs.ts imports from here; never the reverse.\nimport type { Stats } from 'node:fs';\nimport { open as fsOpen } from 'node:fs/promises';\nimport type { FileHandle } from 'node:fs/promises';\nimport { StringDecoder } from 'node:string_decoder';\n\nimport { withAbort } from './concurrency.js';\nimport { ErrorCode, formatUnknownErrorMessage, FsError, isFsError } from './errors.js';\nimport { isBinarySample, isKnownBinaryExtension, MIME_SAMPLE_SIZE } from './mime.js';\nimport { Logger } from './observability.js';\nimport { getMaxTextFileSize } from './util.js';\n\nconst STREAM_CHUNK_SIZE = 64 * 1024;\n\nconst READ_ONLY_FILE_FLAG = 'r';\n\nfunction assertPositiveIntegerOption(name: string, value: unknown, message?: string): void {\n if (\n value === undefined ||\n (typeof value === 'number' && Number.isSafeInteger(value) && value >= 1)\n )\n return;\n throw new FsError(ErrorCode.INVALID_INPUT, message ?? `${name} must be a positive integer`);\n}\n\nasync function openReadableFileHandle(filePath: string, signal?: AbortSignal): Promise<FileHandle> {\n const handlePromise = fsOpen(filePath, READ_ONLY_FILE_FLAG);\n if (!signal) return handlePromise;\n try {\n return await withAbort(handlePromise, signal);\n } catch (error) {\n void handlePromise\n .then((handle) => {\n void handle.close().catch((closeErr: unknown) => {\n Logger.warn(\n `Failed to close file handle for ${filePath} after abort: ${formatUnknownErrorMessage(closeErr)}`,\n );\n });\n })\n .catch(() => {\n /* ignore open error */\n });\n throw error;\n }\n}\n\nasync function readProbe(handle: FileHandle, signal?: AbortSignal): Promise<Buffer> {\n const buffer = Buffer.allocUnsafe(MIME_SAMPLE_SIZE);\n const { bytesRead } = await withAbort(handle.read(buffer, 0, MIME_SAMPLE_SIZE, 0), signal);\n\n if (bytesRead === 0) {\n return Buffer.alloc(0);\n }\n\n return buffer.subarray(0, bytesRead);\n}\n\nasync function isProbablyBinary(\n filePath: string,\n existingHandle?: FileHandle,\n signal?: AbortSignal,\n): Promise<boolean> {\n if (isKnownBinaryExtension(filePath)) {\n return true;\n }\n\n if (existingHandle) {\n const slice = await readProbe(existingHandle, signal);\n return isBinarySample(slice);\n }\n\n await using handle = await openReadableFileHandle(filePath, signal);\n const slice = await readProbe(handle, signal);\n return isBinarySample(slice);\n}\n\nexport type ReadSpec =\n | { kind: 'full'; signal?: AbortSignal }\n | { kind: 'head'; lines: number; signal?: AbortSignal }\n | { kind: 'tail'; lines: number; signal?: AbortSignal }\n | { kind: 'range'; start: number; end?: number; signal?: AbortSignal };\n\ninterface NormalizedBase {\n maxSize: number;\n signal?: AbortSignal;\n}\n\ntype NormalizedSpec =\n | (NormalizedBase & { kind: 'full' })\n | (NormalizedBase & { kind: 'head'; lines: number })\n | (NormalizedBase & { kind: 'tail'; lines: number })\n | (NormalizedBase & { kind: 'range'; start: number; end?: number });\n\ninterface PartialReadResult {\n content: string;\n linesRead: number;\n hasMoreLines: boolean;\n}\n\nexport interface ReadFileResult {\n path: string;\n content: string;\n totalLines?: number;\n readMode: ReadSpec['kind'];\n head?: number;\n tail?: number;\n startLine?: number;\n endLine?: number;\n linesRead?: number;\n hasMoreLines?: boolean;\n}\n\nfunction buildBaseOptions(spec: ReadSpec): NormalizedBase {\n return {\n maxSize: getMaxTextFileSize(),\n ...(spec.signal ? { signal: spec.signal } : {}),\n };\n}\n\nfunction normalizeRangeSpec(\n spec: Extract<ReadSpec, { kind: 'range' }>,\n base: NormalizedBase,\n): NormalizedSpec {\n assertPositiveIntegerOption('start', spec.start, 'start must be at least 1');\n if (spec.end !== undefined) {\n assertPositiveIntegerOption('end', spec.end, 'end must be at least 1');\n if (spec.end < spec.start) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n 'end must be greater than or equal to start (default: 1)',\n );\n }\n }\n return {\n ...base,\n kind: 'range',\n start: spec.start,\n ...(spec.end !== undefined ? { end: spec.end } : {}),\n };\n}\n\nexport function normalizeSpec(spec: ReadSpec): NormalizedSpec {\n const base = buildBaseOptions(spec);\n spec.signal?.throwIfAborted();\n\n switch (spec.kind) {\n case 'head':\n case 'tail':\n assertPositiveIntegerOption('lines', spec.lines, 'lines must be at least 1');\n return { ...base, kind: spec.kind, lines: spec.lines };\n case 'range':\n return normalizeRangeSpec(spec, base);\n case 'full':\n return { ...base, kind: 'full' };\n default: {\n const _exhaustive: never = spec;\n return _exhaustive;\n }\n }\n}\n\nexport function createTooLargeError(\n bytesRead: number,\n maxSize: number,\n requestedPath: string,\n): FsError {\n return new FsError(\n ErrorCode.TOO_LARGE,\n `File exceeds size limit (${bytesRead} > ${maxSize} bytes)`,\n requestedPath,\n );\n}\n\nexport async function readFileBufferWithLimit(\n handle: FileHandle,\n maxSize: number,\n requestedPath: string,\n signal?: AbortSignal,\n): Promise<Buffer> {\n const stream = handle.createReadStream({\n start: 0,\n highWaterMark: STREAM_CHUNK_SIZE,\n autoClose: false,\n emitClose: false,\n signal,\n });\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n\n try {\n for await (const chunk of stream) {\n const buffer = chunk as Buffer;\n totalSize += buffer.length;\n\n if (totalSize > maxSize) {\n stream.destroy();\n throw createTooLargeError(totalSize, maxSize, requestedPath);\n }\n\n chunks.push(buffer);\n }\n } finally {\n if (!stream.destroyed) {\n stream.on('error', (_err: unknown) => {\n /* suppress post-destroy error event */\n });\n stream.destroy();\n }\n }\n\n return Buffer.concat(chunks, totalSize);\n}\n\nexport const countLines = (content: string): number => {\n if (content.length === 0) return 0;\n const trimmed = content.endsWith('\\n') ? content.slice(0, -1) : content;\n return trimmed.split('\\n').length;\n};\n\nasync function peekHasMore(iterator: AsyncIterator<string>): Promise<boolean> {\n try {\n const { done } = await iterator.next();\n return !done;\n } catch (error) {\n // The peek only asks \"is there another line\", and the caller keeps nothing\n // it returns. An over-long line past the requested range still answers yes\n // — failing the whole read over a line outside it would reject e.g. lines\n // 1-2 of a file whose line 3 is one 50 KB blob.\n if (isFsError(error) && error.code === ErrorCode.TOO_LARGE) return true;\n throw error;\n }\n}\n\nconst LF = 0x0a;\n\nfunction stripCarriageReturn(line: string): string {\n return line.endsWith('\\r') ? line.slice(0, -1) : line;\n}\n\n/**\n * Line iterator bounded by bytes rather than by the decoded string, so a file\n * that is one enormous line cannot be materialized before the size check runs.\n * `handle.readLines` decodes the whole line first and can OOM on such a file.\n *\n * Yields lines from `startLine` onward, 1-indexed. Lines before `startLine` are\n * counted and discarded without accumulating, so an over-long line the caller\n * skipped past does not fail the read. Line endings match `readLines`: split on\n * `\\n`, with a preceding `\\r` stripped, so CRLF input decodes identically.\n */\nasync function* readLinesBounded(\n handle: FileHandle,\n options: NormalizedBase,\n filePath: string,\n startLine: number,\n): AsyncGenerator<string, void, undefined> {\n const stream = handle.createReadStream({\n start: 0,\n highWaterMark: STREAM_CHUNK_SIZE,\n autoClose: false,\n emitClose: false,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n\n const decoder = new StringDecoder('utf-8');\n let pending = '';\n let pendingBytes = 0;\n let lineNumber = 0;\n\n const tooLong = (bytes: number): FsError =>\n new FsError(\n ErrorCode.TOO_LARGE,\n `File too large (single line ${bytes} > ${options.maxSize} bytes). Use a narrower range or head.`,\n filePath,\n );\n\n try {\n for await (const chunk of stream) {\n const buffer = chunk as Buffer;\n let offset = 0;\n\n // Search loop: each iteration finds the next LF and advances offset past\n // it. Written as while-with-assignment so the re-search is visible, rather\n // than buried in a for \"increment\" slot that re-runs indexOf.\n let nl = buffer.indexOf(LF, offset);\n while (nl !== -1) {\n const segment = buffer.subarray(offset, nl);\n const lineBytes = pendingBytes + segment.length;\n lineNumber++;\n // Decode even when skipping: the decoder carries multi-byte\n // continuation state into the first line the caller keeps.\n const decoded = decoder.write(segment);\n if (lineNumber >= startLine) {\n if (lineBytes > options.maxSize) throw tooLong(lineBytes);\n yield stripCarriageReturn(pending + decoded);\n }\n pending = '';\n pendingBytes = 0;\n offset = nl + 1;\n nl = buffer.indexOf(LF, offset);\n }\n\n const rest = buffer.subarray(offset);\n pendingBytes += rest.length;\n if (lineNumber + 1 < startLine) {\n decoder.write(rest); // still skipping; drop the text, keep decoder state\n } else {\n if (pendingBytes > options.maxSize) throw tooLong(pendingBytes);\n pending += decoder.write(rest);\n }\n }\n\n // Trailing line with no final newline. A file ending in `\\n` leaves\n // pendingBytes at 0 and emits nothing, matching readLines.\n if (pendingBytes > 0) {\n lineNumber++;\n if (lineNumber >= startLine) {\n if (pendingBytes > options.maxSize) throw tooLong(pendingBytes);\n yield pending + decoder.end();\n }\n }\n } finally {\n if (!stream.destroyed) {\n stream.on('error', (_err: unknown) => {\n /* suppress post-destroy error event */\n });\n stream.destroy();\n }\n }\n}\n\nasync function readRangeContent(\n handle: FileHandle,\n startLine: number,\n endLine: number | undefined,\n options: NormalizedBase,\n filePath: string,\n): Promise<PartialReadResult> {\n options.signal?.throwIfAborted();\n\n const lines: string[] = [];\n let lineNumber = startLine - 1;\n let estimatedBytes = 0;\n const newlineBytes = Buffer.byteLength('\\n', 'utf-8');\n const stopAt = endLine ?? Number.POSITIVE_INFINITY;\n\n let hasMoreLines = false;\n\n // Byte-bounded: an over-long line throws TOO_LARGE while still a partial\n // buffer, before it can be decoded into one huge string.\n const iterator = readLinesBounded(handle, options, filePath, startLine)[Symbol.asyncIterator]();\n\n try {\n for (;;) {\n const { value: line, done } = await iterator.next();\n if (done) {\n break;\n }\n lineNumber++;\n\n if (lineNumber > stopAt) {\n hasMoreLines = true;\n break;\n }\n\n lines.push(line);\n\n estimatedBytes += Buffer.byteLength(line, 'utf-8') + newlineBytes;\n if (estimatedBytes > options.maxSize) {\n hasMoreLines = await peekHasMore(iterator);\n break;\n }\n\n if (lineNumber === stopAt) {\n hasMoreLines = await peekHasMore(iterator);\n break;\n }\n }\n } finally {\n await iterator.return();\n }\n\n return {\n content: lines.join('\\n'),\n linesRead: lines.length,\n hasMoreLines,\n };\n}\n\nasync function readTailContent(\n handle: FileHandle,\n tail: number,\n options: NormalizedBase,\n filePath: string,\n): Promise<PartialReadResult> {\n options.signal?.throwIfAborted();\n\n const stats = await handle.stat();\n const fileSize = stats.size;\n if (fileSize === 0) {\n return {\n content: '',\n linesRead: 0,\n hasMoreLines: false,\n };\n }\n\n const encoding = 'utf-8';\n // Accumulate raw bytes from the end: decoding a chunk ending mid-codepoint\n // corrupts the trailing UTF-8 sequence into U+FFFD. 0x0A is single-byte and\n // never part of a multibyte sequence, so count newlines on the raw buffer and\n // decode the whole bounded buffer once at the end.\n let position = fileSize;\n const chunks: Buffer[] = [];\n let totalLen = 0;\n let newlines = 0;\n let stoppedByLimit = false;\n\n while (position > 0) {\n options.signal?.throwIfAborted();\n const chunkSize = Math.min(position, STREAM_CHUNK_SIZE);\n const buffer = Buffer.allocUnsafe(chunkSize);\n const { bytesRead } = await handle.read(buffer, 0, chunkSize, position - chunkSize);\n if (bytesRead < chunkSize) {\n // The file shrank under us. Bytes from `position` on are still a\n // contiguous suffix, so keep those and stop — splicing this short chunk in\n // would leave a hole (and, with an alloc'd buffer, NULs) mid-content.\n // `position` stays put, so the result is reported as having more lines.\n break;\n }\n position -= chunkSize;\n\n for (const byte of buffer) {\n if (byte === 0x0a) newlines++;\n }\n\n chunks.unshift(buffer);\n totalLen += chunkSize;\n\n // One newline more than `tail`: the oldest segment in the buffer starts\n // mid-line whenever we stop before the file start, and gets dropped below.\n if (newlines > tail) break;\n if (totalLen > options.maxSize) {\n stoppedByLimit = true;\n break;\n }\n }\n\n const allBytes = Buffer.concat(chunks, totalLen);\n let lines = allBytes.toString(encoding).split('\\n');\n\n // A trailing newline produces a spurious empty final segment; drop it.\n if (lines.length > 0 && lines[lines.length - 1] === '') {\n lines = lines.slice(0, -1);\n }\n // Normalize CRLF.\n lines = lines.map((l) => (l.endsWith('\\r') ? l.slice(0, -1) : l));\n\n // We stopped before the file start, so the first segment is the tail of a\n // line whose beginning was never read. Drop it instead of reporting a\n // fragment as a complete line.\n if (position > 0 && lines.length > 0) {\n lines = lines.slice(1);\n }\n\n if (stoppedByLimit && lines.length < tail) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large (${totalLen} > ${options.maxSize} bytes, could not collect ${tail} lines). Use a narrower tail or head.`,\n filePath,\n );\n }\n\n let hasMoreLines = stoppedByLimit || position > 0;\n if (lines.length > tail) {\n hasMoreLines = true;\n lines = lines.slice(lines.length - tail);\n }\n\n const content = lines.join('\\n');\n return {\n content,\n linesRead: lines.length,\n hasMoreLines,\n };\n}\n\nasync function readFullContent(\n handle: FileHandle,\n maxSize: number,\n requestedPath: string,\n signal?: AbortSignal,\n): Promise<{ content: string; totalLines: number }> {\n const buffer = await readFileBufferWithLimit(handle, maxSize, requestedPath, signal);\n const content = buffer.toString('utf-8');\n return { content, totalLines: countLines(content) };\n}\n\nasync function assertNotBinary(\n validPath: string,\n filePath: string,\n handle: FileHandle,\n normalized: NormalizedBase,\n): Promise<void> {\n normalized.signal?.throwIfAborted();\n const isBinary = await isProbablyBinary(validPath, handle, normalized.signal);\n if (!isBinary) return;\n throw new FsError(ErrorCode.INVALID_INPUT, 'Binary file detected.', filePath);\n}\n\nfunction assertSizeWithinLimit(size: number, maxSize: number, filePath: string): void {\n if (size <= maxSize) return;\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large (${size} > ${maxSize} bytes). Use head to preview.`,\n filePath,\n );\n}\n\ninterface ReadModeContext {\n handle: FileHandle;\n validPath: string;\n filePath: string;\n stats: Stats;\n spec: NormalizedSpec;\n}\n\nasync function readHead(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'head' }>,\n): Promise<ReadFileResult> {\n const { content, linesRead, hasMoreLines } = await readRangeContent(\n context.handle,\n 1,\n spec.lines,\n spec,\n context.filePath,\n );\n\n return {\n path: context.validPath,\n content,\n readMode: 'head',\n head: spec.lines,\n linesRead,\n hasMoreLines,\n };\n}\n\nasync function readRange(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'range' }>,\n): Promise<ReadFileResult> {\n const { content, linesRead, hasMoreLines } = await readRangeContent(\n context.handle,\n spec.start,\n spec.end,\n spec,\n context.filePath,\n );\n\n return {\n path: context.validPath,\n content,\n readMode: 'range',\n startLine: spec.start,\n ...(spec.end !== undefined ? { endLine: spec.end } : {}),\n linesRead,\n hasMoreLines,\n };\n}\n\nasync function readFull(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'full' }>,\n): Promise<ReadFileResult> {\n assertSizeWithinLimit(context.stats.size, spec.maxSize, context.filePath);\n const { content, totalLines } = await readFullContent(\n context.handle,\n spec.maxSize,\n context.filePath,\n spec.signal,\n );\n\n return {\n path: context.validPath,\n content,\n totalLines,\n readMode: 'full',\n linesRead: totalLines,\n hasMoreLines: false,\n };\n}\n\nasync function readTail(\n context: ReadModeContext,\n spec: Extract<NormalizedSpec, { kind: 'tail' }>,\n): Promise<ReadFileResult> {\n const { content, linesRead, hasMoreLines } = await readTailContent(\n context.handle,\n spec.lines,\n spec,\n context.validPath,\n );\n\n return {\n path: context.validPath,\n content,\n readMode: 'tail',\n tail: spec.lines,\n linesRead,\n hasMoreLines,\n };\n}\n\nasync function readByMode(context: ReadModeContext): Promise<ReadFileResult> {\n switch (context.spec.kind) {\n case 'head':\n return readHead(context, context.spec);\n case 'range':\n return readRange(context, context.spec);\n case 'full':\n return readFull(context, context.spec);\n case 'tail':\n return readTail(context, context.spec);\n default: {\n const _exhaustive: never = context.spec;\n return _exhaustive;\n }\n }\n}\n\nexport function assertFileStats(filePath: string, stats: Stats): void {\n if (!stats.isFile()) {\n throw new FsError(ErrorCode.NOT_FILE, 'Not a regular file', filePath);\n }\n}\n\nexport async function readNormalized(\n filePath: string,\n validPath: string,\n stats: Stats,\n spec: NormalizedSpec,\n): Promise<ReadFileResult> {\n spec.signal?.throwIfAborted();\n\n assertFileStats(filePath, stats);\n\n await using handle = await openReadableFileHandle(validPath, spec.signal);\n\n await assertNotBinary(validPath, filePath, handle, spec);\n spec.signal?.throwIfAborted();\n\n return await readByMode({ handle, validPath, filePath, stats, spec });\n}\n\nexport async function readFileWithStats(\n filePath: string,\n validPath: string,\n stats: Stats,\n spec: ReadSpec | undefined,\n): Promise<ReadFileResult> {\n return readNormalized(filePath, validPath, stats, normalizeSpec(spec ?? { kind: 'full' }));\n}\n"]}
@@ -64,34 +64,6 @@ export declare const PathFailureSchema: z.ZodObject<{
64
64
  suggestion: z.ZodOptional<z.ZodString>;
65
65
  }, z.core.$strict>;
66
66
  }, z.core.$strict>;
67
- /**
68
- * One entry of a source→destination tool's `failures[]`. The verb and noun stay
69
- * per-op so the `.describe()` text reads correctly for each caller.
70
- */
71
- export declare function pairFailureSchema(verb: 'copied' | 'moved', noun: 'copy' | 'move'): z.ZodObject<{
72
- source: z.ZodString;
73
- destination: z.ZodString;
74
- error: z.ZodObject<{
75
- code: z.ZodString;
76
- message: z.ZodString;
77
- path: z.ZodOptional<z.ZodString>;
78
- suggestion: z.ZodOptional<z.ZodString>;
79
- }, z.core.$strict>;
80
- }, z.core.$strict>;
81
- /** Wire shape of a `pairFailureSchema` entry — the runtime twin of the schema. */
82
- export type PairFailureItem = z.infer<ReturnType<typeof pairFailureSchema>>;
83
- interface ReadRangeDescriptions {
84
- head: string;
85
- tail: string;
86
- startLine: string;
87
- endLine: string;
88
- }
89
- export declare function createReadRangeFields(descs: ReadRangeDescriptions): {
90
- head: z.ZodOptional<z.ZodInt32>;
91
- tail: z.ZodOptional<z.ZodInt32>;
92
- startLine: z.ZodOptional<z.ZodInt32>;
93
- endLine: z.ZodOptional<z.ZodInt32>;
94
- };
95
67
  export declare function validateReadRange(value: {
96
68
  head?: number | undefined;
97
69
  tail?: number | undefined;
@@ -106,10 +78,7 @@ export type SingleOrBatchShape<TExtra extends z.ZodRawShape> = TExtra & {
106
78
  path: z.ZodOptional<typeof RequiredPath>;
107
79
  paths: z.ZodOptional<z.ZodArray<typeof RequiredPath>>;
108
80
  };
109
- export declare function singleOrBatchPathsInput<TExtra extends z.ZodRawShape>(opts: {
110
- extra: TExtra;
111
- maxBatch?: number;
112
- }): z.ZodObject<SingleOrBatchShape<TExtra>>;
81
+ export declare function singleOrBatchPathsInput<TExtra extends z.ZodRawShape>(extra: TExtra): z.ZodObject<SingleOrBatchShape<TExtra>>;
113
82
  /**
114
83
  * Extract the filesystem paths from a {@link singleOrBatchPathsInput} shape
115
84
  * (`{ path?, paths?, files?[{path}] }`) for the executor's access-grant
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"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"}
@@ -157,45 +157,6 @@ export const PathFailureSchema = z.strictObject({
157
157
  path: z.string(),
158
158
  error: PerFileErrorSchema,
159
159
  });
160
- /**
161
- * One entry of a source→destination tool's `failures[]`. The verb and noun stay
162
- * per-op so the `.describe()` text reads correctly for each caller.
163
- */
164
- export function pairFailureSchema(verb, noun) {
165
- return z.strictObject({
166
- source: z.string().describe(`Source path that could not be ${verb}`),
167
- destination: z.string().describe(`Intended destination path for the failed ${noun}`),
168
- error: PerFileErrorSchema,
169
- });
170
- }
171
- export function createReadRangeFields(descs) {
172
- return {
173
- head: z
174
- .int32()
175
- .min(1, { message: 'Min: 1' })
176
- .max(100000, { message: 'Max: 100,000' })
177
- .optional()
178
- .describe(descs.head),
179
- tail: z
180
- .int32()
181
- .min(1, { message: 'Min: 1' })
182
- .max(100000, { message: 'Max: 100,000' })
183
- .optional()
184
- .describe(descs.tail),
185
- startLine: z
186
- .int32()
187
- .min(1, { message: 'Min: 1' })
188
- .max(100000, { message: 'Max: 100,000' })
189
- .optional()
190
- .describe(descs.startLine),
191
- endLine: z
192
- .int32()
193
- .min(1, { message: 'Min: 1' })
194
- .max(100000, { message: 'Max: 100,000' })
195
- .optional()
196
- .describe(descs.endLine),
197
- };
198
- }
199
160
  export function validateReadRange(value, ctx) {
200
161
  const hasHead = value.head !== undefined;
201
162
  const hasTail = value.tail !== undefined;
@@ -205,12 +166,7 @@ export function validateReadRange(value, ctx) {
205
166
  ctx.addIssue({
206
167
  code: 'custom',
207
168
  path: ['head'],
208
- message: "Cannot use 'head' with 'startLine'/'endLine'",
209
- params: {
210
- rule: 'head_no_line_range',
211
- conflictsWith: ['startLine', 'endLine'],
212
- suggestion: "Use either 'head' alone or 'startLine'/'endLine' together.",
213
- },
169
+ message: "Cannot use 'head' with 'startLine'/'endLine'. Use either 'head' alone or 'startLine'/'endLine' together.",
214
170
  input: value,
215
171
  });
216
172
  }
@@ -218,12 +174,7 @@ export function validateReadRange(value, ctx) {
218
174
  ctx.addIssue({
219
175
  code: 'custom',
220
176
  path: ['tail'],
221
- message: "Cannot use 'tail' with 'head'/'startLine'/'endLine'",
222
- params: {
223
- rule: 'tail_exclusive',
224
- conflictsWith: ['head', 'startLine', 'endLine'],
225
- suggestion: "Use 'tail' alone or use 'startLine'/'endLine' without 'tail'.",
226
- },
177
+ message: "Cannot use 'tail' with 'head'/'startLine'/'endLine'. Use 'tail' alone, or 'startLine'/'endLine' without 'tail'.",
227
178
  input: value,
228
179
  });
229
180
  }
@@ -231,11 +182,7 @@ export function validateReadRange(value, ctx) {
231
182
  ctx.addIssue({
232
183
  code: 'custom',
233
184
  path: ['endLine'],
234
- message: "'endLine' requires 'startLine' to be set",
235
- params: {
236
- rule: 'endLine_requires_startLine',
237
- suggestion: "Provide both 'startLine' and 'endLine' together.",
238
- },
185
+ message: "'endLine' requires 'startLine' to be set. Provide both together.",
239
186
  input: value,
240
187
  });
241
188
  }
@@ -245,11 +192,6 @@ export function validateReadRange(value, ctx) {
245
192
  code: 'custom',
246
193
  path: ['endLine'],
247
194
  message: "'endLine' must be >= 'startLine'",
248
- params: {
249
- rule: 'endLine_gte_startLine',
250
- conflictsWith: ['startLine'],
251
- suggestion: 'Set endLine to a value greater than or equal to startLine.',
252
- },
253
195
  input: value,
254
196
  });
255
197
  }
@@ -266,17 +208,16 @@ export const maxDepthField = () => z
266
208
  .optional()
267
209
  .describe('Max directory depth to scan; 0 = base directory only, omit for unlimited');
268
210
  const DEFAULT_MAX_BATCH = 1000;
269
- export function singleOrBatchPathsInput(opts) {
270
- const maxBatch = opts.maxBatch ?? DEFAULT_MAX_BATCH;
211
+ export function singleOrBatchPathsInput(extra) {
271
212
  const shape = {
272
- ...opts.extra,
213
+ ...extra,
273
214
  path: RequiredPath.optional().describe('Single file path; mutually exclusive with paths'),
274
215
  paths: z
275
216
  .array(RequiredPath)
276
217
  .min(1)
277
- .max(maxBatch)
218
+ .max(DEFAULT_MAX_BATCH)
278
219
  .optional()
279
- .describe(`Array of file paths for batch mode (max ${String(maxBatch)}); mutually exclusive with path`),
220
+ .describe(`Array of file paths for batch mode (max ${String(DEFAULT_MAX_BATCH)}); mutually exclusive with path`),
280
221
  };
281
222
  const base = z.strictObject(shape).superRefine((value, ctx) => {
282
223
  const hasPath = value['path'] !== undefined;