@j0hanz/filesystem-mcp 2.7.5 → 2.8.0
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.
- package/README.md +290 -394
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +15 -7
- package/dist/cli-help.js.map +1 -1
- package/dist/cli.d.ts +1 -9
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/concurrency.d.ts +7 -0
- package/dist/core/concurrency.d.ts.map +1 -1
- package/dist/core/concurrency.js +19 -0
- package/dist/core/concurrency.js.map +1 -1
- package/dist/core/errors.d.ts +4 -3
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +5 -16
- package/dist/core/errors.js.map +1 -1
- package/dist/core/fs.d.ts +19 -11
- package/dist/core/fs.d.ts.map +1 -1
- package/dist/core/fs.js +168 -53
- package/dist/core/fs.js.map +1 -1
- package/dist/core/glob.d.ts +8 -0
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/glob.js +192 -29
- package/dist/core/glob.js.map +1 -1
- package/dist/core/input-required.d.ts +12 -0
- package/dist/core/input-required.d.ts.map +1 -1
- package/dist/core/input-required.js +7 -2
- package/dist/core/input-required.js.map +1 -1
- package/dist/core/observability.d.ts +2 -0
- package/dist/core/observability.d.ts.map +1 -1
- package/dist/core/observability.js +7 -0
- package/dist/core/observability.js.map +1 -1
- package/dist/core/path-completer.d.ts.map +1 -1
- package/dist/core/path-completer.js +11 -30
- package/dist/core/path-completer.js.map +1 -1
- package/dist/core/path.d.ts +7 -18
- package/dist/core/path.d.ts.map +1 -1
- package/dist/core/path.js +22 -55
- package/dist/core/path.js.map +1 -1
- package/dist/core/read.d.ts +4 -1
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +25 -16
- package/dist/core/read.js.map +1 -1
- package/dist/core/schema.d.ts +6 -1
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +17 -3
- package/dist/core/schema.js.map +1 -1
- package/dist/core/search.d.ts +7 -0
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +154 -66
- package/dist/core/search.js.map +1 -1
- package/dist/core/store.d.ts +36 -1
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +71 -6
- package/dist/core/store.js.map +1 -1
- package/dist/core/util.d.ts +37 -0
- package/dist/core/util.d.ts.map +1 -1
- package/dist/core/util.js +62 -0
- package/dist/core/util.js.map +1 -1
- package/dist/index.js +5 -16
- package/dist/index.js.map +1 -1
- package/dist/resources.d.ts +5 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +45 -22
- package/dist/resources.js.map +1 -1
- package/dist/server.d.ts +10 -5
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -8
- package/dist/server.js.map +1 -1
- package/dist/tools/create.d.ts.map +1 -1
- package/dist/tools/create.js +93 -90
- package/dist/tools/create.js.map +1 -1
- package/dist/tools/define.d.ts +10 -6
- package/dist/tools/define.d.ts.map +1 -1
- package/dist/tools/define.js +49 -16
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/delete.d.ts.map +1 -1
- package/dist/tools/delete.js +39 -21
- package/dist/tools/delete.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +37 -39
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +49 -60
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/index.d.ts +2 -10
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -8
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list.d.ts.map +1 -1
- package/dist/tools/list.js +59 -69
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/move.d.ts.map +1 -1
- package/dist/tools/move.js +39 -5
- package/dist/tools/move.js.map +1 -1
- package/dist/tools/patch.d.ts.map +1 -1
- package/dist/tools/patch.js +88 -86
- package/dist/tools/patch.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +30 -24
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/replace-text.d.ts.map +1 -1
- package/dist/tools/replace-text.js +60 -46
- package/dist/tools/replace-text.js.map +1 -1
- package/dist/tools/search-text.d.ts.map +1 -1
- package/dist/tools/search-text.js +48 -64
- package/dist/tools/search-text.js.map +1 -1
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +2 -1
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/shared.d.ts +7 -5
- package/dist/transport/shared.d.ts.map +1 -1
- package/dist/transport/shared.js +8 -2
- package/dist/transport/shared.js.map +1 -1
- package/dist/transport/stdio.d.ts +4 -1
- package/dist/transport/stdio.d.ts.map +1 -1
- package/dist/transport/stdio.js +46 -12
- package/dist/transport/stdio.js.map +1 -1
- package/package.json +3 -2
package/dist/tools/edit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { diffStatsFromPatch, unifiedPatch } from '../core/diff.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { buildWrittenFileMeta, type WrittenFileMeta } from '../core/file-uri.ts';\nimport { joinRoster, truncateProgressPattern } from '../core/fmt.ts';\nimport { isSamePath } from '../core/path-utils.ts';\nimport {\n defaultFalseBoolean,\n isBlank,\n RequiredPath,\n singleOrBatchAccessPaths,\n} from '../core/schema.ts';\nimport { compileRegex, execMatches, freeRegex } from '../core/search.ts';\nimport { escapeRegExp } from '../core/util.ts';\nimport { type BatchResult, isTotalFailure, type PerPathResult, runOverPaths } from './batch.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\nconst EditSpecSchema = z.strictObject({\n oldText: z\n .string()\n .min(1, 'oldText required')\n .refine((val) => !isBlank(val), {\n message: 'oldText cannot be empty or whitespace-only',\n })\n .describe(\n 'Exact literal text to locate in the file; it must match exactly once. Include 3-5 lines of context so it does — an oldText found in several places fails with their line numbers.',\n )\n .meta({ examples: ['const x = 1;', 'function oldName('] }),\n newText: z\n .string()\n .describe('Replacement text. Use an empty string to delete the matched oldText.')\n .meta({ examples: ['const x = 2;', 'function newName(', ''] }),\n});\n// No `id`, so no `$defs`/`$ref`: this subschema is inlined at both `edits` and\n// `files[].edits`. Hoisting it saved ~1.3 kB, but clients whose schema\n// converter cannot follow a `$ref` fell back to an opaque pass-through for\n// `edit` alone and sent its arguments as a serialized string (issue #51).\n\nconst MAX_MULTI_FILES = 5;\nconst MAX_EDITS_PER_FILE = 100;\n\nconst EditFileInputSchema = z\n .strictObject({\n path: RequiredPath.optional().describe('Single file path; mutually exclusive with files'),\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .optional()\n .describe('Replacements applied to path; not allowed when using files'),\n files: z\n .array(\n z.strictObject({\n path: RequiredPath,\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .describe('Replacements to apply to this specific file'),\n }),\n )\n .min(1)\n .max(MAX_MULTI_FILES)\n .optional()\n .describe('Per-file entries (batch mode)'),\n dryRun: defaultFalseBoolean(\n 'Preview diffs without writing to disk (default: false = apply edits)',\n ),\n ignoreWhitespace: defaultFalseBoolean(\n 'Ignore leading/trailing whitespace differences when matching oldText',\n ),\n })\n .superRefine((value, ctx) => {\n const hasPath = value.path !== undefined;\n const hasFiles = value.files !== undefined;\n if (hasPath === hasFiles) {\n ctx.addIssue({\n code: 'custom',\n path: ['path'],\n message: \"Provide exactly one of 'path' or 'files'\",\n input: value,\n });\n }\n if (hasPath && value.edits === undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' required when using 'path'\",\n input: value,\n });\n }\n if (hasFiles && value.edits !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' not allowed with 'files'; each file carries its own edits\",\n input: value,\n });\n }\n // Batch entries run in parallel and each rewrites its file whole, so two\n // entries for one file race: the last write wins and the other's edits are\n // lost while both report success. One entry per file.\n const files = value.files ?? [];\n for (const [index, file] of files.entries()) {\n const first = files.findIndex((other) => isSamePath(other.path, file.path));\n if (first < index) {\n ctx.addIssue({\n code: 'custom',\n path: ['files', index, 'path'],\n message: `duplicate of files[${String(first)}].path; put every edit for one file in a single entry`,\n input: value,\n });\n }\n }\n })\n // Mirror the superRefine on the wire: exactly one input mode, and single-file\n // mode carries its own `edits`. Without `edits` in the first branch, `{ path }`\n // alone validated against the published schema and was then rejected at\n // runtime — the model had no way to see that coming.\n .meta({ oneOf: [{ required: ['path', 'edits'] }, { required: ['files'] }] });\n\ntype EditFileValue = Omit<WrittenFileMeta, 'resourceUri' | 'resourceLink'> & {\n path: string;\n resourceUri?: string;\n modified: string;\n appliedEdits: number;\n linesAdded?: number;\n linesRemoved?: number;\n diff?: string;\n unmatchedEdits?: string[];\n};\n\ninterface TextRange {\n startIndex: number;\n length: number;\n}\n\ninterface EditResult {\n content: string;\n appliedEdits: number;\n unmatchedEdits: string[];\n linesAdded?: number;\n linesRemoved?: number;\n diff?: string;\n}\n\nconst MAX_REPORTED_MATCH_LINES = 5;\n\ninterface EditMatches {\n /** The first match; undefined when oldText matches nothing. */\n first: TextRange | undefined;\n count: number;\n /** UTF-16 start offsets of the first {@link MAX_REPORTED_MATCH_LINES} matches. */\n starts: number[];\n}\n\n/**\n * Pattern for a whitespace run of oldText that contains a newline. Between two\n * pieces of text it stays flexible — at least one newline, as many as the file\n * has. At either edge of oldText it matches exactly the newlines written: a\n * flexible edge swallows the blank lines around the match and, at the trailing\n * edge, the next line's indentation, all of which newText then replaces. Each\n * newline may carry horizontal whitespace before it, which covers the `\\r` of\n * a CRLF file and a blank line with stray spaces.\n */\nfunction newlineRunPattern(token: string, edge: { leading: boolean; trailing: boolean }): string {\n if (!edge.leading && !edge.trailing) return '(?:[^\\\\S\\\\n]*\\\\n)+[^\\\\S\\\\n]*';\n const count = token.split('\\n').length - 1;\n const lines = `(?:[^\\\\S\\\\n]*\\\\n){${String(count)}}`;\n // Nothing after the final newline unless the caller wrote indentation there.\n return edge.trailing && token.endsWith('\\n') ? lines : `${lines}[^\\\\S\\\\n]*`;\n}\n\n/**\n * Where `oldText` matches. `count` is non-overlapping occurrences, except that a\n * lone match with a second one overlapping it counts two (`abab` in `ababab`),\n * since either is a span the caller could have meant — the count is exact only\n * when it answers \"once or not\". Only the count and the first few starts are\n * kept: a short oldText in a large file can match millions of times.\n */\nfunction findEditMatches(content: string, oldText: string, ignoreWhitespace: boolean): EditMatches {\n const found: EditMatches = { first: undefined, count: 0, starts: [] };\n const add = (startIndex: number, length: number): void => {\n found.first ??= { startIndex, length };\n found.count += 1;\n if (found.starts.length < MAX_REPORTED_MATCH_LINES) found.starts.push(startIndex);\n };\n\n if (ignoreWhitespace) {\n // Make whitespace flexible (tolerate indentation/spacing differences)\n // without letting it cross line boundaries: a whitespace run that contains\n // a newline keeps at least one newline, so a single-line oldText cannot\n // match across a newline and a multi-line oldText cannot collapse onto one\n // line. Horizontal whitespace stays mandatory between word characters so\n // adjacent identifiers are not merged. Built token by token: `split` on\n // whitespace puts text at even indices and whitespace runs at odd ones.\n // A newline run at either edge of oldText matches exactly, so the edit\n // cannot reach past the lines the caller named.\n const tokens = oldText.split(/(\\s+)/u);\n const last = tokens.length - 1;\n let pattern = '';\n for (const [i, token] of tokens.entries()) {\n if (i % 2 === 0) {\n pattern += escapeRegExp(token);\n } else if (token.includes('\\n')) {\n pattern += newlineRunPattern(token, {\n leading: i === 1 && tokens[0] === '',\n trailing: i === last - 1 && tokens[last] === '',\n });\n } else if (/\\w$/.test(tokens[i - 1] ?? '') && /^\\w/.test(tokens[i + 1] ?? '')) {\n pattern += '[^\\\\S\\\\n]+';\n } else {\n pattern += '[^\\\\S\\\\n]*';\n }\n }\n const regex = compileRegex(pattern, { caseSensitive: true });\n try {\n // execMatches resets lastIndex and reports UTF-16 offsets; the raw RE2\n // index counts code points and would splice off-by-one per emoji.\n const scan = (from: number): void => {\n for (const match of execMatches(regex, from === 0 ? content : content.slice(from))) {\n // A zero-length match names an empty span, which cannot be replaced.\n if (match.text.length > 0) add(from + match.start, match.text.length);\n if (from > 0) return;\n }\n };\n scan(0);\n // execMatches resumes past each match, so a second match overlapping the\n // first is never reported; look once more from just past its first\n // non-whitespace character. Starting inside the leading whitespace would\n // re-find the same occurrence, since the pattern's leading run is `*`. The\n // pattern carries no anchors, so matching a suffix finds the same spans.\n if (found.count === 1 && found.first) {\n const { startIndex, length } = found.first;\n const lead = content.slice(startIndex, startIndex + length).search(/\\S/u);\n scan(afterCodePoint(content, startIndex + lead));\n }\n } finally {\n // The compiled pattern owns wasm memory re2-wasm never reclaims on its\n // own; its lifetime is this one search.\n freeRegex(regex);\n }\n return found;\n }\n\n // Non-overlapping, so the scan stays linear on repetitive content; the one\n // overlap that matters — a second match inside the only one — is checked after.\n for (\n let i = content.indexOf(oldText);\n i !== -1;\n i = content.indexOf(oldText, i + oldText.length)\n ) {\n add(i, oldText.length);\n }\n if (found.count === 1 && found.first) {\n const overlap = content.indexOf(oldText, afterCodePoint(content, found.first.startIndex));\n if (overlap !== -1) add(overlap, oldText.length);\n }\n return found;\n}\n\n/** The UTF-16 offset just past the code point at `index`, so a surrogate pair is never split. */\nfunction afterCodePoint(content: string, index: number): number {\n return index + ((content.codePointAt(index) ?? 0) > 0xffff ? 2 : 1);\n}\n\nfunction ambiguousEditError(\n content: string,\n found: EditMatches,\n editIndex: number,\n shifted: boolean,\n): FsError {\n const lines = [\n ...new Set(found.starts.map((start) => content.slice(0, start).split('\\n').length)),\n ];\n const label = lines.length === 1 ? 'line' : 'lines';\n const more = found.count > found.starts.length ? ', ...' : '';\n // Offsets come from the content as earlier edits in this call left it, which\n // is not the file the caller read once one of them has applied.\n const where = shifted ? ' after earlier edits' : '';\n return new FsError(\n ErrorCode.INVALID_INPUT,\n `edits[${String(editIndex)}]: oldText matches ${String(found.count)} places${where} ` +\n `(${label} ${lines.join(', ')}${more}). Add surrounding lines so it matches once.`,\n );\n}\n\nfunction buildEditFileValue(\n validPath: string,\n meta: WrittenFileMeta,\n modified: string,\n result: EditResult,\n): EditFileValue {\n return {\n path: validPath,\n size: meta.size,\n lineCount: meta.lineCount,\n mimeType: meta.mimeType,\n kind: meta.kind,\n ...(meta.resourceUri !== undefined ? { resourceUri: meta.resourceUri } : {}),\n modified,\n appliedEdits: result.appliedEdits,\n ...(result.appliedEdits > 0 &&\n result.linesAdded !== undefined &&\n result.linesRemoved !== undefined\n ? { linesAdded: result.linesAdded, linesRemoved: result.linesRemoved }\n : {}),\n ...(result.unmatchedEdits.length > 0 ? { unmatchedEdits: result.unmatchedEdits } : {}),\n ...(result.diff ? { diff: result.diff } : {}),\n };\n}\n\n// A file whose every newline is CRLF gets LF-only edit text converted to match\n// — the rule jsdiff's autoConvertLineEndings applies for `patch`. Range, head\n// and tail reads strip `\\r`, so the oldText a model sends is LF-only; text that\n// already carries a `\\r` is taken as written. Mixed-ending files are not\n// converted: there is no one ending to convert to.\nfunction usesCrlf(content: string): boolean {\n return content.includes('\\r\\n') && !/(?<!\\r)\\n/u.test(content);\n}\n\nfunction toCrlf(text: string): string {\n return text.includes('\\r') ? text : text.replaceAll('\\n', '\\r\\n');\n}\n\nfunction applyEdits(\n content: string,\n edits: z.infer<typeof EditSpecSchema>[],\n ignoreWhitespace: boolean,\n): EditResult {\n let newContent = content;\n let appliedEdits = 0;\n const unmatchedEdits: string[] = [];\n const crlf = usesCrlf(content);\n\n for (const [index, edit] of edits.entries()) {\n const oldText = crlf ? toCrlf(edit.oldText) : edit.oldText;\n const newText = crlf ? toCrlf(edit.newText) : edit.newText;\n const found = findEditMatches(newContent, oldText, ignoreWhitespace);\n\n // A second match is an error rather than a pick: splicing the first would\n // edit a block the caller may not have meant and still report success.\n if (found.count > 1) throw ambiguousEditError(newContent, found, index, appliedEdits > 0);\n\n if (!found.first) {\n unmatchedEdits.push(edit.oldText);\n continue;\n }\n\n const first = found.first;\n newContent =\n newContent.slice(0, first.startIndex) +\n newText +\n newContent.slice(first.startIndex + first.length);\n appliedEdits += 1;\n }\n\n return { content: newContent, appliedEdits, unmatchedEdits };\n}\n\ninterface EditFileOptions {\n dryRun: boolean;\n ignoreWhitespace: boolean;\n}\n\nasync function handleEditFile(\n filePath: string,\n edits: z.infer<typeof EditSpecSchema>[],\n options: EditFileOptions,\n ctx: ToolCtx,\n): Promise<{ file: EditFileValue; resourceLink?: ContentBlock }> {\n const { validPath, content } = await ctx.fs.readEditableText(filePath, {\n signal: ctx.signal,\n });\n const editResult = applyEdits(content, edits, options.ignoreWhitespace);\n // One Myers pass serves both the dry-run preview and the line counts.\n const patch =\n editResult.appliedEdits > 0\n ? unifiedPatch(basename(validPath), content, editResult.content)\n : undefined;\n if (patch !== undefined) Object.assign(editResult, diffStatsFromPatch(patch));\n\n if (options.dryRun) {\n if (patch !== undefined) editResult.diff = patch;\n } else {\n if (editResult.unmatchedEdits.length > 0) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n `no match for oldText ${joinRoster(\n editResult.unmatchedEdits.map((t) => JSON.stringify(truncateProgressPattern(t))),\n ', ',\n )}; it must match the file exactly`,\n filePath,\n );\n }\n\n if (editResult.appliedEdits > 0) {\n await ctx.fs.writeFile(filePath, editResult.content, {\n signal: ctx.signal,\n });\n ctx.log(\n 'info',\n `edit: ${filePath} (${editResult.appliedEdits} edits, +${String(editResult.linesAdded ?? 0)}/-${String(editResult.linesRemoved ?? 0)})`,\n 'edit',\n );\n }\n }\n\n // `modified` is read from a post-write stat and is advisory: under a concurrent\n // writer it may reflect that writer's mtime while `size`/content below come from\n // this edit's atomic write. The file content itself is always consistent. A dry\n // run wrote nothing, so it reports the time of the preview.\n const modified = options.dryRun\n ? new Date().toISOString()\n : (await ctx.fs.stat(filePath, { signal: ctx.signal })).stats.mtime.toISOString();\n const meta = buildWrittenFileMeta({\n validPath,\n content: editResult.content,\n dryRun: options.dryRun,\n lastModified: modified,\n });\n return {\n file: buildEditFileValue(validPath, meta, modified, editResult),\n ...(meta.resourceLink ? { resourceLink: meta.resourceLink } : {}),\n };\n}\n\nfunction formatEditSummary(\n results: readonly PerPathResult<EditFileValue>[],\n dryRun: boolean,\n): string {\n const tag = dryRun ? ' [dry run]' : '';\n // Single-file failure: say why here rather than making the caller read\n // structuredContent for the one message that can apply.\n const [only] = results;\n if (results.length === 1 && only && 'error' in only) {\n return `edit: ${only.path} FAILED — ${only.error.message}${tag}`;\n }\n const tokens = results.map((r) => {\n if ('error' in r) return `${basename(r.path)} FAILED`;\n const v = r.value;\n if (v.unmatchedEdits && v.unmatchedEdits.length > 0) {\n const quoted = v.unmatchedEdits.map((t) => JSON.stringify(truncateProgressPattern(t)));\n return `${basename(v.path)} NO MATCH ${joinRoster(quoted, ', ')}`;\n }\n const added = v.linesAdded ?? 0;\n const removed = v.linesRemoved ?? 0;\n if (added === 0 && removed === 0) return `${basename(v.path)} (no change)`;\n return `${basename(v.path)} +${String(added)} -${String(removed)}`;\n });\n\n const failed = results.filter((r) => 'error' in r).length;\n const ok = results.length - failed;\n const ratio = failed > 0 ? ` (${String(ok)}/${String(results.length)} ok)` : '';\n // Only a dry run carries a diff, and it is the preview the caller asked for:\n // the structured value ships under `_meta`, which clients do not show the model.\n // A no-op edit still yields a header-only diff; it previews nothing.\n const diffs = results\n .map((r) => ('value' in r ? (r.value.diff ?? '') : ''))\n .filter((d) => d.includes('\\n@@'))\n .join('');\n return `edit: ${tokens.join(' · ')}${ratio}${tag}${diffs ? `\\n\\n${diffs}` : ''}`;\n}\n\nexport const EDIT = defineTool<typeof EditFileInputSchema, BatchResult<EditFileValue>>({\n name: 'edit',\n title: 'Edit Files',\n description:\n 'Edit text files in place by replacing exact oldText with newText, like str_replace. ' +\n 'Each oldText must match exactly once, and a file is written only if all its edits match. ' +\n 'replace_text replaces every occurrence across files.',\n input: EditFileInputSchema,\n readOnlyHint: false,\n progress: (args) => {\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n let subject: string;\n if (args.path !== undefined) {\n subject = basename(args.path);\n } else if (args.files !== undefined) {\n subject = `${args.files.length} files`;\n } else {\n subject = 'files';\n }\n return { label: `Edit${dryLabel}`, subject };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n const items =\n args.path !== undefined ? [{ path: args.path, edits: args.edits ?? [] }] : (args.files ?? []);\n\n const options: EditFileOptions = {\n dryRun: args.dryRun,\n ignoreWhitespace: args.ignoreWhitespace,\n };\n\n const batch = await runOverPaths(items, ctx, ErrorCode.UNKNOWN, ({ path, edits }) =>\n handleEditFile(path, edits, options, ctx),\n );\n\n const perPathResults: PerPathResult<EditFileValue>[] = [];\n const resourceLinks: ContentBlock[] = [];\n for (const r of batch.results) {\n if ('error' in r) {\n perPathResults.push({ path: r.path, error: r.error });\n continue;\n }\n perPathResults.push({ path: r.path, value: r.value.file });\n if (r.value.resourceLink) resourceLinks.push(r.value.resourceLink);\n }\n\n const summaryText = formatEditSummary(perPathResults, args.dryRun);\n\n return {\n structured: {\n results: perPathResults,\n summary: batch.summary,\n },\n text: summaryText,\n isError: isTotalFailure(batch.summary),\n ...(resourceLinks.length > 0 ? { resources: resourceLinks } : {}),\n };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { diffStatsFromPatch, unifiedPatch } from '../core/diff.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { buildWrittenFileMeta, type WrittenFileMeta } from '../core/file-uri.ts';\nimport { joinRoster, truncateProgressPattern } from '../core/fmt.ts';\nimport { isSamePath } from '../core/path-utils.ts';\nimport {\n defaultFalseBoolean,\n nonBlankString,\n RequiredPath,\n singleOrBatchAccessPaths,\n} from '../core/schema.ts';\nimport { compileRegex, execMatches, freeRegex } from '../core/search.ts';\nimport { escapeRegExp } from '../core/util.ts';\nimport { type BatchResult, isTotalFailure, type PerPathResult, runOverPaths } from './batch.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\nconst EditSpecSchema = z.strictObject({\n oldText: nonBlankString('oldText')\n .describe(\n 'Exact literal text to locate in the file; it must match exactly once. Include 3-5 lines of context so it does — an oldText found in several places fails with their line numbers.',\n )\n .meta({ examples: ['const x = 1;', 'function oldName('] }),\n newText: z\n .string()\n .describe('Replacement text. Use an empty string to delete the matched oldText.')\n .meta({ examples: ['const x = 2;', 'function newName(', ''] }),\n});\n// No `id`, so no `$defs`/`$ref`: this subschema is inlined at both `edits` and\n// `files[].edits`. Hoisting it saved ~1.3 kB, but clients whose schema\n// converter cannot follow a `$ref` fell back to an opaque pass-through for\n// `edit` alone and sent its arguments as a serialized string (issue #51).\n\nconst MAX_MULTI_FILES = 5;\nconst MAX_EDITS_PER_FILE = 100;\n\nconst EditFileInputSchema = z\n .strictObject({\n path: RequiredPath.optional().describe('Single file path; mutually exclusive with files'),\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .optional()\n .describe('Replacements applied to path; not allowed when using files'),\n files: z\n .array(\n z.strictObject({\n path: RequiredPath,\n edits: z\n .array(EditSpecSchema)\n .min(1)\n .max(MAX_EDITS_PER_FILE)\n .describe('Replacements to apply to this specific file'),\n }),\n )\n .min(1)\n .max(MAX_MULTI_FILES)\n .optional()\n .describe('Per-file entries (batch mode)'),\n dryRun: defaultFalseBoolean(\n 'Preview diffs without writing to disk (default: false = apply edits)',\n ),\n ignoreWhitespace: defaultFalseBoolean(\n 'Ignore leading/trailing whitespace differences when matching oldText',\n ),\n })\n .superRefine((value, ctx) => {\n const hasPath = value.path !== undefined;\n const hasFiles = value.files !== undefined;\n if (hasPath === hasFiles) {\n ctx.addIssue({\n code: 'custom',\n path: ['path'],\n message: \"Provide exactly one of 'path' or 'files'\",\n input: value,\n });\n }\n if (hasPath && value.edits === undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' required when using 'path'\",\n input: value,\n });\n }\n if (hasFiles && value.edits !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['edits'],\n message: \"'edits' not allowed with 'files'; each file carries its own edits\",\n input: value,\n });\n }\n // Batch entries run in parallel and each rewrites its file whole, so two\n // entries for one file race: the last write wins and the other's edits are\n // lost while both report success. One entry per file.\n const files = value.files ?? [];\n for (const [index, file] of files.entries()) {\n const first = files.findIndex((other) => isSamePath(other.path, file.path));\n if (first < index) {\n ctx.addIssue({\n code: 'custom',\n path: ['files', index, 'path'],\n message: `duplicate of files[${String(first)}].path; put every edit for one file in a single entry`,\n input: value,\n });\n }\n }\n })\n // Mirror the superRefine on the wire: exactly one input mode, and single-file\n // mode carries its own `edits`. Without `edits` in the first branch, `{ path }`\n // alone validated against the published schema and was then rejected at\n // runtime — the model had no way to see that coming.\n .meta({ oneOf: [{ required: ['path', 'edits'] }, { required: ['files'] }] });\n\ntype EditFileValue = Omit<WrittenFileMeta, 'resourceLink'> & {\n path: string;\n modified: string;\n appliedEdits: number;\n linesAdded?: number;\n linesRemoved?: number;\n diff?: string;\n unmatchedEdits?: string[];\n};\n\ninterface TextRange {\n startIndex: number;\n length: number;\n}\n\ninterface EditResult {\n content: string;\n appliedEdits: number;\n unmatchedEdits: string[];\n linesAdded?: number;\n linesRemoved?: number;\n diff?: string;\n}\n\nconst MAX_REPORTED_MATCH_LINES = 5;\n\ninterface EditMatches {\n /** The first match; undefined when oldText matches nothing. */\n first: TextRange | undefined;\n count: number;\n /** UTF-16 start offsets of the first {@link MAX_REPORTED_MATCH_LINES} matches. */\n starts: number[];\n truncated: boolean;\n}\n\n/**\n * Pattern for a whitespace run of oldText that contains a newline. Between two\n * pieces of text it stays flexible — at least one newline, as many as the file\n * has. At either edge of oldText it matches exactly the newlines written: a\n * flexible edge swallows the blank lines around the match and, at the trailing\n * edge, the next line's indentation, all of which newText then replaces. Each\n * newline may carry horizontal whitespace before it, which covers the `\\r` of\n * a CRLF file and a blank line with stray spaces.\n */\nfunction newlineRunPattern(token: string, edge: { leading: boolean; trailing: boolean }): string {\n if (!edge.leading && !edge.trailing) return '(?:[^\\\\S\\\\n]*\\\\n)+[^\\\\S\\\\n]*';\n const count = token.split('\\n').length - 1;\n const lines = `(?:[^\\\\S\\\\n]*\\\\n){${String(count)}}`;\n // Nothing after the final newline unless the caller wrote indentation there.\n return edge.trailing && token.endsWith('\\n') ? lines : `${lines}[^\\\\S\\\\n]*`;\n}\n\n/**\n * Where `oldText` matches. `count` is non-overlapping occurrences, except that a\n * lone match with a second one overlapping it counts two (`abab` in `ababab`),\n * since either is a span the caller could have meant — the count is exact only\n * when it answers \"once or not\". Only the count and the first few starts are\n * kept: a short oldText in a large file can match millions of times.\n */\nfunction findEditMatches(content: string, oldText: string, ignoreWhitespace: boolean): EditMatches {\n const found: EditMatches = { first: undefined, count: 0, starts: [], truncated: false };\n // Returns true once the match is known ambiguous: applyEdits only needs\n // 0 / 1 / >1 and a few starts, and counting every occurrence of a short\n // oldText in a big file is wasted work (seconds under re2-wasm).\n const add = (startIndex: number, length: number): boolean => {\n found.first ??= { startIndex, length };\n found.count += 1;\n if (found.starts.length < MAX_REPORTED_MATCH_LINES) found.starts.push(startIndex);\n found.truncated = found.count > MAX_REPORTED_MATCH_LINES;\n return found.truncated;\n };\n\n if (ignoreWhitespace) {\n // Make whitespace flexible (tolerate indentation/spacing differences)\n // without letting it cross line boundaries: a whitespace run that contains\n // a newline keeps at least one newline, so a single-line oldText cannot\n // match across a newline and a multi-line oldText cannot collapse onto one\n // line. Horizontal whitespace stays mandatory between word characters so\n // adjacent identifiers are not merged. Built token by token: `split` on\n // whitespace puts text at even indices and whitespace runs at odd ones.\n // A newline run at either edge of oldText matches exactly, so the edit\n // cannot reach past the lines the caller named.\n const tokens = oldText.split(/(\\s+)/u);\n const last = tokens.length - 1;\n let pattern = '';\n for (const [i, token] of tokens.entries()) {\n if (i % 2 === 0) {\n pattern += escapeRegExp(token);\n } else if (token.includes('\\n')) {\n pattern += newlineRunPattern(token, {\n leading: i === 1 && tokens[0] === '',\n trailing: i === last - 1 && tokens[last] === '',\n });\n } else if (/\\w$/.test(tokens[i - 1] ?? '') && /^\\w/.test(tokens[i + 1] ?? '')) {\n pattern += '[^\\\\S\\\\n]+';\n } else {\n pattern += '[^\\\\S\\\\n]*';\n }\n }\n const regex = compileRegex(pattern, { caseSensitive: true });\n try {\n // execMatches resets lastIndex and reports UTF-16 offsets; the raw RE2\n // index counts code points and would splice off-by-one per emoji.\n const scan = (from: number): void => {\n for (const match of execMatches(regex, from === 0 ? content : content.slice(from))) {\n // A zero-length match names an empty span, which cannot be replaced.\n if (match.text.length > 0 && add(from + match.start, match.text.length)) return;\n if (from > 0) return;\n }\n };\n scan(0);\n // execMatches resumes past each match, so a second match overlapping the\n // first is never reported; look once more from just past its first\n // non-whitespace character. Starting inside the leading whitespace would\n // re-find the same occurrence, since the pattern's leading run is `*`. The\n // pattern carries no anchors, so matching a suffix finds the same spans.\n if (found.count === 1 && found.first) {\n const { startIndex, length } = found.first;\n const lead = content.slice(startIndex, startIndex + length).search(/\\S/u);\n scan(afterCodePoint(content, startIndex + lead));\n }\n } finally {\n // The compiled pattern owns wasm memory re2-wasm never reclaims on its\n // own; its lifetime is this one search.\n freeRegex(regex);\n }\n return found;\n }\n\n // Non-overlapping, so the scan stays linear on repetitive content; the one\n // overlap that matters — a second match inside the only one — is checked after.\n for (\n let i = content.indexOf(oldText);\n i !== -1;\n i = content.indexOf(oldText, i + oldText.length)\n ) {\n if (add(i, oldText.length)) break;\n }\n if (found.count === 1 && found.first) {\n const overlap = content.indexOf(oldText, afterCodePoint(content, found.first.startIndex));\n if (overlap !== -1) add(overlap, oldText.length);\n }\n return found;\n}\n\n/** The UTF-16 offset just past the code point at `index`, so a surrogate pair is never split. */\nfunction afterCodePoint(content: string, index: number): number {\n return index + ((content.codePointAt(index) ?? 0) > 0xffff ? 2 : 1);\n}\n\nfunction ambiguousEditError(\n content: string,\n found: EditMatches,\n editIndex: number,\n shifted: boolean,\n): FsError {\n const lines = [\n ...new Set(found.starts.map((start) => content.slice(0, start).split('\\n').length)),\n ];\n const label = lines.length === 1 ? 'line' : 'lines';\n const more = found.count > found.starts.length ? ', ...' : '';\n // Offsets come from the content as earlier edits in this call left it, which\n // is not the file the caller read once one of them has applied.\n const where = shifted ? ' after earlier edits' : '';\n const count = found.truncated ? `at least ${String(found.count)}` : String(found.count);\n return new FsError(\n ErrorCode.INVALID_INPUT,\n `edits[${String(editIndex)}]: oldText matches ${count} places${where} ` +\n `(${label} ${lines.join(', ')}${more}). Add surrounding lines so it matches once.`,\n );\n}\n\n// A file whose every newline is CRLF gets LF-only edit text converted to match\n// — the rule jsdiff's autoConvertLineEndings applies for `patch`. Range, head\n// and tail reads strip `\\r`, so the oldText a model sends is LF-only; text that\n// already carries a `\\r` is taken as written. Mixed-ending files are not\n// converted: there is no one ending to convert to.\nfunction usesCrlf(content: string): boolean {\n return content.includes('\\r\\n') && !/(?<!\\r)\\n/u.test(content);\n}\n\nfunction toCrlf(text: string): string {\n return text.includes('\\r') ? text : text.replaceAll('\\n', '\\r\\n');\n}\n\nfunction applyEdits(\n content: string,\n edits: z.infer<typeof EditSpecSchema>[],\n ignoreWhitespace: boolean,\n): EditResult {\n let newContent = content;\n let appliedEdits = 0;\n const unmatchedEdits: string[] = [];\n const crlf = usesCrlf(content);\n\n for (const [index, edit] of edits.entries()) {\n const oldText = crlf ? toCrlf(edit.oldText) : edit.oldText;\n const newText = crlf ? toCrlf(edit.newText) : edit.newText;\n const found = findEditMatches(newContent, oldText, ignoreWhitespace);\n\n // A second match is an error rather than a pick: splicing the first would\n // edit a block the caller may not have meant and still report success.\n if (found.count > 1) throw ambiguousEditError(newContent, found, index, appliedEdits > 0);\n\n if (!found.first) {\n unmatchedEdits.push(edit.oldText);\n continue;\n }\n\n const first = found.first;\n newContent =\n newContent.slice(0, first.startIndex) +\n newText +\n newContent.slice(first.startIndex + first.length);\n appliedEdits += 1;\n }\n\n return { content: newContent, appliedEdits, unmatchedEdits };\n}\n\nasync function editOnce(\n filePath: string,\n edits: z.infer<typeof EditSpecSchema>[],\n options: { dryRun: boolean; ignoreWhitespace: boolean },\n ctx: ToolCtx,\n): Promise<{ file: EditFileValue; resourceLink?: ContentBlock }> {\n const { validPath, content } = await ctx.fs.readEditableText(filePath, {\n signal: ctx.signal,\n });\n const editResult = applyEdits(content, edits, options.ignoreWhitespace);\n // One Myers pass serves both the dry-run preview and the line counts.\n const patch =\n editResult.appliedEdits > 0\n ? unifiedPatch(basename(validPath), content, editResult.content)\n : undefined;\n if (patch !== undefined) Object.assign(editResult, diffStatsFromPatch(patch));\n\n if (options.dryRun) {\n if (patch !== undefined) editResult.diff = patch;\n } else {\n if (editResult.unmatchedEdits.length > 0) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n `no match for oldText ${joinRoster(\n editResult.unmatchedEdits.map((t) => JSON.stringify(truncateProgressPattern(t))),\n ', ',\n )}; it must match the file exactly`,\n filePath,\n );\n }\n\n if (editResult.appliedEdits > 0) {\n await ctx.fs.writeFile(filePath, editResult.content, {\n signal: ctx.signal,\n });\n ctx.log(\n 'info',\n `edit: ${filePath} (${editResult.appliedEdits} edits, +${String(editResult.linesAdded ?? 0)}/-${String(editResult.linesRemoved ?? 0)})`,\n 'edit',\n );\n }\n }\n\n // `modified` is read from a post-write stat and is advisory: under a concurrent\n // writer it may reflect that writer's mtime while `size`/content below come from\n // this edit's atomic write. The file content itself is always consistent. A dry\n // run wrote nothing, so it reports the time of the preview.\n const modified = options.dryRun\n ? new Date().toISOString()\n : (await ctx.fs.stat(filePath, { signal: ctx.signal })).stats.mtime.toISOString();\n const meta = buildWrittenFileMeta({\n validPath,\n content: editResult.content,\n dryRun: options.dryRun,\n lastModified: modified,\n });\n const { resourceLink, ...fileMeta } = meta;\n return {\n file: {\n path: validPath,\n ...fileMeta,\n modified,\n appliedEdits: editResult.appliedEdits,\n ...(editResult.appliedEdits > 0 &&\n editResult.linesAdded !== undefined &&\n editResult.linesRemoved !== undefined\n ? { linesAdded: editResult.linesAdded, linesRemoved: editResult.linesRemoved }\n : {}),\n ...(editResult.unmatchedEdits.length > 0\n ? { unmatchedEdits: editResult.unmatchedEdits }\n : {}),\n ...(editResult.diff ? { diff: editResult.diff } : {}),\n },\n ...(resourceLink ? { resourceLink } : {}),\n };\n}\n\nfunction formatEditSummary(\n results: readonly PerPathResult<EditFileValue>[],\n dryRun: boolean,\n): string {\n const tag = dryRun ? ' [dry run]' : '';\n // Single-file failure: say why here rather than making the caller read\n // structuredContent for the one message that can apply.\n const [only] = results;\n if (results.length === 1 && only && 'error' in only) {\n return `edit: ${only.path} FAILED — ${only.error.message}${tag}`;\n }\n const tokens = results.map((r) => {\n if ('error' in r) return `${basename(r.path)} FAILED`;\n const v = r.value;\n if (v.unmatchedEdits && v.unmatchedEdits.length > 0) {\n const quoted = v.unmatchedEdits.map((t) => JSON.stringify(truncateProgressPattern(t)));\n return `${basename(v.path)} NO MATCH ${joinRoster(quoted, ', ')}`;\n }\n const added = v.linesAdded ?? 0;\n const removed = v.linesRemoved ?? 0;\n if (added === 0 && removed === 0) return `${basename(v.path)} (no change)`;\n return `${basename(v.path)} +${String(added)} -${String(removed)}`;\n });\n\n const failed = results.filter((r) => 'error' in r).length;\n const ok = results.length - failed;\n const ratio = failed > 0 ? ` (${String(ok)}/${String(results.length)} ok)` : '';\n // Only a dry run carries a diff, and it is the preview the caller asked for:\n // the structured value ships under `_meta`, which clients do not show the model.\n // A no-op edit still yields a header-only diff; it previews nothing.\n const diffs = results\n .map((r) => ('value' in r ? (r.value.diff ?? '') : ''))\n .filter((d) => d.includes('\\n@@'))\n .join('');\n return `edit: ${tokens.join(' · ')}${ratio}${tag}${diffs ? `\\n\\n${diffs}` : ''}`;\n}\n\nexport const EDIT = defineTool<typeof EditFileInputSchema, BatchResult<EditFileValue>>({\n name: 'edit',\n title: 'Edit Files',\n description:\n 'Edit text files in place by replacing exact oldText with newText, like str_replace. ' +\n 'Each oldText must match exactly once, and a file is written only if all its edits match. ' +\n 'replace_text replaces every occurrence across files.',\n input: EditFileInputSchema,\n readOnlyHint: false,\n progress: (args) => {\n const dryLabel = args.dryRun ? ' [dry run]' : '';\n let subject: string;\n if (args.path !== undefined) {\n subject = basename(args.path);\n } else if (args.files !== undefined) {\n subject = `${args.files.length} files`;\n } else {\n subject = 'files';\n }\n return { label: `Edit${dryLabel}`, subject };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n const items =\n args.path !== undefined ? [{ path: args.path, edits: args.edits ?? [] }] : (args.files ?? []);\n\n const batch = await runOverPaths(items, ctx, ErrorCode.UNKNOWN, ({ path, edits }) =>\n // A dry run never writes, so it needs no lock.\n args.dryRun\n ? editOnce(path, edits, args, ctx)\n : ctx.fs.lockForWrite(path, () => editOnce(path, edits, args, ctx)),\n );\n\n const perPathResults: PerPathResult<EditFileValue>[] = [];\n const resourceLinks: ContentBlock[] = [];\n for (const r of batch.results) {\n if ('error' in r) {\n perPathResults.push({ path: r.path, error: r.error });\n continue;\n }\n perPathResults.push({ path: r.path, value: r.value.file });\n if (r.value.resourceLink) resourceLinks.push(r.value.resourceLink);\n }\n\n const summaryText = formatEditSummary(perPathResults, args.dryRun);\n\n return {\n structured: {\n results: perPathResults,\n summary: batch.summary,\n },\n text: summaryText,\n isError: isTotalFailure(batch.summary),\n ...(resourceLinks.length > 0 ? { resources: resourceLinks } : {}),\n };\n },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-files.d.ts","sourceRoot":"","sources":["../../src/tools/find-files.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"find-files.d.ts","sourceRoot":"","sources":["../../src/tools/find-files.ts"],"names":[],"mappings":"AAiEA,eAAO,MAAM,UAAU,mCAsFrB,CAAC"}
|
package/dist/tools/find-files.js
CHANGED
|
@@ -28,60 +28,6 @@ const SearchFilesInputSchema = z.strictObject({
|
|
|
28
28
|
maxDepth: MaxDepth,
|
|
29
29
|
cursor: CursorSchema,
|
|
30
30
|
});
|
|
31
|
-
function searchFilesOutput(results, metadata, nextCursor, resourceUri) {
|
|
32
|
-
return {
|
|
33
|
-
root: metadata.root,
|
|
34
|
-
results: [...results],
|
|
35
|
-
totalMatches: metadata.matched,
|
|
36
|
-
filesScanned: metadata.filesScanned,
|
|
37
|
-
...(metadata.skippedInaccessible ? { skippedInaccessible: metadata.skippedInaccessible } : {}),
|
|
38
|
-
...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),
|
|
39
|
-
...(resourceUri !== undefined ? { resourceUri } : {}),
|
|
40
|
-
...(nextCursor !== undefined ? { nextCursor } : {}),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
async function handleSearchFiles(args, ctx) {
|
|
44
|
-
const requestedBasePath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);
|
|
45
|
-
const queryKey = JSON.stringify({
|
|
46
|
-
method: 'find_files',
|
|
47
|
-
path: requestedBasePath,
|
|
48
|
-
pattern: args.pattern,
|
|
49
|
-
includeIgnored: args.includeIgnored,
|
|
50
|
-
includeHidden: args.includeHidden,
|
|
51
|
-
sortBy: args.sortBy,
|
|
52
|
-
maxDepth: args.maxDepth,
|
|
53
|
-
});
|
|
54
|
-
const paged = await paginate({
|
|
55
|
-
store: ctx.pageStore,
|
|
56
|
-
queryKey,
|
|
57
|
-
cursor: args.cursor,
|
|
58
|
-
pageSize: args.maxResults,
|
|
59
|
-
produce: async () => {
|
|
60
|
-
const basePath = await ctx.fs.pathGuard.validateExistingDirectory(requestedBasePath);
|
|
61
|
-
const searchOptions = {
|
|
62
|
-
maxResults: MAX_SEARCH_RESULTS,
|
|
63
|
-
includeHidden: args.includeHidden,
|
|
64
|
-
sortBy: args.sortBy,
|
|
65
|
-
skipIgnored: !args.includeIgnored,
|
|
66
|
-
...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),
|
|
67
|
-
signal: ctx.signal,
|
|
68
|
-
};
|
|
69
|
-
const result = await searchFiles(basePath, args.pattern, searchOptions, ctx.fs.pathGuard);
|
|
70
|
-
return {
|
|
71
|
-
items: result.results.map((r) => ({ path: toPosixRelative(result.basePath, r.path) })),
|
|
72
|
-
metadata: { root: result.basePath, ...result.summary },
|
|
73
|
-
truncated: result.summary.truncated,
|
|
74
|
-
};
|
|
75
|
-
},
|
|
76
|
-
externalize: (results) => putJsonResource(ctx.resourceStore, `${args.pattern} files`, results),
|
|
77
|
-
});
|
|
78
|
-
return {
|
|
79
|
-
structured: searchFilesOutput(paged.page, paged.metadata, paged.nextCursor, paged.resource?.entry.uri),
|
|
80
|
-
offset: paged.offset,
|
|
81
|
-
total: paged.metadata.matched,
|
|
82
|
-
...(paged.resource ? { link: paged.resource.link } : {}),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
31
|
export const FIND_FILES = defineTool({
|
|
86
32
|
name: 'find_files',
|
|
87
33
|
title: 'Find Files',
|
|
@@ -99,7 +45,53 @@ export const FIND_FILES = defineTool({
|
|
|
99
45
|
}),
|
|
100
46
|
accessPaths: (args) => (args.path ? [args.path] : []),
|
|
101
47
|
run: async (args, ctx) => {
|
|
102
|
-
const
|
|
48
|
+
const requestedBasePath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);
|
|
49
|
+
const queryKey = JSON.stringify({
|
|
50
|
+
method: 'find_files',
|
|
51
|
+
path: requestedBasePath,
|
|
52
|
+
pattern: args.pattern,
|
|
53
|
+
includeIgnored: args.includeIgnored,
|
|
54
|
+
includeHidden: args.includeHidden,
|
|
55
|
+
sortBy: args.sortBy,
|
|
56
|
+
maxDepth: args.maxDepth,
|
|
57
|
+
});
|
|
58
|
+
const paged = await paginate({
|
|
59
|
+
store: ctx.pageStore,
|
|
60
|
+
queryKey,
|
|
61
|
+
cursor: args.cursor,
|
|
62
|
+
pageSize: args.maxResults,
|
|
63
|
+
produce: async () => {
|
|
64
|
+
const basePath = await ctx.fs.pathGuard.validateExistingDirectory(requestedBasePath);
|
|
65
|
+
const searchOptions = {
|
|
66
|
+
maxResults: MAX_SEARCH_RESULTS,
|
|
67
|
+
includeHidden: args.includeHidden,
|
|
68
|
+
sortBy: args.sortBy,
|
|
69
|
+
skipIgnored: !args.includeIgnored,
|
|
70
|
+
...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),
|
|
71
|
+
signal: ctx.signal,
|
|
72
|
+
};
|
|
73
|
+
const result = await searchFiles(basePath, args.pattern, searchOptions, ctx.fs.pathGuard);
|
|
74
|
+
return {
|
|
75
|
+
items: result.results.map((r) => ({ path: toPosixRelative(result.basePath, r.path) })),
|
|
76
|
+
metadata: { root: result.basePath, ...result.summary },
|
|
77
|
+
truncated: result.summary.truncated,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
externalize: (results) => putJsonResource(ctx.resourceStore, `${args.pattern} files`, results),
|
|
81
|
+
});
|
|
82
|
+
const { metadata, offset } = paged;
|
|
83
|
+
const structured = {
|
|
84
|
+
root: metadata.root,
|
|
85
|
+
results: [...paged.page],
|
|
86
|
+
totalMatches: metadata.matched,
|
|
87
|
+
filesScanned: metadata.filesScanned,
|
|
88
|
+
...(metadata.skippedInaccessible
|
|
89
|
+
? { skippedInaccessible: metadata.skippedInaccessible }
|
|
90
|
+
: {}),
|
|
91
|
+
...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),
|
|
92
|
+
...(paged.resource ? { resourceUri: paged.resource.entry.uri } : {}),
|
|
93
|
+
...(paged.nextCursor !== undefined ? { nextCursor: paged.nextCursor } : {}),
|
|
94
|
+
};
|
|
103
95
|
const body = structured.results.length > 0
|
|
104
96
|
? structured.results.map((r) => r.path).join('\n')
|
|
105
97
|
: `No files matching '${args.pattern}'`;
|
|
@@ -107,7 +99,7 @@ export const FIND_FILES = defineTool({
|
|
|
107
99
|
pageTrailer({
|
|
108
100
|
offset,
|
|
109
101
|
shown: structured.results.length,
|
|
110
|
-
total,
|
|
102
|
+
total: metadata.matched,
|
|
111
103
|
noun: 'files',
|
|
112
104
|
tool: 'find_files',
|
|
113
105
|
nextCursor: structured.nextCursor,
|
|
@@ -115,10 +107,7 @@ export const FIND_FILES = defineTool({
|
|
|
115
107
|
stoppedReason: structured.stoppedReason,
|
|
116
108
|
skippedInaccessible: structured.skippedInaccessible,
|
|
117
109
|
});
|
|
118
|
-
|
|
119
|
-
return { structured, text, resources: [link] };
|
|
120
|
-
}
|
|
121
|
-
return { structured, text };
|
|
110
|
+
return { structured, text, resources: paged.resource ? [paged.resource.link] : [] };
|
|
122
111
|
},
|
|
123
112
|
});
|
|
124
113
|
//# sourceMappingURL=find-files.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-files.js","sourceRoot":"","sources":["../../src/tools/find-files.ts"],"names":[],"mappings":"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","sourcesContent":["import * as z from 'zod/v4';\n\nimport { paginate } from '../core/cursor.ts';\nimport { formatCount, pageTrailer, truncateProgressPattern } from '../core/fmt.ts';\nimport { toPosixRelative } from '../core/path.ts';\nimport {\n CursorSchema,\n IncludeHidden,\n IncludeIgnored,\n MaxDepth,\n OptionalPath,\n SafeGlobPattern,\n} from '../core/schema.ts';\nimport { searchFiles } from '../core/search.ts';\nimport type { JsonResourceResult } from '../core/store.ts';\nimport { putJsonResource } from '../core/store.ts';\nimport {\n DEFAULT_SEARCH_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n MAX_SEARCH_RESULTS,\n} from '../core/util.ts';\nimport { defineTool, type ToolCtx } from './define.ts';\n\n// ---------------------------------------------------------------------------\n\nconst SearchFilesInputSchema = z.strictObject({\n path: OptionalPath.describe('Base directory to search under (default: first allowed root)'),\n pattern: SafeGlobPattern.describe('Glob pattern to match file paths (e.g. **/*.ts, src/**/*.js)'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_RESULTS)\n .describe('Maximum number of matching files to return per page'),\n includeIgnored: IncludeIgnored,\n includeHidden: IncludeHidden,\n sortBy: z\n .enum(['name', 'path'])\n .optional()\n .default('path')\n .describe('Sort order: path = full path (default), name = basename only'),\n maxDepth: MaxDepth,\n cursor: CursorSchema,\n});\n\ninterface SearchFileResult {\n path: string;\n}\ninterface SearchFilesOutput {\n root: string;\n results: SearchFileResult[];\n totalMatches?: number;\n filesScanned?: number;\n skippedInaccessible?: number;\n stoppedReason?: 'maxResults' | 'timeout';\n resourceUri?: string;\n nextCursor?: string;\n}\n\n/** The engine's own summary plus its root is the page metadata; nothing is copied out of it. */\ntype SearchFilesPageMetadata = Awaited<ReturnType<typeof searchFiles>>['summary'] & {\n readonly root: string;\n};\n\nfunction searchFilesOutput(\n results: readonly SearchFileResult[],\n metadata: SearchFilesPageMetadata,\n nextCursor: string | undefined,\n resourceUri: string | undefined,\n): SearchFilesOutput {\n return {\n root: metadata.root,\n results: [...results],\n totalMatches: metadata.matched,\n filesScanned: metadata.filesScanned,\n ...(metadata.skippedInaccessible ? { skippedInaccessible: metadata.skippedInaccessible } : {}),\n ...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),\n ...(resourceUri !== undefined ? { resourceUri } : {}),\n ...(nextCursor !== undefined ? { nextCursor } : {}),\n };\n}\n\nasync function handleSearchFiles(\n args: z.infer<typeof SearchFilesInputSchema>,\n ctx: ToolCtx,\n): Promise<{\n structured: SearchFilesOutput;\n offset: number;\n total: number;\n link?: ReturnType<typeof putJsonResource>['link'];\n}> {\n const requestedBasePath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);\n const queryKey = JSON.stringify({\n method: 'find_files',\n path: requestedBasePath,\n pattern: args.pattern,\n includeIgnored: args.includeIgnored,\n includeHidden: args.includeHidden,\n sortBy: args.sortBy,\n maxDepth: args.maxDepth,\n });\n const paged = await paginate<SearchFileResult, SearchFilesPageMetadata, JsonResourceResult>({\n store: ctx.pageStore,\n queryKey,\n cursor: args.cursor,\n pageSize: args.maxResults,\n produce: async () => {\n const basePath = await ctx.fs.pathGuard.validateExistingDirectory(requestedBasePath);\n const searchOptions: Parameters<typeof searchFiles>[2] = {\n maxResults: MAX_SEARCH_RESULTS,\n includeHidden: args.includeHidden,\n sortBy: args.sortBy,\n skipIgnored: !args.includeIgnored,\n ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),\n signal: ctx.signal,\n };\n const result = await searchFiles(basePath, args.pattern, searchOptions, ctx.fs.pathGuard);\n return {\n items: result.results.map((r) => ({ path: toPosixRelative(result.basePath, r.path) })),\n metadata: { root: result.basePath, ...result.summary },\n truncated: result.summary.truncated,\n };\n },\n externalize: (results) => putJsonResource(ctx.resourceStore, `${args.pattern} files`, results),\n });\n\n return {\n structured: searchFilesOutput(\n paged.page,\n paged.metadata,\n paged.nextCursor,\n paged.resource?.entry.uri,\n ),\n offset: paged.offset,\n total: paged.metadata.matched,\n ...(paged.resource ? { link: paged.resource.link } : {}),\n };\n}\n\nexport const FIND_FILES = defineTool<typeof SearchFilesInputSchema, SearchFilesOutput>({\n name: 'find_files',\n title: 'Find Files',\n description:\n 'Find files by name or glob pattern; returns file paths relative to the searched directory. ' +\n 'A pattern without / matches file names at any depth. search_text searches contents.',\n input: SearchFilesInputSchema,\n readOnlyHint: true,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n progress: (args) => ({\n label: 'Find',\n subject: truncateProgressPattern(args.pattern),\n }),\n progressDone: (_args, result) => ({\n detail: formatCount(result.totalMatches ?? 0, 'match', 'matches'),\n }),\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const { structured, offset, total, link } = await handleSearchFiles(args, ctx);\n const body =\n structured.results.length > 0\n ? structured.results.map((r) => r.path).join('\\n')\n : `No files matching '${args.pattern}'`;\n const text =\n body +\n pageTrailer({\n offset,\n shown: structured.results.length,\n total,\n noun: 'files',\n tool: 'find_files',\n nextCursor: structured.nextCursor,\n nextArgs: args,\n stoppedReason: structured.stoppedReason,\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":"find-files.js","sourceRoot":"","sources":["../../src/tools/find-files.ts"],"names":[],"mappings":"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","sourcesContent":["import * as z from 'zod/v4';\n\nimport { paginate } from '../core/cursor.ts';\nimport { formatCount, pageTrailer, truncateProgressPattern } from '../core/fmt.ts';\nimport { toPosixRelative } from '../core/path.ts';\nimport {\n CursorSchema,\n IncludeHidden,\n IncludeIgnored,\n MaxDepth,\n OptionalPath,\n SafeGlobPattern,\n} from '../core/schema.ts';\nimport { searchFiles } from '../core/search.ts';\nimport type { JsonResourceResult } from '../core/store.ts';\nimport { putJsonResource } from '../core/store.ts';\nimport {\n DEFAULT_SEARCH_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n MAX_SEARCH_RESULTS,\n} from '../core/util.ts';\nimport { defineTool } from './define.ts';\n\n// ---------------------------------------------------------------------------\n\nconst SearchFilesInputSchema = z.strictObject({\n path: OptionalPath.describe('Base directory to search under (default: first allowed root)'),\n pattern: SafeGlobPattern.describe('Glob pattern to match file paths (e.g. **/*.ts, src/**/*.js)'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_RESULTS)\n .describe('Maximum number of matching files to return per page'),\n includeIgnored: IncludeIgnored,\n includeHidden: IncludeHidden,\n sortBy: z\n .enum(['name', 'path'])\n .optional()\n .default('path')\n .describe('Sort order: path = full path (default), name = basename only'),\n maxDepth: MaxDepth,\n cursor: CursorSchema,\n});\n\ninterface SearchFileResult {\n path: string;\n}\ninterface SearchFilesOutput {\n root: string;\n results: SearchFileResult[];\n totalMatches?: number;\n filesScanned?: number;\n skippedInaccessible?: number;\n stoppedReason?: 'maxResults' | 'timeout';\n resourceUri?: string;\n nextCursor?: string;\n}\n\n/** The engine's own summary plus its root is the page metadata; nothing is copied out of it. */\ntype SearchFilesPageMetadata = Awaited<ReturnType<typeof searchFiles>>['summary'] & {\n readonly root: string;\n};\n\nexport const FIND_FILES = defineTool<typeof SearchFilesInputSchema, SearchFilesOutput>({\n name: 'find_files',\n title: 'Find Files',\n description:\n 'Find files by name or glob pattern; returns file paths relative to the searched directory. ' +\n 'A pattern without / matches file names at any depth. search_text searches contents.',\n input: SearchFilesInputSchema,\n readOnlyHint: true,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n progress: (args) => ({\n label: 'Find',\n subject: truncateProgressPattern(args.pattern),\n }),\n progressDone: (_args, result) => ({\n detail: formatCount(result.totalMatches ?? 0, 'match', 'matches'),\n }),\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const requestedBasePath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);\n const queryKey = JSON.stringify({\n method: 'find_files',\n path: requestedBasePath,\n pattern: args.pattern,\n includeIgnored: args.includeIgnored,\n includeHidden: args.includeHidden,\n sortBy: args.sortBy,\n maxDepth: args.maxDepth,\n });\n const paged = await paginate<SearchFileResult, SearchFilesPageMetadata, JsonResourceResult>({\n store: ctx.pageStore,\n queryKey,\n cursor: args.cursor,\n pageSize: args.maxResults,\n produce: async () => {\n const basePath = await ctx.fs.pathGuard.validateExistingDirectory(requestedBasePath);\n const searchOptions: Parameters<typeof searchFiles>[2] = {\n maxResults: MAX_SEARCH_RESULTS,\n includeHidden: args.includeHidden,\n sortBy: args.sortBy,\n skipIgnored: !args.includeIgnored,\n ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),\n signal: ctx.signal,\n };\n const result = await searchFiles(basePath, args.pattern, searchOptions, ctx.fs.pathGuard);\n return {\n items: result.results.map((r) => ({ path: toPosixRelative(result.basePath, r.path) })),\n metadata: { root: result.basePath, ...result.summary },\n truncated: result.summary.truncated,\n };\n },\n externalize: (results) =>\n putJsonResource(ctx.resourceStore, `${args.pattern} files`, results),\n });\n\n const { metadata, offset } = paged;\n const structured: SearchFilesOutput = {\n root: metadata.root,\n results: [...paged.page],\n totalMatches: metadata.matched,\n filesScanned: metadata.filesScanned,\n ...(metadata.skippedInaccessible\n ? { skippedInaccessible: metadata.skippedInaccessible }\n : {}),\n ...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),\n ...(paged.resource ? { resourceUri: paged.resource.entry.uri } : {}),\n ...(paged.nextCursor !== undefined ? { nextCursor: paged.nextCursor } : {}),\n };\n const body =\n structured.results.length > 0\n ? structured.results.map((r) => r.path).join('\\n')\n : `No files matching '${args.pattern}'`;\n const text =\n body +\n pageTrailer({\n offset,\n shown: structured.results.length,\n total: metadata.matched,\n noun: 'files',\n tool: 'find_files',\n nextCursor: structured.nextCursor,\n nextArgs: args,\n stoppedReason: structured.stoppedReason,\n skippedInaccessible: structured.skippedInaccessible,\n });\n return { structured, text, resources: paged.resource ? [paged.resource.link] : [] };\n },\n});\n"]}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { PathGuard } from '../core/path.ts';
|
|
3
|
-
import type { PageSnapshotStore, ResourceStore } from '../core/store.ts';
|
|
4
|
-
import type { DefinedTool } from './define.ts';
|
|
1
|
+
import type { DefinedTool, ToolDeps } from './define.ts';
|
|
5
2
|
import { FIND_FILES } from './find-files.ts';
|
|
6
3
|
import { LIST_ROOTS } from './list-roots.ts';
|
|
7
4
|
import { LIST } from './list.ts';
|
|
@@ -13,13 +10,8 @@ export declare const MUTATING_TOOL_NAMES: Set<string>;
|
|
|
13
10
|
/** The tools a server registers at this setting — the one owner of the `--read-only` gate. */
|
|
14
11
|
export declare function registeredTools(readOnly: boolean): readonly DefinedTool[];
|
|
15
12
|
export { LIST, LIST_ROOTS, READ, SEARCH_TEXT, FIND_FILES, STAT };
|
|
16
|
-
interface ToolRegistrarDeps {
|
|
17
|
-
readonly server: McpServer;
|
|
18
|
-
readonly pathGuard: PathGuard;
|
|
19
|
-
readonly pageStore: PageSnapshotStore;
|
|
20
|
-
readonly resourceStore: ResourceStore;
|
|
13
|
+
interface ToolRegistrarDeps extends ToolDeps {
|
|
21
14
|
readonly readOnly?: boolean;
|
|
22
|
-
readonly era?: 'legacy' | 'modern';
|
|
23
15
|
}
|
|
24
16
|
export declare function registerTools(deps: ToolRegistrarDeps): void;
|
|
25
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,eAAO,MAAM,SAAS,oLAcZ,CAAC;AAEX,eAAO,MAAM,mBAAmB,aAE/B,CAAC;AAEF,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,WAAW,EAAE,CAEzE;AAOD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAEjE,UAAU,iBAAkB,SAAQ,QAAQ;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAI3D"}
|
package/dist/tools/index.js
CHANGED
|
@@ -38,15 +38,8 @@ export function registeredTools(readOnly) {
|
|
|
38
38
|
// MUTATING_TOOL_NAMES and ALL_TOOLS instead.
|
|
39
39
|
export { LIST, LIST_ROOTS, READ, SEARCH_TEXT, FIND_FILES, STAT };
|
|
40
40
|
export function registerTools(deps) {
|
|
41
|
-
const toolDeps = {
|
|
42
|
-
server: deps.server,
|
|
43
|
-
pathGuard: deps.pathGuard,
|
|
44
|
-
pageStore: deps.pageStore,
|
|
45
|
-
resourceStore: deps.resourceStore,
|
|
46
|
-
...(deps.era ? { era: deps.era } : {}),
|
|
47
|
-
};
|
|
48
41
|
for (const tool of registeredTools(deps.readOnly ?? false)) {
|
|
49
|
-
tool.register(
|
|
42
|
+
tool.register(deps);
|
|
50
43
|
}
|
|
51
44
|
}
|
|
52
45
|
//# sourceMappingURL=index.js.map
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,YAAY;IACZ,UAAU;IACV,WAAW;IACX,UAAU;IACV,IAAI;CACI,CAAC;AAEX,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CACxC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAC5D,CAAC;AAEF,8FAA8F;AAC9F,MAAM,UAAU,eAAe,CAAC,QAAiB;IAC/C,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1F,CAAC;AAED,gFAAgF;AAChF,6EAA6E;AAC7E,2EAA2E;AAC3E,uEAAuE;AACvE,6CAA6C;AAC7C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAMjE,MAAM,UAAU,aAAa,CAAC,IAAuB;IACnD,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;AACH,CAAC","sourcesContent":["import { CREATE } from './create.ts';\nimport type { DefinedTool, ToolDeps } from './define.ts';\nimport { DELETE } from './delete.ts';\nimport { DIFF } from './diff.ts';\nimport { EDIT } from './edit.ts';\nimport { FIND_FILES } from './find-files.ts';\nimport { LIST_ROOTS } from './list-roots.ts';\nimport { LIST } from './list.ts';\nimport { MOVE } from './move.ts';\nimport { PATCH } from './patch.ts';\nimport { READ } from './read.ts';\nimport { REPLACE_TEXT } from './replace-text.ts';\nimport { SEARCH_TEXT } from './search-text.ts';\nimport { STAT } from './stat.ts';\n\nexport const ALL_TOOLS = [\n CREATE,\n DELETE,\n DIFF,\n EDIT,\n LIST,\n MOVE,\n PATCH,\n READ,\n REPLACE_TEXT,\n LIST_ROOTS,\n SEARCH_TEXT,\n FIND_FILES,\n STAT,\n] as const;\n\nexport const MUTATING_TOOL_NAMES = new Set(\n ALL_TOOLS.filter((t) => !t.readOnlyHint).map((t) => t.name),\n);\n\n/** The tools a server registers at this setting — the one owner of the `--read-only` gate. */\nexport function registeredTools(readOnly: boolean): readonly DefinedTool[] {\n return readOnly ? ALL_TOOLS.filter((t) => !MUTATING_TOOL_NAMES.has(t.name)) : ALL_TOOLS;\n}\n\n// Re-exported so documentation surfaces quote `.name` off the definition rather\n// than repeating the string. This module is the only owner of the inventory.\n// Only the read-only tools are named individually: the mutating six are no\n// longer listed by hand anywhere, so their names reach callers through\n// MUTATING_TOOL_NAMES and ALL_TOOLS instead.\nexport { LIST, LIST_ROOTS, READ, SEARCH_TEXT, FIND_FILES, STAT };\n\ninterface ToolRegistrarDeps extends ToolDeps {\n readonly readOnly?: boolean;\n}\n\nexport function registerTools(deps: ToolRegistrarDeps): void {\n for (const tool of registeredTools(deps.readOnly ?? false)) {\n tool.register(deps);\n }\n}\n"]}
|
package/dist/tools/list.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AAiOA,eAAO,MAAM,IAAI,mCA8Ff,CAAC"}
|
package/dist/tools/list.js
CHANGED
|
@@ -147,71 +147,6 @@ const ListInputSchema = z.strictObject({
|
|
|
147
147
|
includeIgnored: IncludeIgnored,
|
|
148
148
|
cursor: CursorSchema,
|
|
149
149
|
});
|
|
150
|
-
async function handleList(args, ctx) {
|
|
151
|
-
const path = args.path;
|
|
152
|
-
const resolvedPath = ctx.fs.pathGuard.resolvePathOrRoot(path);
|
|
153
|
-
const queryKey = JSON.stringify({
|
|
154
|
-
method: 'list',
|
|
155
|
-
path: resolvedPath,
|
|
156
|
-
maxDepth: args.maxDepth,
|
|
157
|
-
includeHidden: args.includeHidden,
|
|
158
|
-
includeIgnored: args.includeIgnored,
|
|
159
|
-
});
|
|
160
|
-
const paged = await paginate({
|
|
161
|
-
store: ctx.pageStore,
|
|
162
|
-
queryKey,
|
|
163
|
-
cursor: args.cursor,
|
|
164
|
-
pageSize: args.maxEntries,
|
|
165
|
-
produce: async () => {
|
|
166
|
-
const validDir = await ctx.fs.pathGuard.validateExistingDirectory(resolvedPath);
|
|
167
|
-
const result = await collect(validDir, {
|
|
168
|
-
maxDepth: args.maxDepth,
|
|
169
|
-
includeHidden: args.includeHidden,
|
|
170
|
-
includeIgnored: args.includeIgnored,
|
|
171
|
-
signal: AbortSignal.any([ctx.signal, AbortSignal.timeout(DEFAULT_SEARCH_TIMEOUT_MS)]),
|
|
172
|
-
pathGuard: ctx.fs.pathGuard,
|
|
173
|
-
entryCap: MAX_LIST_ENTRIES,
|
|
174
|
-
onProgress: ctx.onProgress,
|
|
175
|
-
});
|
|
176
|
-
return {
|
|
177
|
-
items: result.entries,
|
|
178
|
-
metadata: {
|
|
179
|
-
path: validDir,
|
|
180
|
-
totalEntries: result.totalEntries,
|
|
181
|
-
totalFiles: result.totalFiles,
|
|
182
|
-
totalDirectories: result.totalDirectories,
|
|
183
|
-
},
|
|
184
|
-
truncated: result.totalEntries > result.entries.length,
|
|
185
|
-
};
|
|
186
|
-
},
|
|
187
|
-
externalize: (entries, metadata) => {
|
|
188
|
-
const name = basename(metadata.path);
|
|
189
|
-
// The stored tree is the whole collected set, bounded by the hard cap.
|
|
190
|
-
const fullOutput = {
|
|
191
|
-
entries,
|
|
192
|
-
markdown: renderMarkdown(name, entries),
|
|
193
|
-
totalEntries: metadata.totalEntries,
|
|
194
|
-
totalFiles: metadata.totalFiles,
|
|
195
|
-
totalDirectories: metadata.totalDirectories,
|
|
196
|
-
...(metadata.totalEntries > entries.length ? { truncated: true } : {}),
|
|
197
|
-
};
|
|
198
|
-
return putJsonResource(ctx.resourceStore, `${name} tree`, fullOutput);
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
const resourceUri = paged.resource?.entry.uri;
|
|
202
|
-
return {
|
|
203
|
-
structured: {
|
|
204
|
-
...paged.metadata,
|
|
205
|
-
entries: [...paged.page],
|
|
206
|
-
entryCount: paged.page.length,
|
|
207
|
-
...(resourceUri !== undefined ? { resourceUri } : {}),
|
|
208
|
-
...(paged.nextCursor !== undefined ? { nextCursor: paged.nextCursor } : {}),
|
|
209
|
-
},
|
|
210
|
-
markdown: renderMarkdown(basename(paged.metadata.path), [...paged.page]),
|
|
211
|
-
offset: paged.offset,
|
|
212
|
-
...(paged.resource ? { link: paged.resource.link } : {}),
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
150
|
export const LIST = defineTool({
|
|
216
151
|
name: 'list',
|
|
217
152
|
title: 'List',
|
|
@@ -227,13 +162,68 @@ export const LIST = defineTool({
|
|
|
227
162
|
}),
|
|
228
163
|
accessPaths: (args) => (args.path ? [args.path] : []),
|
|
229
164
|
run: async (args, ctx) => {
|
|
230
|
-
const
|
|
165
|
+
const resolvedPath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);
|
|
166
|
+
const queryKey = JSON.stringify({
|
|
167
|
+
method: 'list',
|
|
168
|
+
path: resolvedPath,
|
|
169
|
+
maxDepth: args.maxDepth,
|
|
170
|
+
includeHidden: args.includeHidden,
|
|
171
|
+
includeIgnored: args.includeIgnored,
|
|
172
|
+
});
|
|
173
|
+
const paged = await paginate({
|
|
174
|
+
store: ctx.pageStore,
|
|
175
|
+
queryKey,
|
|
176
|
+
cursor: args.cursor,
|
|
177
|
+
pageSize: args.maxEntries,
|
|
178
|
+
produce: async () => {
|
|
179
|
+
const validDir = await ctx.fs.pathGuard.validateExistingDirectory(resolvedPath);
|
|
180
|
+
const result = await collect(validDir, {
|
|
181
|
+
maxDepth: args.maxDepth,
|
|
182
|
+
includeHidden: args.includeHidden,
|
|
183
|
+
includeIgnored: args.includeIgnored,
|
|
184
|
+
signal: ctx.signal,
|
|
185
|
+
pathGuard: ctx.fs.pathGuard,
|
|
186
|
+
entryCap: MAX_LIST_ENTRIES,
|
|
187
|
+
onProgress: ctx.onProgress,
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
items: result.entries,
|
|
191
|
+
metadata: {
|
|
192
|
+
path: validDir,
|
|
193
|
+
totalEntries: result.totalEntries,
|
|
194
|
+
totalFiles: result.totalFiles,
|
|
195
|
+
totalDirectories: result.totalDirectories,
|
|
196
|
+
},
|
|
197
|
+
truncated: result.totalEntries > result.entries.length,
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
externalize: (entries, metadata) => {
|
|
201
|
+
const name = basename(metadata.path);
|
|
202
|
+
// The stored tree is the whole collected set, bounded by the hard cap.
|
|
203
|
+
const fullOutput = {
|
|
204
|
+
entries,
|
|
205
|
+
markdown: renderMarkdown(name, entries),
|
|
206
|
+
totalEntries: metadata.totalEntries,
|
|
207
|
+
totalFiles: metadata.totalFiles,
|
|
208
|
+
totalDirectories: metadata.totalDirectories,
|
|
209
|
+
...(metadata.totalEntries > entries.length ? { truncated: true } : {}),
|
|
210
|
+
};
|
|
211
|
+
return putJsonResource(ctx.resourceStore, `${name} tree`, fullOutput);
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
const structured = {
|
|
215
|
+
...paged.metadata,
|
|
216
|
+
entries: [...paged.page],
|
|
217
|
+
entryCount: paged.page.length,
|
|
218
|
+
...(paged.resource ? { resourceUri: paged.resource.entry.uri } : {}),
|
|
219
|
+
...(paged.nextCursor !== undefined ? { nextCursor: paged.nextCursor } : {}),
|
|
220
|
+
};
|
|
231
221
|
// The tree is what the model reads, so position and the full-list URI ride
|
|
232
222
|
// the text too — paging needs no second lookup. `pageTrailer` is the one
|
|
233
223
|
// owner of that line, and it owes it on the last page as much as the first.
|
|
234
|
-
const text =
|
|
224
|
+
const text = renderMarkdown(basename(paged.metadata.path), [...paged.page]) +
|
|
235
225
|
pageTrailer({
|
|
236
|
-
offset,
|
|
226
|
+
offset: paged.offset,
|
|
237
227
|
shown: structured.entryCount,
|
|
238
228
|
total: structured.totalEntries,
|
|
239
229
|
noun: 'entries',
|
|
@@ -245,7 +235,7 @@ export const LIST = defineTool({
|
|
|
245
235
|
return {
|
|
246
236
|
structured,
|
|
247
237
|
text,
|
|
248
|
-
...(
|
|
238
|
+
...(paged.resource ? { resources: [paged.resource.link] } : {}),
|
|
249
239
|
};
|
|
250
240
|
},
|
|
251
241
|
});
|