@j0hanz/filesystem-mcp 2.6.3 → 2.7.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 (148) hide show
  1. package/README.md +28 -19
  2. package/dist/cli-help.d.ts.map +1 -1
  3. package/dist/cli-help.js +5 -2
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +22 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/concurrency.d.ts +0 -17
  9. package/dist/core/concurrency.d.ts.map +1 -1
  10. package/dist/core/concurrency.js +53 -47
  11. package/dist/core/concurrency.js.map +1 -1
  12. package/dist/core/config.d.ts +7 -0
  13. package/dist/core/config.d.ts.map +1 -1
  14. package/dist/core/config.js +7 -0
  15. package/dist/core/config.js.map +1 -1
  16. package/dist/core/diff.d.ts +0 -4
  17. package/dist/core/diff.d.ts.map +1 -1
  18. package/dist/core/diff.js +1 -15
  19. package/dist/core/diff.js.map +1 -1
  20. package/dist/core/file-uri.d.ts +9 -9
  21. package/dist/core/file-uri.d.ts.map +1 -1
  22. package/dist/core/file-uri.js +16 -11
  23. package/dist/core/file-uri.js.map +1 -1
  24. package/dist/core/fs.d.ts +1 -1
  25. package/dist/core/fs.d.ts.map +1 -1
  26. package/dist/core/fs.js +65 -56
  27. package/dist/core/fs.js.map +1 -1
  28. package/dist/core/glob.d.ts +6 -0
  29. package/dist/core/glob.d.ts.map +1 -1
  30. package/dist/core/glob.js +80 -13
  31. package/dist/core/glob.js.map +1 -1
  32. package/dist/core/input-required.d.ts +30 -13
  33. package/dist/core/input-required.d.ts.map +1 -1
  34. package/dist/core/input-required.js +35 -10
  35. package/dist/core/input-required.js.map +1 -1
  36. package/dist/core/mime.d.ts +2 -4
  37. package/dist/core/mime.d.ts.map +1 -1
  38. package/dist/core/mime.js +3 -8
  39. package/dist/core/mime.js.map +1 -1
  40. package/dist/core/path-completer.d.ts.map +1 -1
  41. package/dist/core/path-completer.js +7 -4
  42. package/dist/core/path-completer.js.map +1 -1
  43. package/dist/core/path-discovery.d.ts.map +1 -1
  44. package/dist/core/path-discovery.js +2 -2
  45. package/dist/core/path-discovery.js.map +1 -1
  46. package/dist/core/path-utils.d.ts +1 -3
  47. package/dist/core/path-utils.d.ts.map +1 -1
  48. package/dist/core/path-utils.js +0 -3
  49. package/dist/core/path-utils.js.map +1 -1
  50. package/dist/core/path.d.ts +7 -0
  51. package/dist/core/path.d.ts.map +1 -1
  52. package/dist/core/path.js +69 -26
  53. package/dist/core/path.js.map +1 -1
  54. package/dist/core/read.d.ts +1 -0
  55. package/dist/core/read.d.ts.map +1 -1
  56. package/dist/core/read.js +4 -0
  57. package/dist/core/read.js.map +1 -1
  58. package/dist/core/schema.d.ts +0 -80
  59. package/dist/core/schema.d.ts.map +1 -1
  60. package/dist/core/schema.js +0 -89
  61. package/dist/core/schema.js.map +1 -1
  62. package/dist/core/search.d.ts +8 -1
  63. package/dist/core/search.d.ts.map +1 -1
  64. package/dist/core/search.js +191 -101
  65. package/dist/core/search.js.map +1 -1
  66. package/dist/core/store.d.ts +7 -11
  67. package/dist/core/store.d.ts.map +1 -1
  68. package/dist/core/store.js +19 -21
  69. package/dist/core/store.js.map +1 -1
  70. package/dist/core/util.d.ts +17 -0
  71. package/dist/core/util.d.ts.map +1 -1
  72. package/dist/core/util.js +19 -0
  73. package/dist/core/util.js.map +1 -1
  74. package/dist/instructions.js +1 -1
  75. package/dist/instructions.js.map +1 -1
  76. package/dist/resources.d.ts.map +1 -1
  77. package/dist/resources.js +5 -2
  78. package/dist/resources.js.map +1 -1
  79. package/dist/server.d.ts.map +1 -1
  80. package/dist/server.js +8 -1
  81. package/dist/server.js.map +1 -1
  82. package/dist/tools/batch.d.ts +3 -13
  83. package/dist/tools/batch.d.ts.map +1 -1
  84. package/dist/tools/batch.js +11 -27
  85. package/dist/tools/batch.js.map +1 -1
  86. package/dist/tools/create.d.ts.map +1 -1
  87. package/dist/tools/create.js +25 -46
  88. package/dist/tools/create.js.map +1 -1
  89. package/dist/tools/define.d.ts +20 -23
  90. package/dist/tools/define.d.ts.map +1 -1
  91. package/dist/tools/define.js +11 -27
  92. package/dist/tools/define.js.map +1 -1
  93. package/dist/tools/delete.d.ts.map +1 -1
  94. package/dist/tools/delete.js +10 -37
  95. package/dist/tools/delete.js.map +1 -1
  96. package/dist/tools/diff.d.ts.map +1 -1
  97. package/dist/tools/diff.js +2 -13
  98. package/dist/tools/diff.js.map +1 -1
  99. package/dist/tools/edit.d.ts.map +1 -1
  100. package/dist/tools/edit.js +20 -53
  101. package/dist/tools/edit.js.map +1 -1
  102. package/dist/tools/find-files.d.ts.map +1 -1
  103. package/dist/tools/find-files.js +3 -28
  104. package/dist/tools/find-files.js.map +1 -1
  105. package/dist/tools/index.js +1 -1
  106. package/dist/tools/index.js.map +1 -1
  107. package/dist/tools/list-roots.d.ts.map +1 -1
  108. package/dist/tools/list-roots.js +1 -12
  109. package/dist/tools/list-roots.js.map +1 -1
  110. package/dist/tools/list.d.ts.map +1 -1
  111. package/dist/tools/list.js +19 -53
  112. package/dist/tools/list.js.map +1 -1
  113. package/dist/tools/move.d.ts.map +1 -1
  114. package/dist/tools/move.js +54 -37
  115. package/dist/tools/move.js.map +1 -1
  116. package/dist/tools/patch.d.ts.map +1 -1
  117. package/dist/tools/patch.js +4 -24
  118. package/dist/tools/patch.js.map +1 -1
  119. package/dist/tools/progress.d.ts +0 -2
  120. package/dist/tools/progress.d.ts.map +1 -1
  121. package/dist/tools/progress.js +20 -12
  122. package/dist/tools/progress.js.map +1 -1
  123. package/dist/tools/read.d.ts.map +1 -1
  124. package/dist/tools/read.js +29 -116
  125. package/dist/tools/read.js.map +1 -1
  126. package/dist/tools/replace-text.d.ts.map +1 -1
  127. package/dist/tools/replace-text.js +20 -43
  128. package/dist/tools/replace-text.js.map +1 -1
  129. package/dist/tools/search-text.d.ts.map +1 -1
  130. package/dist/tools/search-text.js +24 -78
  131. package/dist/tools/search-text.js.map +1 -1
  132. package/dist/tools/stat.d.ts.map +1 -1
  133. package/dist/tools/stat.js +5 -19
  134. package/dist/tools/stat.js.map +1 -1
  135. package/dist/transport/http-policy.d.ts.map +1 -1
  136. package/dist/transport/http-policy.js +1 -0
  137. package/dist/transport/http-policy.js.map +1 -1
  138. package/dist/transport/http.d.ts.map +1 -1
  139. package/dist/transport/http.js +16 -27
  140. package/dist/transport/http.js.map +1 -1
  141. package/dist/transport/shared.d.ts +3 -1
  142. package/dist/transport/shared.d.ts.map +1 -1
  143. package/dist/transport/shared.js +14 -1
  144. package/dist/transport/shared.js.map +1 -1
  145. package/dist/transport/stdio.d.ts.map +1 -1
  146. package/dist/transport/stdio.js +18 -3
  147. package/dist/transport/stdio.js.map +1 -1
  148. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"replace-text.js","sourceRoot":"","sources":["../../src/tools/replace-text.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { Buffer, isUtf8 } from 'node:buffer';\nimport { basename, dirname } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport type { StoppedReason } from '../core/concurrency.ts';\nimport { processEntriesConcurrently, StoppedReasonSchema } from '../core/concurrency.ts';\nimport { unifiedPatch } from '../core/diff.ts';\nimport { ErrorCode, FsError, Problem } from '../core/errors.ts';\nimport { buildWrittenFileMeta } from '../core/file-uri.ts';\nimport { stoppedEarlyLine, truncateProgressPattern } from '../core/fmt.ts';\nimport type { GuardedFileSystem } from '../core/fs.ts';\nimport { globEntries } from '../core/glob.ts';\nimport { toPosixRelative } from '../core/path.ts';\nimport { readFileBufferWithLimit } from '../core/read.ts';\nimport {\n defaultFalseBoolean,\n IncludeHidden,\n IncludeIgnored,\n isBlank,\n MaxDepth,\n NonNegInt,\n OperationSummarySchema,\n OptionalPath,\n perPathEnvelope,\n SafeGlobPattern,\n} from '../core/schema.ts';\nimport type { Regex } from '../core/search.ts';\nimport { compileRegex, execMatches, freeRegex, RE2_MAX_INPUT_BYTES } from '../core/search.ts';\nimport {\n DEFAULT_SEARCH_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n escapeRegExp,\n getMaxTextFileSize,\n MAX_SEARCH_RESULTS,\n PARALLEL_CONCURRENCY,\n} from '../core/util.ts';\nimport { isTotalFailure } from './batch.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\nconst SearchAndReplaceInputSchema = z.strictObject({\n path: OptionalPath.describe(\n 'File to rewrite, or directory to rewrite under. Omitting it targets the ENTIRE first allowed root — ' +\n 'scope it deliberately, and pair a wide scope with dryRun=true first',\n ),\n pattern: SafeGlobPattern.optional().describe(\n 'Glob to restrict replacements to specific file types (e.g. **/*.ts); default: all text files',\n ),\n searchPattern: z\n .string()\n .min(1)\n .max(10000)\n .refine((val) => !isBlank(val), {\n message: 'searchPattern cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text or RE2 regex pattern to search for. When isRegex=true, uses RE2 syntax (no lookahead, lookbehind, or backreferences are supported). Cannot be empty or whitespace-only.',\n )\n .meta({ examples: ['TODO', 'function\\\\s+(\\\\w+)', 'import.*from'] }),\n replacement: z\n .string()\n .max(10000)\n .describe(\n 'Replacement text. Use capture group references ($1, $2, etc.) when isRegex=true. Use an empty string to delete all matches.',\n )\n .meta({ examples: ['$1_renamed', '', 'TODO: fix'] }),\n isRegex: defaultFalseBoolean('Treat searchPattern as a RE2 regex (default: literal text match)'),\n includeHidden: IncludeHidden,\n includeIgnored: IncludeIgnored,\n caseSensitive: defaultFalseBoolean('Enable case-sensitive matching (default: case-insensitive)'),\n wholeWord: defaultFalseBoolean('Match whole words only (word boundary anchoring)'),\n dryRun: defaultFalseBoolean(\n 'Preview replacements without writing to disk (default: false = apply changes)',\n ),\n returnDiff: defaultFalseBoolean('Include a unified diff of all changes in the response'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_RESULTS)\n .describe('Maximum total match count across all files before stopping'),\n maxFiles: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .describe('Maximum number of files to process'),\n maxDepth: MaxDepth,\n});\n\nconst ReplacePerPathSchema = perPathEnvelope(\n z.strictObject({ matches: NonNegInt.describe('Replacements applied in this file') }),\n 'Replacement outcome; present on success',\n);\n\n// The same `{ results, summary }` envelope `read`, `stat`, and `delete` use, so\n// a caller learns one shape for every tool that spans many paths. The former\n// `filesModified` / `failedFiles` counters are `summary.succeeded` / `.failed`,\n// and the old `primaryFile` block is gone — the resource_link content block\n// already points at the first modified file.\nconst SearchAndReplaceOutputSchema = z.strictObject({\n results: z\n .array(ReplacePerPathSchema)\n .describe('Per-file results: modified files, then any that could not be processed'),\n summary: OperationSummarySchema,\n totalMatches: NonNegInt.describe('Total number of replacements made across all files'),\n filesScanned: NonNegInt.describe('Total number of files examined'),\n skippedBinary: NonNegInt.optional().describe(\n 'Matching files left untouched because they are binary or not valid UTF-8 text',\n ),\n resultsTruncated: z\n .boolean()\n .optional()\n .describe(\n 'True when the results list holds fewer entries than summary.total: the changed-file or failed-file cap was hit. Trust summary over results.length.',\n ),\n diff: z\n .string()\n .optional()\n .describe('Unified diff of all changes (present when returnDiff=true or dryRun=true)'),\n diffTruncated: z\n .boolean()\n .optional()\n .describe('True when the diff was cut due to the size limit'),\n stoppedReason: StoppedReasonSchema.describe(\n 'Why enumeration stopped early: maxResults = match cap reached, maxFiles = file cap reached, timeout = time limit hit or cancelled. Absent when every matching file was enumerated. Marks the sweep incomplete, not the writes; files already dispatched still complete.',\n ),\n});\n\nconst MAX_FAILURES = 20;\nconst REPLACE_CONCURRENCY = Math.min(PARALLEL_CONCURRENCY, 8);\nconst MAX_CHANGED_FILES = 100;\nconst MAX_DIFF_SIZE = 20 * 1024; // 20KB limit for diff output\nconst DIFF_APPEND_BUFFER = 1024;\n\ninterface Failure {\n path: string;\n error: NonNullable<z.infer<typeof ReplacePerPathSchema>['error']>;\n}\n\nfunction recordFailure(failures: Failure[], failure: Failure): void {\n if (failures.length >= MAX_FAILURES) return;\n failures.push(failure);\n}\n\nfunction recordChangedFile(summary: ReplaceSummary, plan: ReplacementPlan, filePath: string): void {\n const relativePath = toPosixRelative(summary.root, filePath);\n // The first changed file is the one the resource_link points at; keep what\n // was written so the link needs no read-back.\n summary.primary ??= { path: filePath, content: plan.updatedContent };\n if (summary.changedFiles.length < MAX_CHANGED_FILES) {\n summary.changedFiles.push({ path: relativePath, matches: plan.matchCount });\n return;\n }\n summary.changedFilesTruncated = true;\n}\n\ninterface ReplacementMatcher {\n replace(content: string, replacement: string): { content: string; matchCount: number };\n testBuffer(buffer: Buffer): boolean;\n /** Releases any compiled pattern this matcher owns. Idempotent. */\n dispose(): void;\n}\n\nconst DOLLAR_TOKEN = /\\$(\\$|&|`|'|<([^>]*)>|\\d{1,2})/g;\n\n/**\n * Expand `$`-substitutions in a replacement template the way `RegExp` does.\n *\n * We cannot hand the template to RE2's own string replacer: it throws\n * `Invalid replacement string` on any `$` not followed by a substitution it\n * recognises (so a replacement of `$100` or a trailing `$` fails outright,\n * where `RegExp` inserts the `$` literally), and it renders an out-of-range\n * `$5` as `$4`. The matcher splices matches itself, so this is the single owner\n * of the syntax.\n */\nfunction expandDollarTokens(\n template: string,\n match: string,\n groups: (string | undefined)[],\n offset: number,\n input: string,\n named: Record<string, string> | undefined,\n): string {\n return template.replace(DOLLAR_TOKEN, (token: string, kind: string, name?: string) => {\n if (kind === '$') return '$';\n if (kind === '&') return match;\n if (kind === '`') return input.slice(0, offset);\n if (kind === \"'\") return input.slice(offset + match.length);\n if (name !== undefined) {\n if (named && Object.hasOwn(named, name)) return named[name] ?? '';\n return token;\n }\n // `$12` prefers group 12, then falls back to group 1 followed by a literal\n // `2`, and stays literal when neither exists — RegExp's own precedence.\n const two = Number.parseInt(kind, 10);\n if (kind.length === 2 && two >= 1 && two <= groups.length) return groups[two - 1] ?? '';\n const one = Number.parseInt(kind.slice(0, 1), 10);\n if (one >= 1 && one <= groups.length) {\n return (groups[one - 1] ?? '') + (kind.length === 2 ? kind.slice(1) : '');\n }\n return token;\n });\n}\n\nfunction createRegexReplacementMatcher(\n regex: Regex,\n expandReplacement: boolean,\n): ReplacementMatcher {\n return {\n testBuffer(buffer: Buffer): boolean {\n if (buffer.length > RE2_MAX_INPUT_BYTES) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large for a regex replace (${String(buffer.length)} > ${String(RE2_MAX_INPUT_BYTES)} bytes). Regex mode is used for isRegex, wholeWord, or the default caseSensitive: false; pass caseSensitive: true with a literal searchPattern, or split the file.`,\n );\n }\n // The regex is global and shared across every file in the batch, so a\n // previous file's match would otherwise start this scan mid-string.\n regex.lastIndex = 0;\n return regex.test(buffer.toString('utf-8'));\n },\n replace(content: string, replacement: string): { content: string; matchCount: number } {\n // Splicing by hand rather than through `String.replace(regex, …)`: RE2's\n // own replacer indexes the JS string with the code-point offsets it\n // reports, which lands the replacement short by one per astral character\n // (most emoji) earlier in the file. execMatches reports UTF-16 offsets.\n let matchCount = 0;\n let updated = '';\n let cursor = 0;\n for (const match of execMatches(regex, content)) {\n matchCount++;\n // Only isRegex=true opts into $1/$& substitution. A literal search\n // reaches this matcher too (case-insensitive and wholeWord both need a\n // regex), and there the replacement must be inserted verbatim.\n updated +=\n content.slice(cursor, match.start) +\n (expandReplacement\n ? expandDollarTokens(\n replacement,\n match.text,\n match.groups,\n match.start,\n content,\n match.named,\n )\n : replacement);\n cursor = match.end;\n }\n return { content: updated + content.slice(cursor), matchCount };\n },\n dispose(): void {\n freeRegex(regex);\n },\n };\n}\n\nfunction createCaseSensitiveLiteralMatcher(searchPattern: string): ReplacementMatcher {\n const searchBuffer = Buffer.from(searchPattern, 'utf8');\n\n return {\n testBuffer(buffer: Buffer): boolean {\n return buffer.indexOf(searchBuffer) !== -1;\n },\n replace(content: string, replacement: string): { content: string; matchCount: number } {\n let matchCount = 0;\n const updated = content.replaceAll(searchPattern, () => {\n matchCount++;\n return replacement;\n });\n return { content: updated, matchCount };\n },\n dispose(): void {\n // no compiled pattern to release\n },\n };\n}\n\ntype SearchAndReplaceArgs = z.infer<typeof SearchAndReplaceInputSchema>;\ntype SearchAndReplaceOutput = z.infer<typeof SearchAndReplaceOutputSchema>;\n\ninterface ReplaceContext {\n options: { dryRun: boolean; returnDiff: boolean };\n replacement: string;\n matcher: ReplacementMatcher;\n maxFileSize: number;\n signal: AbortSignal | undefined;\n summary: ReplaceSummary;\n fs: GuardedFileSystem;\n singleFile: boolean;\n}\n\ninterface ReplacementPlan {\n matchCount: number;\n originalContent: string;\n updatedContent: string;\n}\n\nasync function processEntry(entryPath: string, ctx: ReplaceContext): Promise<void> {\n const { options, signal, summary } = ctx;\n\n try {\n const plan = await readReplacementPlan(entryPath, ctx);\n if (!plan) {\n return;\n }\n\n if (!options.dryRun) {\n await ctx.fs.writeFile(entryPath, plan.updatedContent, {\n signal,\n });\n }\n\n // Bookkeep only after the write succeeds (or in dryRun, where there is no\n // write): a failed write must not count the file as changed.\n summary.totalMatches += plan.matchCount;\n summary.filesChanged++;\n\n recordChangedFile(summary, plan, entryPath);\n\n maybeAppendPatchDiff(summary, {\n filePath: entryPath,\n originalContent: plan.originalContent,\n updatedContent: plan.updatedContent,\n includeDiff: options.dryRun || options.returnDiff,\n });\n } catch (error) {\n summary.failedFiles++;\n recordFailure(summary.failures, {\n path: toPosixRelative(summary.root, entryPath),\n error: Problem.fromUnknown(error, ErrorCode.UNKNOWN, entryPath),\n });\n }\n}\n\nasync function readReplacementPlan(\n validPath: string,\n ctx: ReplaceContext,\n): Promise<ReplacementPlan | undefined> {\n const { matcher, replacement, maxFileSize, signal } = ctx;\n await using fileHandle = await ctx.fs.open(validPath);\n const stats = await fileHandle.stat();\n if (stats.size > maxFileSize) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large: ${validPath} (${String(stats.size)} bytes > ${String(maxFileSize)} bytes)`,\n );\n }\n\n const buffer = await readFileBufferWithLimit(fileHandle, maxFileSize, validPath, signal);\n if (!matcher.testBuffer(buffer)) return undefined;\n // Only bytes that decode to UTF-8 losslessly survive the string round trip;\n // anything else would be written back with U+FFFD in place of every bad byte.\n // NUL is valid UTF-8 but marks a binary file, as it does for `read`.\n if (!isUtf8(buffer) || buffer.includes(0)) {\n if (ctx.singleFile) {\n throw new FsError(ErrorCode.INVALID_INPUT, 'Binary or non-UTF-8 file detected.', validPath);\n }\n ctx.summary.skippedBinary++;\n return undefined;\n }\n\n const originalContent = buffer.toString('utf-8');\n const { content: updatedContent, matchCount } = matcher.replace(originalContent, replacement);\n return matchCount === 0 ? undefined : { matchCount, originalContent, updatedContent };\n}\n\nfunction maybeAppendPatchDiff(\n summary: ReplaceSummary,\n params: {\n filePath: string;\n originalContent: string;\n updatedContent: string;\n includeDiff: boolean;\n },\n): void {\n if (!params.includeDiff) return;\n\n // Budget first: a full budget must not pay for a diff it will discard, and a\n // diff past its deadline counts as truncated output, not a failed file.\n if (summary.diff.length >= MAX_DIFF_SIZE) {\n summary.diffTruncated = true;\n return;\n }\n const header = toPosixRelative(summary.root, params.filePath);\n const patch = unifiedPatch(header, params.originalContent, params.updatedContent);\n if (patch === undefined) {\n summary.diffTruncated = true;\n return;\n }\n if (summary.diff.length + patch.length <= MAX_DIFF_SIZE + DIFF_APPEND_BUFFER) {\n summary.diff += patch;\n return;\n }\n summary.diffTruncated = true;\n}\n\ninterface ReplaceSummary {\n root: string;\n totalMatches: number;\n filesChanged: number;\n failedFiles: number;\n processedFiles: number;\n skippedBinary: number;\n failures: Failure[];\n changedFiles: { path: string; matches: number }[];\n changedFilesTruncated: boolean;\n /** First file changed, as written. */\n primary?: { path: string; content: string };\n diff: string;\n diffTruncated: boolean;\n stoppedReason?: StoppedReason;\n}\n\nfunction createReplaceSummary(root: string): ReplaceSummary {\n return {\n root,\n totalMatches: 0,\n filesChanged: 0,\n failedFiles: 0,\n processedFiles: 0,\n skippedBinary: 0,\n failures: [],\n changedFiles: [],\n changedFilesTruncated: false,\n diff: '',\n diffTruncated: false,\n };\n}\n\nasync function resolveSearchRoot(\n pathValue: string | undefined,\n fs: GuardedFileSystem,\n): Promise<{ root: string; singleFile?: string }> {\n if (!pathValue) {\n return { root: fs.pathGuard.resolvePathOrRoot(undefined) };\n }\n const resolvedPath = await fs.pathGuard.validateExistingPath(pathValue);\n const { stats: fileStats } = await fs.stat(resolvedPath);\n if (fileStats.isFile()) {\n // A single explicit file target bypasses the glob machinery entirely:\n // routing it through globEntries with baseNameMatch would rewrite the\n // escaped basename to `**/${basename}` and match every same-named file\n // under the parent tree, not just this one.\n return {\n root: dirname(resolvedPath),\n singleFile: resolvedPath,\n };\n }\n return { root: resolvedPath };\n}\n\nfunction buildSearchPattern(args: SearchAndReplaceArgs): string {\n if (args.isRegex) {\n return args.wholeWord ? `\\\\b(?:${args.searchPattern})\\\\b` : args.searchPattern;\n }\n const escaped = escapeRegExp(args.searchPattern);\n return args.wholeWord ? `\\\\b(?:${escaped})\\\\b` : escaped;\n}\n\nfunction createReplacementMatcher(args: SearchAndReplaceArgs): ReplacementMatcher {\n // Use regex when isRegex, wholeWord, or case-insensitive (all require RE2)\n if (args.isRegex || args.wholeWord || !args.caseSensitive) {\n const regex = compileRegex(buildSearchPattern(args), { caseSensitive: args.caseSensitive });\n return createRegexReplacementMatcher(regex, args.isRegex);\n }\n return createCaseSensitiveLiteralMatcher(args.searchPattern);\n}\n\nfunction buildSearchAndReplaceStructuredResult(\n summary: ReplaceSummary,\n args: SearchAndReplaceArgs,\n): SearchAndReplaceOutput {\n const results = [\n ...summary.changedFiles.map((f) => ({ path: f.path, value: { matches: f.matches } })),\n ...summary.failures.map((f) => ({ path: f.path, error: f.error })),\n ];\n return {\n results,\n // `failedFiles` counts every failure; `failures` itself is capped at\n // MAX_FAILURES, so the summary must not be derived from the array length.\n summary: {\n total: summary.filesChanged + summary.failedFiles,\n succeeded: summary.filesChanged,\n failed: summary.failedFiles,\n },\n totalMatches: summary.totalMatches,\n filesScanned: summary.processedFiles,\n ...(summary.skippedBinary ? { skippedBinary: summary.skippedBinary } : {}),\n // Failures are capped at MAX_FAILURES independently of the changed-file\n // cap, so either cap can leave `results` shorter than `summary.total`.\n ...(summary.changedFilesTruncated || summary.failures.length < summary.failedFiles\n ? { resultsTruncated: true }\n : {}),\n ...((args.dryRun || args.returnDiff) && summary.diff ? { diff: summary.diff } : {}),\n ...(summary.diffTruncated ? { diffTruncated: true } : {}),\n ...(summary.stoppedReason ? { stoppedReason: summary.stoppedReason } : {}),\n };\n}\n\nasync function handleSearchAndReplace(\n args: SearchAndReplaceArgs,\n ctx: ToolCtx,\n): Promise<{\n structured: SearchAndReplaceOutput;\n link?: ContentBlock;\n}> {\n const maxFileSize = getMaxTextFileSize();\n const { root, singleFile } = await resolveSearchRoot(args.path, ctx.fs);\n const effectivePattern = args.pattern ?? '**/*';\n\n // An explicit single-file target bypasses baseNameMatch/exclude/hidden/\n // gitignore filtering — it should always be processed as the one file named.\n const entries: AsyncIterable<{ path: string }> | Iterable<{ path: string }> = singleFile\n ? [{ path: singleFile }]\n : globEntries({\n cwd: root,\n pattern: effectivePattern,\n includeHidden: args.includeHidden,\n skipIgnored: !args.includeIgnored,\n signal: ctx.signal,\n baseNameMatch: true,\n onlyFiles: true,\n suppressErrors: true,\n ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),\n });\n\n const summary = createReplaceSummary(root);\n\n // The matcher may own a compiled RE2 pattern, whose wasm memory re2-wasm\n // never reclaims on its own. Nothing past the scan touches it, so free it the\n // moment the scan is done — success, failure, or abort alike.\n const matcher = createReplacementMatcher(args);\n let stoppedReason: StoppedReason | undefined;\n try {\n const context: ReplaceContext = {\n options: {\n dryRun: args.dryRun,\n returnDiff: args.returnDiff,\n },\n replacement: args.replacement,\n matcher,\n maxFileSize,\n signal: ctx.signal,\n summary,\n fs: ctx.fs,\n singleFile: singleFile !== undefined,\n };\n\n stoppedReason = await processEntriesConcurrently(entries, {\n signal: ctx.signal,\n concurrency: REPLACE_CONCURRENCY,\n ...(args.maxFiles !== undefined ? { maxEntries: args.maxFiles } : {}),\n shouldStop: () => summary.totalMatches >= args.maxResults,\n onEntry: () => {\n summary.processedFiles++;\n ctx.onProgress?.({ current: summary.processedFiles });\n },\n onError: (entryPath, err) => {\n summary.failedFiles++;\n recordFailure(summary.failures, {\n path: toPosixRelative(summary.root, entryPath),\n error: Problem.fromUnknown(err, ErrorCode.UNKNOWN, entryPath),\n });\n },\n runEntry: (entryPath) => processEntry(entryPath, context),\n });\n } finally {\n matcher.dispose();\n }\n if (stoppedReason !== undefined) summary.stoppedReason = stoppedReason;\n\n ctx.onProgress?.({ current: summary.processedFiles });\n\n if (!args.dryRun && summary.totalMatches > 0) {\n ctx.log?.(\n 'info',\n `${summary.filesChanged} file(s) changed, ${summary.totalMatches} match(es)`,\n 'replace_text',\n );\n }\n\n const structured = buildSearchAndReplaceStructuredResult(summary, args);\n\n const link = summary.primary\n ? buildWrittenFileMeta({\n validPath: summary.primary.path,\n content: summary.primary.content,\n resourceStore: ctx.resourceStore,\n dryRun: args.dryRun,\n }).resourceLink\n : undefined;\n return link ? { structured, link } : { structured };\n}\n\nexport const REPLACE_TEXT = defineTool({\n name: 'replace_text',\n title: 'Search and Replace',\n description:\n 'Find and replace every occurrence of literal text or an RE2 regex, like sed -i, in one file or all files ' +\n 'under a directory, optionally filtered by glob. The pattern runs over the whole file: it can span lines, ' +\n 'and ^ and $ anchor to file start and end. edit replaces one unique exact match.',\n input: SearchAndReplaceInputSchema,\n output: SearchAndReplaceOutputSchema,\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n openWorldHint: false,\n },\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n progress: (args) => {\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n return {\n label: `Replace${dryLabel}`,\n subject: `${truncateProgressPattern(args.searchPattern)} → ${truncateProgressPattern(args.replacement)}`,\n };\n },\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const truncatedPattern = truncateProgressPattern(args.searchPattern);\n const { structured, link } = await handleSearchAndReplace(args, ctx);\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n const summaryText =\n `replace_text: '${truncatedPattern}'${dryLabel}` +\n ` \\u00b7 ${String(structured.totalMatches)} match(es)` +\n ` in ${String(structured.summary.succeeded)} file(s)` +\n (structured.summary.failed > 0 ? ` \\u00b7 ${String(structured.summary.failed)} failed` : '') +\n (structured.skippedBinary\n ? ` \\u00b7 ${String(structured.skippedBinary)} binary skipped`\n : '');\n // The structured half ships under `_meta`, which clients do not show the\n // model, so the stop state and the diff preview must ride the text.\n const lines = [summaryText];\n const stop = structured.stoppedReason;\n if (stop === 'timeout') lines.push(stoppedEarlyLine(stop));\n else if (stop !== undefined) {\n // maxResults/maxFiles here are the caller's own caps, so raising one is\n // what reaches the rest; the search engine's advice to narrow is not.\n lines.push(\n `// scan stopped early: hit the ${stop} limit; later files were not scanned. A higher ${stop} reaches them.`,\n );\n }\n // A failure's reason lives in `results`, which ships under `_meta`.\n for (const r of structured.results.filter((x) => x.error).slice(0, 3)) {\n if (r.error) lines.push(`// ${basename(r.path)}: ${r.error.code} ${r.error.message}`);\n }\n if (structured.diffTruncated) {\n lines.push(\n `// diff cut at ${String(MAX_DIFF_SIZE / 1024)} KB: some files' changes are not shown.`,\n );\n }\n const text = lines.join('\\n') + (structured.diff ? `\\n\\n${structured.diff}` : '');\n const isError = isTotalFailure(structured.summary);\n if (link) {\n return { structured, text, resources: [link], isError };\n }\n return { structured, text, isError };\n },\n});\n"]}
1
+ {"version":3,"file":"replace-text.js","sourceRoot":"","sources":["../../src/tools/replace-text.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { Buffer, isUtf8 } from 'node:buffer';\nimport { basename, dirname } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport type { StoppedReason } from '../core/concurrency.ts';\nimport { processEntriesConcurrently } from '../core/concurrency.ts';\nimport { unifiedPatch } from '../core/diff.ts';\nimport { ErrorCode, FsError, Problem } from '../core/errors.ts';\nimport { buildWrittenFileMeta } from '../core/file-uri.ts';\nimport { stoppedEarlyLine, truncateProgressPattern } from '../core/fmt.ts';\nimport type { GuardedFileSystem } from '../core/fs.ts';\nimport { globEntries } from '../core/glob.ts';\nimport { toPosixRelative } from '../core/path.ts';\nimport { readFileBufferWithLimit } from '../core/read.ts';\nimport {\n defaultFalseBoolean,\n IncludeHidden,\n IncludeIgnored,\n isBlank,\n MaxDepth,\n OptionalPath,\n SafeGlobPattern,\n} from '../core/schema.ts';\nimport type { Regex } from '../core/search.ts';\nimport { compileRegex, execMatches, freeRegex, RE2_MAX_INPUT_BYTES } from '../core/search.ts';\nimport {\n DEFAULT_SEARCH_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n escapeRegExp,\n getMaxTextFileSize,\n MAX_SEARCH_RESULTS,\n PARALLEL_CONCURRENCY,\n} from '../core/util.ts';\nimport { type BatchResult, isTotalFailure } from './batch.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\nconst SearchAndReplaceInputSchema = z.strictObject({\n path: OptionalPath.describe(\n 'File to rewrite, or directory to rewrite under. Omitting it targets the ENTIRE first allowed root — ' +\n 'scope it deliberately, and pair a wide scope with dryRun=true first',\n ),\n pattern: SafeGlobPattern.optional().describe(\n 'Glob to restrict replacements to specific file types (e.g. **/*.ts); default: all text files',\n ),\n searchPattern: z\n .string()\n .min(1)\n .max(10000)\n .refine((val) => !isBlank(val), {\n message: 'searchPattern cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text or RE2 regex pattern to search for. When isRegex=true, uses RE2 syntax (no lookahead, lookbehind, or backreferences are supported). Cannot be empty or whitespace-only.',\n )\n .meta({ examples: ['TODO', 'function\\\\s+(\\\\w+)', 'import.*from'] }),\n replacement: z\n .string()\n .max(10000)\n .describe(\n 'Replacement text. Use capture group references ($1, $2, etc.) when isRegex=true. Use an empty string to delete all matches.',\n )\n .meta({ examples: ['$1_renamed', '', 'TODO: fix'] }),\n isRegex: defaultFalseBoolean('Treat searchPattern as a RE2 regex (default: literal text match)'),\n includeHidden: IncludeHidden,\n includeIgnored: IncludeIgnored,\n caseSensitive: defaultFalseBoolean('Enable case-sensitive matching (default: case-insensitive)'),\n wholeWord: defaultFalseBoolean('Match whole words only (word boundary anchoring)'),\n dryRun: defaultFalseBoolean(\n 'Preview replacements without writing to disk (default: false = apply changes)',\n ),\n returnDiff: defaultFalseBoolean('Include a unified diff of all changes in the response'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_RESULTS)\n .describe('Maximum total match count across all files before stopping'),\n maxFiles: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .describe('Maximum number of files to process'),\n maxDepth: MaxDepth,\n});\n\ntype SearchAndReplaceOutput = BatchResult<{ matches: number }> & {\n totalMatches: number;\n filesScanned: number;\n skippedBinary?: number;\n resultsTruncated?: boolean;\n diff?: string;\n diffTruncated?: boolean;\n stoppedReason?: StoppedReason;\n};\n\nconst MAX_FAILURES = 20;\nconst REPLACE_CONCURRENCY = Math.min(PARALLEL_CONCURRENCY, 8);\nconst MAX_CHANGED_FILES = 100;\nconst MAX_DIFF_SIZE = 20 * 1024; // 20KB limit for diff output\nconst DIFF_APPEND_BUFFER = 1024;\n\ninterface Failure {\n path: string;\n error: Problem;\n}\n\nfunction recordFailure(failures: Failure[], failure: Failure): void {\n if (failures.length >= MAX_FAILURES) return;\n failures.push(failure);\n}\n\nfunction recordChangedFile(summary: ReplaceSummary, plan: ReplacementPlan, filePath: string): void {\n const relativePath = toPosixRelative(summary.root, filePath);\n // The first changed file is the one the resource_link points at; keep what\n // was written so the link needs no read-back.\n summary.primary ??= { path: filePath, content: plan.updatedContent };\n if (summary.changedFiles.length < MAX_CHANGED_FILES) {\n summary.changedFiles.push({ path: relativePath, matches: plan.matchCount });\n return;\n }\n summary.changedFilesTruncated = true;\n}\n\ninterface ReplacementMatcher {\n replace(content: string, replacement: string): { content: string; matchCount: number };\n testBuffer(buffer: Buffer): boolean;\n /** Releases any compiled pattern this matcher owns. Idempotent. */\n dispose(): void;\n}\n\nconst DOLLAR_TOKEN = /\\$(\\$|&|`|'|<([^>]*)>|\\d{1,2})/g;\n\n/**\n * Expand `$`-substitutions in a replacement template the way `RegExp` does.\n *\n * We cannot hand the template to RE2's own string replacer: it throws\n * `Invalid replacement string` on any `$` not followed by a substitution it\n * recognises (so a replacement of `$100` or a trailing `$` fails outright,\n * where `RegExp` inserts the `$` literally), and it renders an out-of-range\n * `$5` as `$4`. The matcher splices matches itself, so this is the single owner\n * of the syntax.\n */\nfunction expandDollarTokens(\n template: string,\n match: string,\n groups: (string | undefined)[],\n offset: number,\n input: string,\n named: Record<string, string> | undefined,\n): string {\n return template.replace(DOLLAR_TOKEN, (token: string, kind: string, name?: string) => {\n if (kind === '$') return '$';\n if (kind === '&') return match;\n if (kind === '`') return input.slice(0, offset);\n if (kind === \"'\") return input.slice(offset + match.length);\n if (name !== undefined) {\n if (named && Object.hasOwn(named, name)) return named[name] ?? '';\n return token;\n }\n // `$12` prefers group 12, then falls back to group 1 followed by a literal\n // `2`, and stays literal when neither exists — RegExp's own precedence.\n const two = Number.parseInt(kind, 10);\n if (kind.length === 2 && two >= 1 && two <= groups.length) return groups[two - 1] ?? '';\n const one = Number.parseInt(kind.slice(0, 1), 10);\n if (one >= 1 && one <= groups.length) {\n return (groups[one - 1] ?? '') + (kind.length === 2 ? kind.slice(1) : '');\n }\n return token;\n });\n}\n\nfunction createRegexReplacementMatcher(\n regex: Regex,\n expandReplacement: boolean,\n): ReplacementMatcher {\n return {\n testBuffer(buffer: Buffer): boolean {\n if (buffer.length > RE2_MAX_INPUT_BYTES) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large for a regex replace (${String(buffer.length)} > ${String(RE2_MAX_INPUT_BYTES)} bytes). Regex mode is used for isRegex, wholeWord, or the default caseSensitive: false; pass caseSensitive: true with a literal searchPattern, or split the file.`,\n );\n }\n // The regex is global and shared across every file in the batch, so a\n // previous file's match would otherwise start this scan mid-string.\n regex.lastIndex = 0;\n return regex.test(buffer.toString('utf-8'));\n },\n replace(content: string, replacement: string): { content: string; matchCount: number } {\n // Splicing by hand rather than through `String.replace(regex, …)`: RE2's\n // own replacer indexes the JS string with the code-point offsets it\n // reports, which lands the replacement short by one per astral character\n // (most emoji) earlier in the file. execMatches reports UTF-16 offsets.\n let matchCount = 0;\n let updated = '';\n let cursor = 0;\n for (const match of execMatches(regex, content)) {\n matchCount++;\n // Only isRegex=true opts into $1/$& substitution. A literal search\n // reaches this matcher too (case-insensitive and wholeWord both need a\n // regex), and there the replacement must be inserted verbatim.\n updated +=\n content.slice(cursor, match.start) +\n (expandReplacement\n ? expandDollarTokens(\n replacement,\n match.text,\n match.groups,\n match.start,\n content,\n match.named,\n )\n : replacement);\n cursor = match.end;\n }\n return { content: updated + content.slice(cursor), matchCount };\n },\n dispose(): void {\n freeRegex(regex);\n },\n };\n}\n\nfunction createCaseSensitiveLiteralMatcher(searchPattern: string): ReplacementMatcher {\n const searchBuffer = Buffer.from(searchPattern, 'utf8');\n\n return {\n testBuffer(buffer: Buffer): boolean {\n return buffer.indexOf(searchBuffer) !== -1;\n },\n replace(content: string, replacement: string): { content: string; matchCount: number } {\n let matchCount = 0;\n const updated = content.replaceAll(searchPattern, () => {\n matchCount++;\n return replacement;\n });\n return { content: updated, matchCount };\n },\n dispose(): void {\n // no compiled pattern to release\n },\n };\n}\n\ntype SearchAndReplaceArgs = z.infer<typeof SearchAndReplaceInputSchema>;\n\ninterface ReplaceContext {\n options: { dryRun: boolean; returnDiff: boolean };\n replacement: string;\n matcher: ReplacementMatcher;\n maxFileSize: number;\n signal: AbortSignal | undefined;\n summary: ReplaceSummary;\n fs: GuardedFileSystem;\n singleFile: boolean;\n}\n\ninterface ReplacementPlan {\n matchCount: number;\n originalContent: string;\n updatedContent: string;\n}\n\nasync function processEntry(entryPath: string, ctx: ReplaceContext): Promise<void> {\n const { options, signal, summary } = ctx;\n\n try {\n const plan = await readReplacementPlan(entryPath, ctx);\n if (!plan) {\n return;\n }\n\n if (!options.dryRun) {\n await ctx.fs.writeFile(entryPath, plan.updatedContent, {\n signal,\n });\n }\n\n // Bookkeep only after the write succeeds (or in dryRun, where there is no\n // write): a failed write must not count the file as changed.\n summary.totalMatches += plan.matchCount;\n summary.filesChanged++;\n\n recordChangedFile(summary, plan, entryPath);\n\n maybeAppendPatchDiff(summary, {\n filePath: entryPath,\n originalContent: plan.originalContent,\n updatedContent: plan.updatedContent,\n includeDiff: options.dryRun || options.returnDiff,\n });\n } catch (error) {\n summary.failedFiles++;\n recordFailure(summary.failures, {\n path: toPosixRelative(summary.root, entryPath),\n error: Problem.fromUnknown(error, ErrorCode.UNKNOWN, entryPath),\n });\n }\n}\n\nasync function readReplacementPlan(\n validPath: string,\n ctx: ReplaceContext,\n): Promise<ReplacementPlan | undefined> {\n const { matcher, replacement, maxFileSize, signal } = ctx;\n await using fileHandle = await ctx.fs.open(validPath);\n const stats = await fileHandle.stat();\n if (stats.size > maxFileSize) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large: ${validPath} (${String(stats.size)} bytes > ${String(maxFileSize)} bytes)`,\n );\n }\n\n const buffer = await readFileBufferWithLimit(fileHandle, maxFileSize, validPath, signal);\n if (!matcher.testBuffer(buffer)) return undefined;\n // Only bytes that decode to UTF-8 losslessly survive the string round trip;\n // anything else would be written back with U+FFFD in place of every bad byte.\n // NUL is valid UTF-8 but marks a binary file, as it does for `read`.\n if (!isUtf8(buffer) || buffer.includes(0)) {\n if (ctx.singleFile) {\n throw new FsError(ErrorCode.INVALID_INPUT, 'Binary or non-UTF-8 file detected.', validPath);\n }\n ctx.summary.skippedBinary++;\n return undefined;\n }\n\n const originalContent = buffer.toString('utf-8');\n const { content: updatedContent, matchCount } = matcher.replace(originalContent, replacement);\n return matchCount === 0 ? undefined : { matchCount, originalContent, updatedContent };\n}\n\nfunction maybeAppendPatchDiff(\n summary: ReplaceSummary,\n params: {\n filePath: string;\n originalContent: string;\n updatedContent: string;\n includeDiff: boolean;\n },\n): void {\n if (!params.includeDiff) return;\n\n // Budget first: a full budget must not pay for a diff it will discard, and a\n // diff past its deadline counts as truncated output, not a failed file.\n if (summary.diff.length >= MAX_DIFF_SIZE) {\n summary.diffTruncated = true;\n return;\n }\n const header = toPosixRelative(summary.root, params.filePath);\n const patch = unifiedPatch(header, params.originalContent, params.updatedContent);\n if (patch === undefined) {\n summary.diffTruncated = true;\n return;\n }\n if (summary.diff.length + patch.length <= MAX_DIFF_SIZE + DIFF_APPEND_BUFFER) {\n summary.diff += patch;\n return;\n }\n summary.diffTruncated = true;\n}\n\ninterface ReplaceSummary {\n root: string;\n totalMatches: number;\n filesChanged: number;\n failedFiles: number;\n processedFiles: number;\n skippedBinary: number;\n failures: Failure[];\n changedFiles: { path: string; matches: number }[];\n changedFilesTruncated: boolean;\n /** First file changed, as written. */\n primary?: { path: string; content: string };\n diff: string;\n diffTruncated: boolean;\n stoppedReason?: StoppedReason;\n}\n\nfunction createReplaceSummary(root: string): ReplaceSummary {\n return {\n root,\n totalMatches: 0,\n filesChanged: 0,\n failedFiles: 0,\n processedFiles: 0,\n skippedBinary: 0,\n failures: [],\n changedFiles: [],\n changedFilesTruncated: false,\n diff: '',\n diffTruncated: false,\n };\n}\n\nasync function resolveSearchRoot(\n pathValue: string | undefined,\n fs: GuardedFileSystem,\n): Promise<{ root: string; singleFile?: string }> {\n if (!pathValue) {\n return { root: fs.pathGuard.resolvePathOrRoot(undefined) };\n }\n const resolvedPath = await fs.pathGuard.validateExistingPath(pathValue);\n const { stats: fileStats } = await fs.stat(resolvedPath);\n if (fileStats.isFile()) {\n // A single explicit file target bypasses the glob machinery entirely:\n // routing it through globEntries with baseNameMatch would rewrite the\n // escaped basename to `**/${basename}` and match every same-named file\n // under the parent tree, not just this one.\n return {\n root: dirname(resolvedPath),\n singleFile: resolvedPath,\n };\n }\n return { root: resolvedPath };\n}\n\nfunction buildSearchPattern(args: SearchAndReplaceArgs): string {\n if (args.isRegex) {\n return args.wholeWord ? `\\\\b(?:${args.searchPattern})\\\\b` : args.searchPattern;\n }\n const escaped = escapeRegExp(args.searchPattern);\n return args.wholeWord ? `\\\\b(?:${escaped})\\\\b` : escaped;\n}\n\nfunction createReplacementMatcher(args: SearchAndReplaceArgs): ReplacementMatcher {\n // Use regex when isRegex, wholeWord, or case-insensitive (all require RE2)\n if (args.isRegex || args.wholeWord || !args.caseSensitive) {\n const regex = compileRegex(buildSearchPattern(args), { caseSensitive: args.caseSensitive });\n return createRegexReplacementMatcher(regex, args.isRegex);\n }\n return createCaseSensitiveLiteralMatcher(args.searchPattern);\n}\n\nfunction buildSearchAndReplaceStructuredResult(\n summary: ReplaceSummary,\n args: SearchAndReplaceArgs,\n): SearchAndReplaceOutput {\n const results = [\n ...summary.changedFiles.map((f) => ({ path: f.path, value: { matches: f.matches } })),\n ...summary.failures.map((f) => ({ path: f.path, error: f.error })),\n ];\n return {\n results,\n // `failedFiles` counts every failure; `failures` itself is capped at\n // MAX_FAILURES, so the summary must not be derived from the array length.\n summary: {\n total: summary.filesChanged + summary.failedFiles,\n succeeded: summary.filesChanged,\n failed: summary.failedFiles,\n },\n totalMatches: summary.totalMatches,\n filesScanned: summary.processedFiles,\n ...(summary.skippedBinary ? { skippedBinary: summary.skippedBinary } : {}),\n // Failures are capped at MAX_FAILURES independently of the changed-file\n // cap, so either cap can leave `results` shorter than `summary.total`.\n ...(summary.changedFilesTruncated || summary.failures.length < summary.failedFiles\n ? { resultsTruncated: true }\n : {}),\n ...((args.dryRun || args.returnDiff) && summary.diff ? { diff: summary.diff } : {}),\n ...(summary.diffTruncated ? { diffTruncated: true } : {}),\n ...(summary.stoppedReason ? { stoppedReason: summary.stoppedReason } : {}),\n };\n}\n\nasync function handleSearchAndReplace(\n args: SearchAndReplaceArgs,\n ctx: ToolCtx,\n): Promise<{\n structured: SearchAndReplaceOutput;\n link?: ContentBlock;\n}> {\n const maxFileSize = getMaxTextFileSize();\n const { root, singleFile } = await resolveSearchRoot(args.path, ctx.fs);\n const effectivePattern = args.pattern ?? '**/*';\n const ceiling = ctx.fs.pathGuard.allowedRootContaining(root);\n\n // An explicit single-file target bypasses baseNameMatch/exclude/hidden/\n // gitignore filtering — it should always be processed as the one file named.\n const entries: AsyncIterable<{ path: string }> | Iterable<{ path: string }> = singleFile\n ? [{ path: singleFile }]\n : globEntries({\n cwd: root,\n pattern: effectivePattern,\n includeHidden: args.includeHidden,\n skipIgnored: !args.includeIgnored,\n ...(ceiling !== undefined ? { ignoreCeiling: ceiling } : {}),\n signal: ctx.signal,\n baseNameMatch: true,\n onlyFiles: true,\n suppressErrors: true,\n ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),\n });\n\n const summary = createReplaceSummary(root);\n\n // The matcher may own a compiled RE2 pattern, whose wasm memory re2-wasm\n // never reclaims on its own. Nothing past the scan touches it, so free it the\n // moment the scan is done — success, failure, or abort alike.\n const matcher = createReplacementMatcher(args);\n let stoppedReason: StoppedReason | undefined;\n try {\n const context: ReplaceContext = {\n options: {\n dryRun: args.dryRun,\n returnDiff: args.returnDiff,\n },\n replacement: args.replacement,\n matcher,\n maxFileSize,\n signal: ctx.signal,\n summary,\n fs: ctx.fs,\n singleFile: singleFile !== undefined,\n };\n\n stoppedReason = await processEntriesConcurrently(entries, {\n signal: ctx.signal,\n concurrency: REPLACE_CONCURRENCY,\n ...(args.maxFiles !== undefined ? { maxEntries: args.maxFiles } : {}),\n shouldStop: () => summary.totalMatches >= args.maxResults,\n onEntry: () => {\n summary.processedFiles++;\n ctx.onProgress({ current: summary.processedFiles });\n },\n onError: (entryPath, err) => {\n summary.failedFiles++;\n recordFailure(summary.failures, {\n path: toPosixRelative(summary.root, entryPath),\n error: Problem.fromUnknown(err, ErrorCode.UNKNOWN, entryPath),\n });\n },\n runEntry: (entryPath) => processEntry(entryPath, context),\n });\n } finally {\n matcher.dispose();\n }\n if (stoppedReason !== undefined) summary.stoppedReason = stoppedReason;\n\n ctx.onProgress({ current: summary.processedFiles });\n\n if (!args.dryRun && summary.totalMatches > 0) {\n ctx.log(\n 'info',\n `${summary.filesChanged} file(s) changed, ${summary.totalMatches} match(es)`,\n 'replace_text',\n );\n }\n\n const structured = buildSearchAndReplaceStructuredResult(summary, args);\n\n let primaryModified: string | undefined;\n if (summary.primary && !args.dryRun) {\n try {\n primaryModified = (\n await ctx.fs.stat(summary.primary.path, { signal: ctx.signal })\n ).stats.mtime.toISOString();\n } catch {\n /* result metadata only; the write already succeeded */\n }\n }\n const link = summary.primary\n ? buildWrittenFileMeta({\n validPath: summary.primary.path,\n content: summary.primary.content,\n dryRun: args.dryRun,\n lastModified: primaryModified,\n }).resourceLink\n : undefined;\n return link ? { structured, link } : { structured };\n}\n\nexport const REPLACE_TEXT = defineTool<typeof SearchAndReplaceInputSchema, SearchAndReplaceOutput>({\n name: 'replace_text',\n title: 'Search and Replace',\n description:\n 'Find and replace every occurrence of literal text or an RE2 regex, like sed -i, in one file or all files ' +\n 'under a directory, optionally filtered by glob. The pattern runs over the whole file: it can span lines, ' +\n 'and ^ and $ anchor to file start and end. edit replaces one unique exact match.',\n input: SearchAndReplaceInputSchema,\n readOnlyHint: false,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n progress: (args) => {\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n return {\n label: `Replace${dryLabel}`,\n subject: `${truncateProgressPattern(args.searchPattern)} → ${truncateProgressPattern(args.replacement)}`,\n };\n },\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const truncatedPattern = truncateProgressPattern(args.searchPattern);\n const { structured, link } = await handleSearchAndReplace(args, ctx);\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n const summaryText =\n `replace_text: '${truncatedPattern}'${dryLabel}` +\n ` \\u00b7 ${String(structured.totalMatches)} match(es)` +\n ` in ${String(structured.summary.succeeded)} file(s)` +\n (structured.summary.failed > 0 ? ` \\u00b7 ${String(structured.summary.failed)} failed` : '') +\n (structured.skippedBinary\n ? ` \\u00b7 ${String(structured.skippedBinary)} binary skipped`\n : '');\n // The structured half ships under `_meta`, which clients do not show the\n // model, so the stop state and the diff preview must ride the text.\n const lines = [summaryText];\n const stop = structured.stoppedReason;\n if (stop === 'timeout') lines.push(stoppedEarlyLine(stop));\n else if (stop !== undefined) {\n // maxResults/maxFiles here are the caller's own caps, so raising one is\n // what reaches the rest; the search engine's advice to narrow is not.\n lines.push(\n `// scan stopped early: hit the ${stop} limit; later files were not scanned. A higher ${stop} reaches them.`,\n );\n }\n // A failure's reason lives in `results`, which ships under `_meta`.\n for (const r of structured.results.filter((x) => 'error' in x).slice(0, 3)) {\n lines.push(`// ${basename(r.path)}: ${r.error.code} ${r.error.message}`);\n }\n if (structured.diffTruncated) {\n lines.push(\n `// diff cut at ${String(MAX_DIFF_SIZE / 1024)} KB: some files' changes are not shown.`,\n );\n }\n const text = lines.join('\\n') + (structured.diff ? `\\n\\n${structured.diff}` : '');\n const isError = isTotalFailure(structured.summary);\n if (link) {\n return { structured, text, resources: [link], isError };\n }\n return { structured, text, isError };\n },\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"search-text.d.ts","sourceRoot":"","sources":["../../src/tools/search-text.ts"],"names":[],"mappings":"AAwVA,eAAO,MAAM,WAAW,mCA4CtB,CAAC"}
1
+ {"version":3,"file":"search-text.d.ts","sourceRoot":"","sources":["../../src/tools/search-text.ts"],"names":[],"mappings":"AA4RA,eAAO,MAAM,WAAW,mCAwCtB,CAAC"}
@@ -1,12 +1,11 @@
1
1
  import { stat } from 'node:fs/promises';
2
- import { basename, dirname } from 'node:path';
2
+ import { dirname } from 'node:path';
3
3
  import * as z from 'zod/v4';
4
- import { SearchStoppedReasonSchema } from "../core/concurrency.js";
5
4
  import { paginate } from "../core/cursor.js";
6
5
  import { ErrorCode, FsError } from "../core/errors.js";
7
6
  import { formatCount, pageTrailer, truncateProgressPattern } from "../core/fmt.js";
8
7
  import { toPosixRelative } from "../core/path.js";
9
- import { CursorSchema, defaultFalseBoolean, IncludeHidden, IncludeIgnored, isBlank, MaxDepth, NextCursorSchema, NonNegInt, OptionalPath, PositiveInt, SafeGlobPattern, } from "../core/schema.js";
8
+ import { CursorSchema, defaultFalseBoolean, IncludeHidden, IncludeIgnored, isBlank, MaxDepth, OptionalPath, SafeGlobPattern, } from "../core/schema.js";
10
9
  import { searchContent } from "../core/search.js";
11
10
  import { putJsonResource } from "../core/store.js";
12
11
  import { DEFAULT_SEARCH_CONTENT_RESULTS, DEFAULT_SEARCH_TIMEOUT_MS, MAX_SEARCH_RESULTS, } from "../core/util.js";
@@ -43,41 +42,6 @@ const GrepInputSchema = z.strictObject({
43
42
  maxDepth: MaxDepth,
44
43
  cursor: CursorSchema,
45
44
  });
46
- const GrepOutputSchema = z.strictObject({
47
- matches: z
48
- .array(z.strictObject({
49
- file: z.string().describe('File path relative to the search root'),
50
- line: PositiveInt.describe('1-indexed line number of the match'),
51
- column: NonNegInt.optional().describe('0-indexed column offset of the match start'),
52
- content: z.string().describe('Full text of the matching line'),
53
- matchCount: NonNegInt.optional().describe('Number of pattern occurrences on this line'),
54
- before: z
55
- .array(z.string())
56
- .optional()
57
- .describe('Lines immediately before the match; present when context > 0'),
58
- after: z
59
- .array(z.string())
60
- .optional()
61
- .describe('Lines immediately after the match; present when context > 0'),
62
- }))
63
- .describe('Flat list of matches sorted by file path then line number'),
64
- totalMatches: NonNegInt.optional().describe("Total matching lines, one per entry in matches (not per occurrence); see that entry's matchCount for occurrences on a line."),
65
- filesMatched: NonNegInt.optional().describe('Number of files containing at least one match'),
66
- filesScanned: NonNegInt.optional().describe('Total number of files examined'),
67
- skippedInaccessible: NonNegInt.optional().describe('Files skipped unread due to permission or access errors'),
68
- skippedTooLarge: NonNegInt.optional().describe('Files skipped unread because they exceed the text-file size limit; raise the limit or narrow pattern if a match was expected in one'),
69
- skippedBinary: NonNegInt.optional().describe('Files skipped because they are binary'),
70
- truncated: z
71
- .boolean()
72
- .optional()
73
- .describe('True when the search engine cut the match list — the hard result cap or the time limit. Paging is not truncation: a set that spans pages has nextCursor instead.'),
74
- stoppedReason: SearchStoppedReasonSchema.describe('Why the search ended early: maxResults = result cap reached, timeout = time limit hit or the request was cancelled. Absent when the scan ran to completion.'),
75
- resourceUri: z
76
- .string()
77
- .optional()
78
- .describe('URI to the full match list in the resource store; first page only, whenever the response is incomplete — more pages follow, or the engine cut the search'),
79
- nextCursor: NextCursorSchema,
80
- });
81
45
  function matchRow(m) {
82
46
  return `${m.file}:${String(m.line)}: ${m.content}`;
83
47
  }
@@ -165,16 +129,9 @@ function buildSortedPayloads(result) {
165
129
  payloads.sort((l, r) => l.file.localeCompare(r.file) || l.line - r.line);
166
130
  return payloads;
167
131
  }
168
- /**
169
- * `path` is documented as "file to search, or directory to search under", but
170
- * the scan itself only walks directories. A file path is therefore rewritten
171
- * into the scan it means: its parent as the base, its own name as the glob.
172
- * Naming a file is an explicit request for that file, so hidden/ignored
173
- * filtering is lifted for it — otherwise `search_text` on a path the caller can
174
- * see returned nothing.
175
- */
176
- async function resolveSearchScope(args, ctx) {
177
- const requested = ctx.fs.pathGuard.resolvePathOrRoot(args.path);
132
+ /** Explicit files bypass glob filtering; their parent anchors the relative result paths. */
133
+ async function resolveSearchScope(path, ctx) {
134
+ const requested = ctx.fs.pathGuard.resolvePathOrRoot(path);
178
135
  // One resolution, one stat: validateExistingDirectory would redo both.
179
136
  const resolved = await ctx.fs.pathGuard.validateExistingPath(requested);
180
137
  const stats = await stat(resolved);
@@ -182,21 +139,14 @@ async function resolveSearchScope(args, ctx) {
182
139
  if (!stats.isDirectory()) {
183
140
  throw new FsError(ErrorCode.NOT_DIRECTORY, 'Not a directory', requested);
184
141
  }
185
- return { basePath: resolved, args };
142
+ return { basePath: resolved };
186
143
  }
187
144
  return {
188
145
  basePath: dirname(resolved),
189
- // The `./` anchors the name to the parent: a bare name is a basename glob
190
- // that would also match every namesake anywhere below it.
191
- // ponytail: the name goes through as a glob, so a file whose name contains
192
- // glob metacharacters (`[id].ts`) matches as a pattern rather than
193
- // literally. Escape it here if that ever bites.
194
- args: {
195
- ...args,
196
- pattern: `./${basename(resolved)}`,
197
- includeHidden: true,
198
- includeIgnored: true,
199
- },
146
+ // The name is NOT turned into a glob: `[slug].tsx` would read as a
147
+ // character class. searchContent scans exactly this file instead, and
148
+ // hidden/ignored filtering is moot for a file the caller named.
149
+ explicitFile: resolved,
200
150
  };
201
151
  }
202
152
  async function handleSearchContent(args, ctx) {
@@ -213,23 +163,23 @@ async function handleSearchContent(args, ctx) {
213
163
  maxDepth: args.maxDepth,
214
164
  context: args.context,
215
165
  });
216
- const { resourceStore } = ctx;
217
166
  const paged = await paginate({
218
167
  store: ctx.pageStore,
219
168
  queryKey,
220
169
  cursor: args.cursor,
221
170
  pageSize: args.maxResults,
222
171
  produce: async () => {
223
- const { basePath, args: scoped } = await resolveSearchScope(args, ctx);
224
- const result = await searchContent(basePath, scoped.searchPattern, {
225
- includeHidden: scoped.includeHidden,
226
- filePattern: scoped.pattern ?? '**/*',
227
- caseSensitive: scoped.caseSensitive,
228
- isRegex: scoped.isRegex,
172
+ const { basePath, explicitFile } = await resolveSearchScope(args.path, ctx);
173
+ const result = await searchContent(basePath, args.searchPattern, {
174
+ includeHidden: args.includeHidden,
175
+ filePattern: args.pattern ?? '**/*',
176
+ caseSensitive: args.caseSensitive,
177
+ isRegex: args.isRegex,
229
178
  maxResults: MAX_SEARCH_RESULTS,
230
- skipIgnored: !scoped.includeIgnored,
231
- context: scoped.context,
232
- ...(scoped.maxDepth !== undefined ? { maxDepth: scoped.maxDepth } : {}),
179
+ skipIgnored: !args.includeIgnored,
180
+ context: args.context,
181
+ ...(explicitFile !== undefined ? { explicitFile } : {}),
182
+ ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),
233
183
  signal: ctx.signal,
234
184
  }, ctx.fs.pathGuard);
235
185
  return {
@@ -238,9 +188,9 @@ async function handleSearchContent(args, ctx) {
238
188
  truncated: result.summary.truncated,
239
189
  };
240
190
  },
241
- externalize: resourceStore
242
- ? (matches, metadata) => putJsonResource(resourceStore, `'${args.searchPattern}' matches`, searchContentOutput(matches, metadata, undefined, undefined))
243
- : undefined,
191
+ externalize: (matches, metadata) => putJsonResource(ctx.resourceStore, `'${args.searchPattern}' matches`, {
192
+ ...searchContentOutput(matches, metadata, undefined, undefined),
193
+ }),
244
194
  });
245
195
  return {
246
196
  structured: searchContentOutput(paged.page, paged.metadata, paged.nextCursor, paged.resource?.entry.uri),
@@ -255,11 +205,7 @@ export const SEARCH_TEXT = defineTool({
255
205
  description: 'Search file contents for literal text or an RE2 regex, like grep; returns matching lines with line numbers ' +
256
206
  'and paths relative to the searched directory. Patterns match within one line. find_files matches file names.',
257
207
  input: GrepInputSchema,
258
- output: GrepOutputSchema,
259
- annotations: {
260
- readOnlyHint: true,
261
- openWorldHint: false,
262
- },
208
+ readOnlyHint: true,
263
209
  timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
264
210
  progress: (args) => ({
265
211
  label: 'Search',
@@ -1 +1 @@
1
- {"version":3,"file":"search-text.js","sourceRoot":"","sources":["../../src/tools/search-text.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from 'node:fs/promises';\nimport { basename, dirname } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { SearchStoppedReasonSchema } from '../core/concurrency.ts';\nimport { paginate } from '../core/cursor.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { formatCount, pageTrailer, truncateProgressPattern } from '../core/fmt.ts';\nimport { toPosixRelative } from '../core/path.ts';\nimport {\n CursorSchema,\n defaultFalseBoolean,\n IncludeHidden,\n IncludeIgnored,\n isBlank,\n MaxDepth,\n NextCursorSchema,\n NonNegInt,\n OptionalPath,\n PositiveInt,\n SafeGlobPattern,\n} from '../core/schema.ts';\nimport { searchContent } from '../core/search.ts';\nimport type { JsonResourceResult } from '../core/store.ts';\nimport { putJsonResource } from '../core/store.ts';\nimport {\n DEFAULT_SEARCH_CONTENT_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n MAX_SEARCH_RESULTS,\n} from '../core/util.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\n// Type Definitions\ntype SearchInput = z.infer<typeof GrepInputSchema>;\ntype SearchOutput = z.infer<typeof GrepOutputSchema>;\ntype SearchMatchPayload = NonNullable<SearchOutput['matches']>[number];\ntype SearchResultValue = Awaited<ReturnType<typeof searchContent>>;\n/** The engine's own summary is the page metadata; nothing is copied out of it. */\ntype SearchContentPageMetadata = SearchResultValue['summary'];\n\nconst GrepInputSchema = z.strictObject({\n path: OptionalPath.describe(\n 'File to search, or directory to search under (default: the whole first allowed root). Naming a file searches that file alone: pattern is ignored and hidden/ignored filtering does not apply.',\n ),\n pattern: SafeGlobPattern.optional().describe(\n 'Glob to restrict search to specific file types (e.g. **/*.ts); default: all text files',\n ),\n searchPattern: z\n .string()\n .min(1)\n .max(10000)\n .refine((val) => !isBlank(val), {\n message: 'searchPattern cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text or RE2 regex pattern to search for in file contents. When isRegex=true, uses RE2 syntax (no lookahead, lookbehind, or backreferences). Cannot be empty or whitespace-only.',\n )\n .meta({ examples: ['TODO', 'function\\\\s+(\\\\w+)', 'import.*from'] }),\n isRegex: defaultFalseBoolean('Treat searchPattern as a regex (default: literal text match)'),\n includeHidden: IncludeHidden,\n includeIgnored: IncludeIgnored,\n caseSensitive: defaultFalseBoolean('Enable case-sensitive matching (default: case-insensitive)'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_CONTENT_RESULTS)\n .describe('Maximum number of matching lines to return per page'),\n context: z\n .uint32()\n .max(10)\n .optional()\n .default(0)\n .describe(\n 'Lines of context to return either side of each match, like grep -C (default: 0, max: 10)',\n ),\n maxDepth: MaxDepth,\n cursor: CursorSchema,\n});\n\nconst GrepOutputSchema = z.strictObject({\n matches: z\n .array(\n z.strictObject({\n file: z.string().describe('File path relative to the search root'),\n line: PositiveInt.describe('1-indexed line number of the match'),\n column: NonNegInt.optional().describe('0-indexed column offset of the match start'),\n content: z.string().describe('Full text of the matching line'),\n matchCount: NonNegInt.optional().describe('Number of pattern occurrences on this line'),\n before: z\n .array(z.string())\n .optional()\n .describe('Lines immediately before the match; present when context > 0'),\n after: z\n .array(z.string())\n .optional()\n .describe('Lines immediately after the match; present when context > 0'),\n }),\n )\n .describe('Flat list of matches sorted by file path then line number'),\n totalMatches: NonNegInt.optional().describe(\n \"Total matching lines, one per entry in matches (not per occurrence); see that entry's matchCount for occurrences on a line.\",\n ),\n filesMatched: NonNegInt.optional().describe('Number of files containing at least one match'),\n filesScanned: NonNegInt.optional().describe('Total number of files examined'),\n skippedInaccessible: NonNegInt.optional().describe(\n 'Files skipped unread due to permission or access errors',\n ),\n skippedTooLarge: NonNegInt.optional().describe(\n 'Files skipped unread because they exceed the text-file size limit; raise the limit or narrow pattern if a match was expected in one',\n ),\n skippedBinary: NonNegInt.optional().describe('Files skipped because they are binary'),\n truncated: z\n .boolean()\n .optional()\n .describe(\n 'True when the search engine cut the match list — the hard result cap or the time limit. Paging is not truncation: a set that spans pages has nextCursor instead.',\n ),\n stoppedReason: SearchStoppedReasonSchema.describe(\n 'Why the search ended early: maxResults = result cap reached, timeout = time limit hit or the request was cancelled. Absent when the scan ran to completion.',\n ),\n resourceUri: z\n .string()\n .optional()\n .describe(\n 'URI to the full match list in the resource store; first page only, whenever the response is incomplete — more pages follow, or the engine cut the search',\n ),\n nextCursor: NextCursorSchema,\n});\n\nfunction matchRow(m: SearchMatchPayload): string {\n return `${m.file}:${String(m.line)}: ${m.content}`;\n}\n\n/**\n * grep -C layout: `file-line- text` for a context line, `--` between groups\n * that are not adjacent. Every match's window lands in a per-file line map\n * where a match wins over context, so a line two windows share prints once,\n * and as a match when it is one. The maps iterate in line order without a\n * sort: matches arrive sorted, each window is contiguous, and setting an\n * existing key keeps its slot. Without context the rows are the bare match\n * lines, byte-identical to before the option existed.\n */\nfunction renderRows(matches: readonly SearchMatchPayload[], withContext: boolean): string[] {\n if (!withContext) return matches.map(matchRow);\n const byFile = new Map<string, Map<number, string>>();\n for (const m of matches) {\n const lines = byFile.get(m.file) ?? new Map<number, string>();\n byFile.set(m.file, lines);\n const setContext = (n: number, text: string): void => {\n if (!lines.has(n)) lines.set(n, `${m.file}-${String(n)}- ${text}`);\n };\n const before = m.before ?? [];\n before.forEach((text, k) => {\n setContext(m.line - before.length + k, text);\n });\n lines.set(m.line, matchRow(m));\n (m.after ?? []).forEach((text, k) => {\n setContext(m.line + 1 + k, text);\n });\n }\n const rows: string[] = [];\n for (const lines of byFile.values()) {\n let prev: number | undefined;\n for (const [n, row] of lines) {\n if (prev === undefined ? rows.length > 0 : n > prev + 1) rows.push('--');\n rows.push(row);\n prev = n;\n }\n }\n return rows;\n}\n\nfunction buildSearchMatchDetail(totalMatches: number, filesMatched: number): string {\n const matchDetail = formatCount(totalMatches, 'match', 'matches');\n if (filesMatched <= 0) return matchDetail;\n return `${matchDetail} · ${formatCount(filesMatched, 'file', 'files')}`;\n}\n\nfunction searchContentOutput(\n matches: readonly SearchMatchPayload[],\n metadata: SearchContentPageMetadata,\n nextCursor: string | undefined,\n resourceUri: string | undefined,\n): SearchOutput {\n return {\n matches: [...matches],\n totalMatches: metadata.matchingLines,\n filesScanned: metadata.filesScanned,\n ...(metadata.filesMatched ? { filesMatched: metadata.filesMatched } : {}),\n ...(metadata.truncated ? { truncated: true } : {}),\n ...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),\n ...(metadata.skippedInaccessible ? { skippedInaccessible: metadata.skippedInaccessible } : {}),\n ...(metadata.skippedTooLarge ? { skippedTooLarge: metadata.skippedTooLarge } : {}),\n ...(metadata.skippedBinary ? { skippedBinary: metadata.skippedBinary } : {}),\n ...(resourceUri !== undefined ? { resourceUri } : {}),\n ...(nextCursor !== undefined ? { nextCursor } : {}),\n };\n}\n\nfunction buildSortedPayloads(result: SearchResultValue): SearchMatchPayload[] {\n const relativeByFile = new Map<string, string>();\n\n const getRelativeFile = (file: string): string => {\n const cached = relativeByFile.get(file);\n if (cached !== undefined) return cached;\n\n const rel = toPosixRelative(result.basePath, file);\n relativeByFile.set(file, rel);\n return rel;\n };\n\n const payloads = result.matches.map((match): SearchMatchPayload => ({\n file: getRelativeFile(match.file),\n line: match.line,\n column: match.column,\n content: match.content,\n matchCount: match.matchCount,\n ...(match.before !== undefined ? { before: match.before } : {}),\n ...(match.after !== undefined ? { after: match.after } : {}),\n }));\n\n payloads.sort((l, r) => l.file.localeCompare(r.file) || l.line - r.line);\n return payloads;\n}\n\n/**\n * `path` is documented as \"file to search, or directory to search under\", but\n * the scan itself only walks directories. A file path is therefore rewritten\n * into the scan it means: its parent as the base, its own name as the glob.\n * Naming a file is an explicit request for that file, so hidden/ignored\n * filtering is lifted for it — otherwise `search_text` on a path the caller can\n * see returned nothing.\n */\nasync function resolveSearchScope(\n args: SearchInput,\n ctx: ToolCtx,\n): Promise<{ basePath: string; args: SearchInput }> {\n const requested = ctx.fs.pathGuard.resolvePathOrRoot(args.path);\n // One resolution, one stat: validateExistingDirectory would redo both.\n const resolved = await ctx.fs.pathGuard.validateExistingPath(requested);\n const stats = await stat(resolved);\n if (!stats.isFile()) {\n if (!stats.isDirectory()) {\n throw new FsError(ErrorCode.NOT_DIRECTORY, 'Not a directory', requested);\n }\n return { basePath: resolved, args };\n }\n return {\n basePath: dirname(resolved),\n // The `./` anchors the name to the parent: a bare name is a basename glob\n // that would also match every namesake anywhere below it.\n // ponytail: the name goes through as a glob, so a file whose name contains\n // glob metacharacters (`[id].ts`) matches as a pattern rather than\n // literally. Escape it here if that ever bites.\n args: {\n ...args,\n pattern: `./${basename(resolved)}`,\n includeHidden: true,\n includeIgnored: true,\n },\n };\n}\n\nasync function handleSearchContent(\n args: SearchInput,\n ctx: ToolCtx,\n): Promise<{\n structured: SearchOutput;\n offset: number;\n total: number;\n link?: ReturnType<typeof putJsonResource>['link'];\n}> {\n const requestedPath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);\n const queryKey = JSON.stringify({\n method: 'search_text',\n path: requestedPath,\n pattern: args.pattern,\n searchPattern: args.searchPattern,\n isRegex: args.isRegex,\n includeHidden: args.includeHidden,\n includeIgnored: args.includeIgnored,\n caseSensitive: args.caseSensitive,\n maxDepth: args.maxDepth,\n context: args.context,\n });\n const { resourceStore } = ctx;\n\n const paged = await paginate<SearchMatchPayload, SearchContentPageMetadata, JsonResourceResult>({\n store: ctx.pageStore,\n queryKey,\n cursor: args.cursor,\n pageSize: args.maxResults,\n produce: async () => {\n const { basePath, args: scoped } = await resolveSearchScope(args, ctx);\n\n const result = await searchContent(\n basePath,\n scoped.searchPattern,\n {\n includeHidden: scoped.includeHidden,\n filePattern: scoped.pattern ?? '**/*',\n caseSensitive: scoped.caseSensitive,\n isRegex: scoped.isRegex,\n maxResults: MAX_SEARCH_RESULTS,\n skipIgnored: !scoped.includeIgnored,\n context: scoped.context,\n ...(scoped.maxDepth !== undefined ? { maxDepth: scoped.maxDepth } : {}),\n signal: ctx.signal,\n },\n ctx.fs.pathGuard,\n );\n\n return {\n items: buildSortedPayloads(result),\n metadata: result.summary,\n truncated: result.summary.truncated,\n };\n },\n externalize: resourceStore\n ? (matches, metadata) =>\n putJsonResource(\n resourceStore,\n `'${args.searchPattern}' matches`,\n searchContentOutput(matches, metadata, undefined, undefined),\n )\n : undefined,\n });\n\n return {\n structured: searchContentOutput(\n paged.page,\n paged.metadata,\n paged.nextCursor,\n paged.resource?.entry.uri,\n ),\n offset: paged.offset,\n total: paged.metadata.matchingLines,\n ...(paged.resource ? { link: paged.resource.link } : {}),\n };\n}\n\nexport const SEARCH_TEXT = defineTool({\n name: 'search_text',\n title: 'Search Content',\n description:\n 'Search file contents for literal text or an RE2 regex, like grep; returns matching lines with line numbers ' +\n 'and paths relative to the searched directory. Patterns match within one line. find_files matches file names.',\n input: GrepInputSchema,\n output: GrepOutputSchema,\n annotations: {\n readOnlyHint: true,\n openWorldHint: false,\n },\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n progress: (args) => ({\n label: 'Search',\n subject: truncateProgressPattern(args.searchPattern),\n }),\n progressDone: (_args, result) => ({\n detail: buildSearchMatchDetail(result.totalMatches ?? 0, result.filesMatched ?? 0),\n }),\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const { structured, offset, total, link } = await handleSearchContent(args, ctx);\n const rows = renderRows(structured.matches, args.context > 0);\n const body = rows.length > 0 ? rows.join('\\n') : `No matches for '${args.searchPattern}'`;\n const text =\n body +\n pageTrailer({\n offset,\n shown: structured.matches.length,\n total,\n noun: 'matches',\n tool: 'search_text',\n nextCursor: structured.nextCursor,\n nextArgs: args,\n stoppedReason: structured.stoppedReason,\n skippedTooLarge: structured.skippedTooLarge,\n skippedInaccessible: structured.skippedInaccessible,\n });\n if (link) {\n return { structured, text, resources: [link] };\n }\n return { structured, text };\n },\n});\n"]}
1
+ {"version":3,"file":"search-text.js","sourceRoot":"","sources":["../../src/tools/search-text.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from 'node:fs/promises';\nimport { dirname } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { paginate } from '../core/cursor.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { formatCount, pageTrailer, truncateProgressPattern } from '../core/fmt.ts';\nimport { toPosixRelative } from '../core/path.ts';\nimport {\n CursorSchema,\n defaultFalseBoolean,\n IncludeHidden,\n IncludeIgnored,\n isBlank,\n MaxDepth,\n OptionalPath,\n SafeGlobPattern,\n} from '../core/schema.ts';\nimport { searchContent } from '../core/search.ts';\nimport type { JsonResourceResult } from '../core/store.ts';\nimport { putJsonResource } from '../core/store.ts';\nimport {\n DEFAULT_SEARCH_CONTENT_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n MAX_SEARCH_RESULTS,\n} from '../core/util.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\n// Type Definitions\ntype SearchInput = z.infer<typeof GrepInputSchema>;\ntype SearchResultValue = Awaited<ReturnType<typeof searchContent>>;\ntype SearchMatchPayload = SearchResultValue['matches'][number];\n/** The engine's own summary is the page metadata; nothing is copied out of it. */\ntype SearchContentPageMetadata = SearchResultValue['summary'];\n\nconst GrepInputSchema = z.strictObject({\n path: OptionalPath.describe(\n 'File to search, or directory to search under (default: the whole first allowed root). Naming a file searches that file alone: pattern is ignored and hidden/ignored filtering does not apply.',\n ),\n pattern: SafeGlobPattern.optional().describe(\n 'Glob to restrict search to specific file types (e.g. **/*.ts); default: all text files',\n ),\n searchPattern: z\n .string()\n .min(1)\n .max(10000)\n .refine((val) => !isBlank(val), {\n message: 'searchPattern cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text or RE2 regex pattern to search for in file contents. When isRegex=true, uses RE2 syntax (no lookahead, lookbehind, or backreferences). Cannot be empty or whitespace-only.',\n )\n .meta({ examples: ['TODO', 'function\\\\s+(\\\\w+)', 'import.*from'] }),\n isRegex: defaultFalseBoolean('Treat searchPattern as a regex (default: literal text match)'),\n includeHidden: IncludeHidden,\n includeIgnored: IncludeIgnored,\n caseSensitive: defaultFalseBoolean('Enable case-sensitive matching (default: case-insensitive)'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_CONTENT_RESULTS)\n .describe('Maximum number of matching lines to return per page'),\n context: z\n .uint32()\n .max(10)\n .optional()\n .default(0)\n .describe(\n 'Lines of context to return either side of each match, like grep -C (default: 0, max: 10)',\n ),\n maxDepth: MaxDepth,\n cursor: CursorSchema,\n});\n\ninterface SearchOutput {\n matches: SearchMatchPayload[];\n totalMatches?: number;\n filesMatched?: number;\n filesScanned?: number;\n skippedInaccessible?: number;\n skippedTooLarge?: number;\n skippedBinary?: number;\n truncated?: boolean;\n stoppedReason?: 'maxResults' | 'timeout';\n resourceUri?: string;\n nextCursor?: string;\n}\n\nfunction matchRow(m: SearchMatchPayload): string {\n return `${m.file}:${String(m.line)}: ${m.content}`;\n}\n\n/**\n * grep -C layout: `file-line- text` for a context line, `--` between groups\n * that are not adjacent. Every match's window lands in a per-file line map\n * where a match wins over context, so a line two windows share prints once,\n * and as a match when it is one. The maps iterate in line order without a\n * sort: matches arrive sorted, each window is contiguous, and setting an\n * existing key keeps its slot. Without context the rows are the bare match\n * lines, byte-identical to before the option existed.\n */\nfunction renderRows(matches: readonly SearchMatchPayload[], withContext: boolean): string[] {\n if (!withContext) return matches.map(matchRow);\n const byFile = new Map<string, Map<number, string>>();\n for (const m of matches) {\n const lines = byFile.get(m.file) ?? new Map<number, string>();\n byFile.set(m.file, lines);\n const setContext = (n: number, text: string): void => {\n if (!lines.has(n)) lines.set(n, `${m.file}-${String(n)}- ${text}`);\n };\n const before = m.before ?? [];\n before.forEach((text, k) => {\n setContext(m.line - before.length + k, text);\n });\n lines.set(m.line, matchRow(m));\n (m.after ?? []).forEach((text, k) => {\n setContext(m.line + 1 + k, text);\n });\n }\n const rows: string[] = [];\n for (const lines of byFile.values()) {\n let prev: number | undefined;\n for (const [n, row] of lines) {\n if (prev === undefined ? rows.length > 0 : n > prev + 1) rows.push('--');\n rows.push(row);\n prev = n;\n }\n }\n return rows;\n}\n\nfunction buildSearchMatchDetail(totalMatches: number, filesMatched: number): string {\n const matchDetail = formatCount(totalMatches, 'match', 'matches');\n if (filesMatched <= 0) return matchDetail;\n return `${matchDetail} · ${formatCount(filesMatched, 'file', 'files')}`;\n}\n\nfunction searchContentOutput(\n matches: readonly SearchMatchPayload[],\n metadata: SearchContentPageMetadata,\n nextCursor: string | undefined,\n resourceUri: string | undefined,\n): SearchOutput {\n return {\n matches: [...matches],\n totalMatches: metadata.matchingLines,\n filesScanned: metadata.filesScanned,\n ...(metadata.filesMatched ? { filesMatched: metadata.filesMatched } : {}),\n ...(metadata.truncated ? { truncated: true } : {}),\n ...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),\n ...(metadata.skippedInaccessible ? { skippedInaccessible: metadata.skippedInaccessible } : {}),\n ...(metadata.skippedTooLarge ? { skippedTooLarge: metadata.skippedTooLarge } : {}),\n ...(metadata.skippedBinary ? { skippedBinary: metadata.skippedBinary } : {}),\n ...(resourceUri !== undefined ? { resourceUri } : {}),\n ...(nextCursor !== undefined ? { nextCursor } : {}),\n };\n}\n\nfunction buildSortedPayloads(result: SearchResultValue): SearchMatchPayload[] {\n const relativeByFile = new Map<string, string>();\n\n const getRelativeFile = (file: string): string => {\n const cached = relativeByFile.get(file);\n if (cached !== undefined) return cached;\n\n const rel = toPosixRelative(result.basePath, file);\n relativeByFile.set(file, rel);\n return rel;\n };\n\n const payloads = result.matches.map((match): SearchMatchPayload => ({\n file: getRelativeFile(match.file),\n line: match.line,\n column: match.column,\n content: match.content,\n matchCount: match.matchCount,\n ...(match.before !== undefined ? { before: match.before } : {}),\n ...(match.after !== undefined ? { after: match.after } : {}),\n }));\n\n payloads.sort((l, r) => l.file.localeCompare(r.file) || l.line - r.line);\n return payloads;\n}\n\n/** Explicit files bypass glob filtering; their parent anchors the relative result paths. */\nasync function resolveSearchScope(\n path: string | undefined,\n ctx: ToolCtx,\n): Promise<{ basePath: string; explicitFile?: string }> {\n const requested = ctx.fs.pathGuard.resolvePathOrRoot(path);\n // One resolution, one stat: validateExistingDirectory would redo both.\n const resolved = await ctx.fs.pathGuard.validateExistingPath(requested);\n const stats = await stat(resolved);\n if (!stats.isFile()) {\n if (!stats.isDirectory()) {\n throw new FsError(ErrorCode.NOT_DIRECTORY, 'Not a directory', requested);\n }\n return { basePath: resolved };\n }\n return {\n basePath: dirname(resolved),\n // The name is NOT turned into a glob: `[slug].tsx` would read as a\n // character class. searchContent scans exactly this file instead, and\n // hidden/ignored filtering is moot for a file the caller named.\n explicitFile: resolved,\n };\n}\n\nasync function handleSearchContent(\n args: SearchInput,\n ctx: ToolCtx,\n): Promise<{\n structured: SearchOutput;\n offset: number;\n total: number;\n link?: ReturnType<typeof putJsonResource>['link'];\n}> {\n const requestedPath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);\n const queryKey = JSON.stringify({\n method: 'search_text',\n path: requestedPath,\n pattern: args.pattern,\n searchPattern: args.searchPattern,\n isRegex: args.isRegex,\n includeHidden: args.includeHidden,\n includeIgnored: args.includeIgnored,\n caseSensitive: args.caseSensitive,\n maxDepth: args.maxDepth,\n context: args.context,\n });\n const paged = await paginate<SearchMatchPayload, SearchContentPageMetadata, JsonResourceResult>({\n store: ctx.pageStore,\n queryKey,\n cursor: args.cursor,\n pageSize: args.maxResults,\n produce: async () => {\n const { basePath, explicitFile } = await resolveSearchScope(args.path, ctx);\n\n const result = await searchContent(\n basePath,\n args.searchPattern,\n {\n includeHidden: args.includeHidden,\n filePattern: args.pattern ?? '**/*',\n caseSensitive: args.caseSensitive,\n isRegex: args.isRegex,\n maxResults: MAX_SEARCH_RESULTS,\n skipIgnored: !args.includeIgnored,\n context: args.context,\n ...(explicitFile !== undefined ? { explicitFile } : {}),\n ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),\n signal: ctx.signal,\n },\n ctx.fs.pathGuard,\n );\n\n return {\n items: buildSortedPayloads(result),\n metadata: result.summary,\n truncated: result.summary.truncated,\n };\n },\n externalize: (matches, metadata) =>\n putJsonResource(ctx.resourceStore, `'${args.searchPattern}' matches`, {\n ...searchContentOutput(matches, metadata, undefined, undefined),\n }),\n });\n\n return {\n structured: searchContentOutput(\n paged.page,\n paged.metadata,\n paged.nextCursor,\n paged.resource?.entry.uri,\n ),\n offset: paged.offset,\n total: paged.metadata.matchingLines,\n ...(paged.resource ? { link: paged.resource.link } : {}),\n };\n}\n\nexport const SEARCH_TEXT = defineTool<typeof GrepInputSchema, SearchOutput>({\n name: 'search_text',\n title: 'Search Content',\n description:\n 'Search file contents for literal text or an RE2 regex, like grep; returns matching lines with line numbers ' +\n 'and paths relative to the searched directory. Patterns match within one line. find_files matches file names.',\n input: GrepInputSchema,\n readOnlyHint: true,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n progress: (args) => ({\n label: 'Search',\n subject: truncateProgressPattern(args.searchPattern),\n }),\n progressDone: (_args, result) => ({\n detail: buildSearchMatchDetail(result.totalMatches ?? 0, result.filesMatched ?? 0),\n }),\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const { structured, offset, total, link } = await handleSearchContent(args, ctx);\n const rows = renderRows(structured.matches, args.context > 0);\n const body = rows.length > 0 ? rows.join('\\n') : `No matches for '${args.searchPattern}'`;\n const text =\n body +\n pageTrailer({\n offset,\n shown: structured.matches.length,\n total,\n noun: 'matches',\n tool: 'search_text',\n nextCursor: structured.nextCursor,\n nextArgs: args,\n stoppedReason: structured.stoppedReason,\n skippedTooLarge: structured.skippedTooLarge,\n skippedInaccessible: structured.skippedInaccessible,\n });\n if (link) {\n return { structured, text, resources: [link] };\n }\n return { structured, text };\n },\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"stat.d.ts","sourceRoot":"","sources":["../../src/tools/stat.ts"],"names":[],"mappings":"AAoJA,eAAO,MAAM,IAAI,mCA2Cf,CAAC"}
1
+ {"version":3,"file":"stat.d.ts","sourceRoot":"","sources":["../../src/tools/stat.ts"],"names":[],"mappings":"AA+IA,eAAO,MAAM,IAAI,mCAoCf,CAAC"}
@@ -1,22 +1,12 @@
1
1
  import { parse } from 'node:path';
2
- import * as z from 'zod/v4';
3
2
  import { ErrorCode, rethrowIfAborted } from "../core/errors.js";
4
3
  import { detectMimeType } from "../core/mime.js";
5
4
  import { resolveEntryType } from "../core/path-utils.js";
6
- import { FileInfoSchema, NonNegInt, OperationSummarySchema, perPathEnvelope, singleOrBatchAccessPaths, singleOrBatchPathsInput, } from "../core/schema.js";
5
+ import { singleOrBatchAccessPaths, singleOrBatchPathsInput } from "../core/schema.js";
7
6
  import { DEFAULT_SEARCH_TIMEOUT_MS } from "../core/util.js";
8
7
  import { isTotalFailure, runOverPaths } from "./batch.js";
9
8
  import { defineTool } from "./define.js";
10
9
  const StatInputSchema = singleOrBatchPathsInput({});
11
- const StatPerPathSchema = perPathEnvelope(FileInfoSchema, 'File metadata; present on success');
12
- const StatOutputSchema = z.strictObject({
13
- results: z
14
- .array(StatPerPathSchema)
15
- .describe('Per-path metadata results ordered to match the input paths'),
16
- summary: OperationSummarySchema,
17
- fileCount: NonNegInt.optional().describe('Number of regular files in the results'),
18
- dirCount: NonNegInt.optional().describe('Number of directories in the results'),
19
- });
20
10
  function getPermissions(mode) {
21
11
  let out = '';
22
12
  for (const shift of [6, 3, 0]) {
@@ -74,7 +64,7 @@ async function getFileInfo(filePath, { signal, fs, log }) {
74
64
  // root that is itself a symlink, whose parent sits outside the roots).
75
65
  // Falling back to the followed stats degrades the report to the target's
76
66
  // metadata, so leave a trace instead of degrading silently.
77
- log?.('warning', `stat: lstat failed for "${requestedPath}": ${String(error)}`, 'stat');
67
+ log('warning', `stat: lstat failed for "${requestedPath}": ${String(error)}`, 'stat');
78
68
  stats = followedStats;
79
69
  }
80
70
  }
@@ -108,11 +98,7 @@ export const STAT = defineTool({
108
98
  'tokenEstimate, timestamps, permissions, MIME type guessed from the extension, and symlink target. ' +
109
99
  'Also checks whether paths exist.',
110
100
  input: StatInputSchema,
111
- output: StatOutputSchema,
112
- annotations: {
113
- readOnlyHint: true,
114
- openWorldHint: false,
115
- },
101
+ readOnlyHint: true,
116
102
  timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
117
103
  defaultErrorCode: ErrorCode.NOT_FOUND,
118
104
  progress: (args) => {
@@ -123,8 +109,8 @@ export const STAT = defineTool({
123
109
  },
124
110
  accessPaths: singleOrBatchAccessPaths,
125
111
  run: async (args, ctx) => {
126
- const batchInput = args.path !== undefined ? { path: args.path } : { paths: args.paths ?? [] };
127
- const batch = await runOverPaths(batchInput, ctx, ErrorCode.NOT_FOUND, async ({ path }) => getFileInfo(path, ctx));
112
+ const paths = args.path !== undefined ? [args.path] : (args.paths ?? []);
113
+ const batch = await runOverPaths(paths, ctx, ErrorCode.NOT_FOUND, async (path) => getFileInfo(path, ctx));
128
114
  const { fileCount, dirCount } = classifyTypeCounts(batch.results);
129
115
  // No `text` on purpose. The one-liner this used to build (`AGENTS.md: file,
130
116
  // 751 B`) dropped tokenEstimate, modified, mimeType and isHidden — the very