@j0hanz/filesystem-mcp 2.6.3 → 2.7.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 +27 -18
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +5 -2
- package/dist/cli-help.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -3
- package/dist/cli.js.map +1 -1
- package/dist/core/concurrency.d.ts +0 -17
- package/dist/core/concurrency.d.ts.map +1 -1
- package/dist/core/concurrency.js +0 -10
- package/dist/core/concurrency.js.map +1 -1
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +7 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/diff.d.ts +0 -4
- package/dist/core/diff.d.ts.map +1 -1
- package/dist/core/diff.js +1 -15
- package/dist/core/diff.js.map +1 -1
- package/dist/core/file-uri.d.ts +9 -9
- package/dist/core/file-uri.d.ts.map +1 -1
- package/dist/core/file-uri.js +16 -11
- package/dist/core/file-uri.js.map +1 -1
- package/dist/core/fs.d.ts +1 -1
- package/dist/core/fs.d.ts.map +1 -1
- package/dist/core/fs.js +65 -56
- package/dist/core/fs.js.map +1 -1
- package/dist/core/glob.d.ts +6 -0
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/glob.js +64 -8
- package/dist/core/glob.js.map +1 -1
- package/dist/core/input-required.d.ts +15 -3
- package/dist/core/input-required.d.ts.map +1 -1
- package/dist/core/input-required.js +30 -5
- package/dist/core/input-required.js.map +1 -1
- package/dist/core/mime.d.ts +2 -4
- package/dist/core/mime.d.ts.map +1 -1
- package/dist/core/mime.js +3 -8
- package/dist/core/mime.js.map +1 -1
- package/dist/core/path-discovery.d.ts.map +1 -1
- package/dist/core/path-discovery.js +2 -2
- package/dist/core/path-discovery.js.map +1 -1
- package/dist/core/path-utils.d.ts +1 -3
- package/dist/core/path-utils.d.ts.map +1 -1
- package/dist/core/path-utils.js +0 -3
- package/dist/core/path-utils.js.map +1 -1
- package/dist/core/path.d.ts +7 -0
- package/dist/core/path.d.ts.map +1 -1
- package/dist/core/path.js +69 -26
- package/dist/core/path.js.map +1 -1
- package/dist/core/read.d.ts +1 -0
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +4 -0
- package/dist/core/read.js.map +1 -1
- package/dist/core/schema.d.ts +0 -80
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +0 -89
- package/dist/core/schema.js.map +1 -1
- package/dist/core/search.d.ts +8 -1
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +169 -87
- package/dist/core/search.js.map +1 -1
- package/dist/core/store.d.ts +7 -11
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +19 -21
- package/dist/core/store.js.map +1 -1
- package/dist/core/util.d.ts +17 -0
- package/dist/core/util.d.ts.map +1 -1
- package/dist/core/util.js +19 -0
- package/dist/core/util.js.map +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +5 -2
- package/dist/resources.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/batch.d.ts +2 -13
- package/dist/tools/batch.d.ts.map +1 -1
- package/dist/tools/batch.js +6 -18
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/create.d.ts.map +1 -1
- package/dist/tools/create.js +25 -42
- package/dist/tools/create.js.map +1 -1
- package/dist/tools/define.d.ts +20 -23
- package/dist/tools/define.d.ts.map +1 -1
- package/dist/tools/define.js +11 -23
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/delete.d.ts.map +1 -1
- package/dist/tools/delete.js +9 -28
- package/dist/tools/delete.js.map +1 -1
- package/dist/tools/diff.d.ts.map +1 -1
- package/dist/tools/diff.js +2 -13
- package/dist/tools/diff.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +20 -53
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +3 -28
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-roots.d.ts.map +1 -1
- package/dist/tools/list-roots.js +1 -12
- package/dist/tools/list-roots.js.map +1 -1
- package/dist/tools/list.d.ts.map +1 -1
- package/dist/tools/list.js +19 -53
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/move.d.ts.map +1 -1
- package/dist/tools/move.js +54 -33
- package/dist/tools/move.js.map +1 -1
- package/dist/tools/patch.d.ts.map +1 -1
- package/dist/tools/patch.js +4 -24
- package/dist/tools/patch.js.map +1 -1
- package/dist/tools/progress.d.ts +0 -2
- package/dist/tools/progress.d.ts.map +1 -1
- package/dist/tools/progress.js +20 -12
- package/dist/tools/progress.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +7 -42
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/replace-text.d.ts.map +1 -1
- package/dist/tools/replace-text.js +20 -43
- 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 +24 -78
- package/dist/tools/search-text.js.map +1 -1
- package/dist/tools/stat.d.ts.map +1 -1
- package/dist/tools/stat.js +5 -19
- package/dist/tools/stat.js.map +1 -1
- package/dist/transport/http-policy.d.ts.map +1 -1
- package/dist/transport/http-policy.js +1 -0
- package/dist/transport/http-policy.js.map +1 -1
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +14 -9
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/stdio.d.ts.map +1 -1
- package/dist/transport/stdio.js +18 -3
- package/dist/transport/stdio.js.map +1 -1
- package/package.json +3 -3
package/dist/core/glob.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/core/glob.ts"],"names":[],"mappings":"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","sourcesContent":["import { glob as fsGlob, readFile as fsReadFile, lstat } from 'node:fs/promises';\nimport { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';\n\nimport type { Ignore } from 'ignore';\nimport ignore from 'ignore';\n\nimport { processInParallel } from './concurrency.ts';\nimport { formatUnknownErrorMessage } from './errors.ts';\nimport { Logger } from './observability.ts';\nimport type { DirentLike } from './path-utils.ts';\nimport { isWindowsDriveRelativePath, toPosixPath } from './path-utils.ts';\nimport { MIB } from './util.ts';\n\nexport function isSafeGlobSyntax(pattern: string): boolean {\n if (!pattern || pattern.trim().length === 0) {\n return false;\n }\n if (isAbsolute(pattern)) {\n return false;\n }\n if (isWindowsDriveRelativePath(pattern)) {\n return false;\n }\n // Covers every engine-specific traversal form too — `{a,..}` and `[..]` both\n // contain '..', so they are rejected here. Keep this check whole-string: the\n // per-form guards that used to follow it were unreachable because of it.\n if (pattern.includes('..')) {\n return false;\n }\n return true;\n}\n\n/** A .gitignore past this size is not a .gitignore; skip it rather than read it. */\nconst MAX_GITIGNORE_BYTES = MIB;\n\nasync function loadGitignoreFiles(\n root: string,\n gitignorePaths: readonly string[],\n manager: GitignoreManager,\n signal?: AbortSignal,\n): Promise<void> {\n await processInParallel(\n gitignorePaths,\n async (relPath) => {\n const absPath = join(root, relPath);\n try {\n // lstat, not stat: a symlinked .gitignore may point at a device, a\n // FIFO or a huge file outside the root. Only a plain, small file is a\n // rule set worth reading.\n const info = await lstat(absPath);\n if (!info.isFile() || info.size > MAX_GITIGNORE_BYTES) return;\n const contents = await fsReadFile(absPath, { encoding: 'utf-8', signal });\n const matcher = ignore();\n matcher.add(contents);\n const dir = toPosixPath(dirname(relPath));\n manager.addMatcher(dir === '.' ? '' : dir, matcher);\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n Logger.warn(`Failed to read .gitignore at ${absPath}: ${formatUnknownErrorMessage(error)}`);\n }\n },\n GLOB_BATCH_CONCURRENCY,\n signal,\n );\n}\n\nclass GitignoreManager {\n private matchers = new Map<string, Ignore>();\n\n addMatcher(dir: string, matcher: Ignore): void {\n this.matchers.set(dir, matcher);\n }\n\n /** `null` when no `.gitignore` was found, so callers skip the filter entirely. */\n static async load(\n root: string,\n signal?: AbortSignal,\n maxDepth?: number,\n ): Promise<GitignoreManager | null> {\n const manager = new GitignoreManager();\n try {\n const gitignorePaths: string[] = [];\n const gitignoreEntries = fsGlob('**/.gitignore', {\n cwd: root,\n // Skip what the walk itself skips, and stop one level past its depth\n // bound: a .gitignore at depth d only affects entries at depth >= d.\n exclude: (entry: string) => {\n const name = basename(entry);\n if (name === '.hg' || name === '.svn' || DEFAULT_EXCLUDED_NAMES.has(name)) return true;\n return maxDepth !== undefined && toPosixPath(entry).split('/').length - 1 > maxDepth;\n },\n });\n for await (const match of gitignoreEntries) {\n if (signal?.aborted) break;\n gitignorePaths.push(match);\n }\n\n await loadGitignoreFiles(root, gitignorePaths, manager, signal);\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n Logger.warn(\n `Failed to enumerate .gitignore files under ${root}: ${formatUnknownErrorMessage(error)}`,\n );\n }\n return manager.matchers.size === 0 ? null : manager;\n }\n\n isIgnored(relativePath: string, isDirectory: boolean): boolean {\n const normalized = toPosixPath(relativePath);\n if (normalized === '' || normalized === '.') return false;\n const parts = normalized.split('/');\n\n // 1. Check parent directories first\n let currentDir = '';\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!part) continue;\n currentDir = currentDir ? `${currentDir}/${part}` : part;\n\n if (this.checkPath(currentDir, true)) {\n return true;\n }\n }\n\n // 2. Check the file/directory itself\n return this.checkPath(normalized, isDirectory);\n }\n\n private checkPath(posixPath: string, isDirectory: boolean): boolean {\n const parts = posixPath.split('/');\n const pathToCheck = isDirectory\n ? posixPath.endsWith('/')\n ? posixPath\n : `${posixPath}/`\n : posixPath;\n\n let ignored = false;\n\n // Check root level\n const rootMatcher = this.matchers.get('');\n if (rootMatcher) {\n const res = rootMatcher.test(pathToCheck);\n if (res.ignored) ignored = true;\n if (res.unignored) ignored = false;\n }\n\n // Check subdirectories\n let currentDir = '';\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!part) continue;\n currentDir = currentDir ? `${currentDir}/${part}` : part;\n\n const matcher = this.matchers.get(currentDir);\n if (matcher) {\n const relParts = parts.slice(i + 1);\n const relPath = relParts.join('/');\n const relPathToCheck = isDirectory\n ? relPath.endsWith('/')\n ? relPath\n : `${relPath}/`\n : relPath;\n\n const res = matcher.test(relPathToCheck);\n if (res.ignored) ignored = true;\n if (res.unignored) ignored = false;\n }\n }\n\n return ignored;\n }\n}\n\ninterface GlobDirentLike extends DirentLike {\n name: string;\n parentPath: string;\n}\n\nexport interface GlobEntry {\n path: string;\n dirent: DirentLike;\n}\n\nexport interface GlobEntriesOptions {\n cwd: string;\n pattern: string;\n includeHidden?: boolean;\n baseNameMatch?: boolean;\n maxDepth?: number;\n onlyFiles?: boolean;\n suppressErrors?: boolean;\n /** Skip what a walk should not surface: DEFAULT_EXCLUDED_NAMES and .gitignore. */\n skipIgnored?: boolean;\n /** Bounds the `.gitignore` discovery `skipIgnored` runs before the walk. */\n signal?: AbortSignal;\n}\n\ninterface NormalizedGlob {\n cwd: string;\n patterns: readonly string[];\n suppressErrors: boolean;\n maxDepth?: number;\n}\n\nconst GLOB_MAGIC_RE = /[*?[\\]{}!]/u;\nconst GLOB_BATCH_CONCURRENCY = 64;\nconst SEP = '/';\nconst DOT_CHAR_CODE = 46;\nfunction normalizePattern(pattern: string, baseNameMatch: boolean): string {\n const normalized = toPosixPath(pattern);\n\n if (!baseNameMatch) return normalized;\n if (normalized.includes(SEP)) return normalized;\n return `**/${normalized}`;\n}\n\nfunction splitPatternPrefix(normalizedPattern: string): {\n prefix: string;\n remainder: string;\n} {\n if (!GLOB_MAGIC_RE.test(normalizedPattern)) {\n return { prefix: '', remainder: normalizedPattern };\n }\n\n const segments = normalizedPattern.split(SEP);\n const splitIndex = segments.findIndex((seg) => GLOB_MAGIC_RE.test(seg));\n\n if (splitIndex <= 0) {\n return { prefix: '', remainder: normalizedPattern };\n }\n\n return {\n prefix: segments.slice(0, splitIndex).join(SEP) + SEP,\n remainder: segments.slice(splitIndex).join(SEP),\n };\n}\n\nfunction addFirstDotSegment(patterns: Set<string>, prefix: string, remainder: string): void {\n if (remainder.length === 0) return;\n const segments = remainder.split(SEP);\n const idx = segments.findIndex((seg) => seg !== '**' && seg.length > 0);\n\n if (idx !== -1) {\n const original = segments[idx];\n if (original && original.charCodeAt(0) !== DOT_CHAR_CODE) {\n const newSegments = [...segments];\n newSegments[idx] = `.${original}`;\n patterns.add(`${prefix}${newSegments.join(SEP)}`);\n }\n }\n}\n\nfunction expandHiddenGlobstars(patterns: Set<string>, prefix: string, remainder: string): void {\n // Trailing bare globstar — `src/**`, `**` (remainder is exactly `**`, no\n // following segment). The pattern itself already matches every non-dot\n // entry under the prefix; add the two hidden complements fs.glob skips:\n // dotfiles/dot-dirs anywhere, and the contents of dot-dirs anywhere.\n if (remainder === '**') {\n patterns.add(`${prefix}**/.*`);\n patterns.add(`${prefix}**/.*/**`);\n return;\n }\n\n if (!remainder.startsWith('**/')) return;\n\n const afterGlobstar = remainder.slice(3);\n // Node fs.glob skips leading-dot entries unless the matching segment itself\n // starts with '.', and its `dot` option is not honored. So `**/*` alone misses\n // hidden files. Two depth-agnostic patterns cover everything the per-depth\n // unroll did: contents of dot-directories anywhere, and dotfiles/dotdirs\n // anywhere.\n patterns.add(`${prefix}**/.*/**/${afterGlobstar}`);\n const addDotFile = afterGlobstar.length > 0 && afterGlobstar.charCodeAt(0) !== DOT_CHAR_CODE;\n if (addDotFile) patterns.add(`${prefix}**/.${afterGlobstar}`);\n}\n\nfunction buildHiddenPatterns(normalizedPattern: string): readonly string[] {\n const patterns = new Set<string>([normalizedPattern]);\n const { prefix, remainder } = splitPatternPrefix(normalizedPattern);\n\n addFirstDotSegment(patterns, prefix, remainder);\n expandHiddenGlobstars(patterns, prefix, remainder);\n\n return Array.from(patterns);\n}\n\nfunction normalizeGlobOptions(options: GlobEntriesOptions): NormalizedGlob {\n const cwd = resolve(options.cwd);\n const normalizedPattern = normalizePattern(options.pattern, options.baseNameMatch ?? false);\n\n const patterns = options.includeHidden\n ? buildHiddenPatterns(normalizedPattern)\n : [normalizedPattern];\n\n const normalized: NormalizedGlob = {\n cwd,\n patterns,\n suppressErrors: options.suppressErrors ?? false,\n };\n\n if (options.maxDepth !== undefined) {\n normalized.maxDepth = options.maxDepth;\n }\n\n return normalized;\n}\n\nfunction* processDirentMatch(\n match: GlobDirentLike,\n cwd: string,\n maxDepth: number | undefined,\n seen: Set<string>,\n onlyFiles: boolean,\n): Generator<GlobEntry> {\n const absolutePath = resolve(cwd, match.parentPath, match.name);\n\n if (maxDepth !== undefined) {\n const rel = relative(cwd, absolutePath);\n if (rel.split(/[/\\\\]/u).length - 1 > maxDepth) return;\n }\n\n if (seen.has(absolutePath)) return;\n seen.add(absolutePath);\n\n if (onlyFiles && !match.isFile()) return;\n yield { path: absolutePath, dirent: match };\n}\n\ninterface WalkFilter {\n /** Given to fs.glob: true stops descent into a directory. */\n prune: (match: GlobDirentLike) => boolean;\n /** Re-applied to yielded entries: the ignore rules only, never the depth bound. */\n isExcluded: (match: GlobDirentLike) => boolean;\n}\n\nfunction createWalkFilter(\n cwd: string,\n skipIgnored: boolean,\n gitignoreMatcher: GitignoreManager | null,\n maxDepth: number | undefined,\n): WalkFilter | undefined {\n if (!skipIgnored && maxDepth === undefined) return undefined;\n\n // fs.glob can hand the predicate a dirent whose parentPath is \".\" — the walk\n // root, not the process cwd — when it re-visits a directory under `**` whose\n // name also exists in the process cwd. Resolving against `cwd` names the\n // entry the dirent describes; `join` would resolve it against the process.\n const relativeOf = (match: GlobDirentLike): string =>\n toPosixPath(relative(cwd, resolve(cwd, match.parentPath, match.name)));\n // Every default exclude is a bare name that applies at any depth, so a Set\n // lookup per segment replaces compiling dozens of globs per entry.\n const excluded = (posixRel: string, isDir: boolean): boolean =>\n skipIgnored &&\n (posixRel.split('/').some((segment) => DEFAULT_EXCLUDED_NAMES.has(segment)) ||\n (gitignoreMatcher?.isIgnored(posixRel, isDir) ?? false));\n\n return {\n prune: (match) => {\n const posixRel = relativeOf(match);\n const isDir = match.isDirectory();\n if (excluded(posixRel, isDir)) return true;\n // Stop descent one level past the depth bound. Pruning a directory *at*\n // the bound would drop it where fs.glob treats it as top-level, so prune\n // its children instead; processDirentMatch drops that extra level.\n if (maxDepth === undefined || !isDir) return false;\n return posixRel.split('/').length - 1 > maxDepth;\n },\n isExcluded: (match) => excluded(relativeOf(match), match.isDirectory()),\n };\n}\n\nasync function* processGlobPattern(\n pattern: string,\n plan: NormalizedGlob,\n seen: Set<string>,\n onlyFiles: boolean,\n filter: WalkFilter | undefined,\n): AsyncGenerator<GlobEntry> {\n const { cwd, maxDepth, suppressErrors } = plan;\n let iterable: AsyncIterable<GlobDirentLike>;\n try {\n iterable = fsGlob(pattern, {\n cwd,\n ...(filter ? { exclude: filter.prune } : {}),\n withFileTypes: true,\n }) as AsyncIterable<GlobDirentLike>;\n } catch (error) {\n if (suppressErrors) return;\n throw error;\n }\n\n try {\n for await (const match of iterable) {\n // A function `exclude` only prunes descent in fs.glob — it still yields\n // the rejected dirent itself, and any rejected entry below the top level.\n // Re-apply the ignore rules (not the depth bound) to drop those.\n if (filter?.isExcluded(match)) continue;\n yield* processDirentMatch(match, cwd, maxDepth, seen, onlyFiles);\n }\n } catch (error) {\n if (!suppressErrors) throw error;\n Logger.warn(\n `globEntries: suppressed mid-walk error for pattern \"${pattern}\": ${formatUnknownErrorMessage(error)}`,\n );\n }\n}\n\nexport async function* globEntries(options: GlobEntriesOptions): AsyncGenerator<GlobEntry> {\n const gitignoreMatcher = options.skipIgnored\n ? await GitignoreManager.load(options.cwd, options.signal, options.maxDepth)\n : null;\n\n const plan = normalizeGlobOptions(options);\n const seen = new Set<string>();\n const onlyFiles = options.onlyFiles ?? true;\n const filter = createWalkFilter(\n plan.cwd,\n options.skipIgnored ?? false,\n gitignoreMatcher,\n plan.maxDepth,\n );\n\n for (const pattern of plan.patterns) {\n yield* processGlobPattern(pattern, plan, seen, onlyFiles, filter);\n }\n}\n\n/** Names a `skipIgnored` walk never enters or yields, at any depth. */\nconst DEFAULT_EXCLUDED_NAMES: ReadonlySet<string> = new Set([\n 'node_modules',\n 'dist',\n 'build',\n 'coverage',\n '.git',\n '.vscode',\n '.idea',\n '.DS_Store',\n '.next',\n '.nuxt',\n '.output',\n '.svelte-kit',\n '.cache',\n '.yarn',\n 'jspm_packages',\n 'bower_components',\n 'out',\n 'tmp',\n '.temp',\n 'npm-debug.log',\n 'yarn-debug.log',\n 'yarn-error.log',\n 'Thumbs.db',\n]);\n"]}
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/core/glob.ts"],"names":[],"mappings":"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","sourcesContent":["import { glob as fsGlob, readFile as fsReadFile, lstat } from 'node:fs/promises';\nimport { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';\n\nimport type { Ignore } from 'ignore';\nimport ignore from 'ignore';\n\nimport { processInParallel } from './concurrency.ts';\nimport { formatUnknownErrorMessage } from './errors.ts';\nimport { Logger } from './observability.ts';\nimport type { DirentLike } from './path-utils.ts';\nimport { isPathInsideDirectory, isWindowsDriveRelativePath, toPosixPath } from './path-utils.ts';\nimport { MIB } from './util.ts';\n\n/** `..` bounded on both sides by a separator, a brace delimiter, or the pattern edge. */\nconst TRAVERSAL_DOTDOT_RE = /(?:^|[/\\\\{,])\\.\\.(?=[/\\\\},]|$)/u;\n\nexport function isSafeGlobSyntax(pattern: string): boolean {\n if (!pattern || pattern.trim().length === 0) {\n return false;\n }\n if (isAbsolute(pattern)) {\n return false;\n }\n if (isWindowsDriveRelativePath(pattern)) {\n return false;\n }\n // Only a whole `..` — a path segment, or one alternative of a `{a,..}`\n // brace set — can traverse. `..` inside a segment (`[...slug]`, `v1..2.md`,\n // `[..]`) is a literal name or a character class, and PathGuard re-checks\n // containment on every resolved entry regardless.\n if (TRAVERSAL_DOTDOT_RE.test(pattern)) {\n return false;\n }\n return true;\n}\n\n/** A .gitignore past this size is not a .gitignore; skip it rather than read it. */\nconst MAX_GITIGNORE_BYTES = MIB;\n\nasync function loadGitignoreFiles(\n root: string,\n gitignorePaths: readonly string[],\n manager: GitignoreManager,\n signal?: AbortSignal,\n): Promise<void> {\n await processInParallel(\n gitignorePaths,\n async (relPath) => {\n const absPath = join(root, relPath);\n try {\n // lstat, not stat: a symlinked .gitignore may point at a device, a\n // FIFO or a huge file outside the root. Only a plain, small file is a\n // rule set worth reading.\n const info = await lstat(absPath);\n if (!info.isFile() || info.size > MAX_GITIGNORE_BYTES) return;\n const contents = await fsReadFile(absPath, { encoding: 'utf-8', signal });\n const matcher = ignore();\n matcher.add(contents);\n const dir = toPosixPath(dirname(relPath));\n manager.addMatcher(dir === '.' ? '' : dir, matcher);\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n Logger.warn(`Failed to read .gitignore at ${absPath}: ${formatUnknownErrorMessage(error)}`);\n }\n },\n GLOB_BATCH_CONCURRENCY,\n signal,\n );\n}\n\n/**\n * Load `.gitignore` from each ancestor of `root` up to and including `ceiling`,\n * farthest first. A rule set that ignores `root` itself is skipped: the caller\n * named that directory on purpose, and applying the rule would empty the walk.\n */\nasync function loadAncestorGitignores(\n root: string,\n ceiling: string,\n manager: GitignoreManager,\n signal?: AbortSignal,\n): Promise<void> {\n const normalizedCeiling = resolve(ceiling);\n const chain: string[] = [];\n for (let dir = dirname(resolve(root)); ; dir = dirname(dir)) {\n if (!isPathInsideDirectory(normalizedCeiling, dir)) break;\n chain.push(dir);\n if (\n (isPathInsideDirectory(dir, normalizedCeiling) &&\n isPathInsideDirectory(normalizedCeiling, dir)) ||\n dirname(dir) === dir\n ) {\n break;\n }\n }\n for (const dir of chain.reverse()) {\n signal?.throwIfAborted();\n const file = join(dir, '.gitignore');\n try {\n const info = await lstat(file);\n if (!info.isFile() || info.size > MAX_GITIGNORE_BYTES) continue;\n const matcher = ignore().add(await fsReadFile(file, { encoding: 'utf-8', signal }));\n const prefix = toPosixPath(relative(dir, root));\n if (matcher.test(`${prefix}/`).ignored) continue;\n manager.addAncestorMatcher(prefix, matcher);\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n // ENOENT is the normal case (no .gitignore at this level); anything else is not worth a warning per walk\n }\n }\n}\n\nclass GitignoreManager {\n private matchers = new Map<string, Ignore>();\n /** Rules from directories above the walk root, farthest first; `prefix` re-bases a walk-relative path to that directory. */\n private ancestors: { prefix: string; matcher: Ignore }[] = [];\n\n addMatcher(dir: string, matcher: Ignore): void {\n this.matchers.set(dir, matcher);\n }\n\n addAncestorMatcher(prefix: string, matcher: Ignore): void {\n this.ancestors.push({ prefix, matcher });\n }\n\n /** `null` when no `.gitignore` was found, so callers skip the filter entirely. */\n static async load(\n root: string,\n signal?: AbortSignal,\n maxDepth?: number,\n ignoreCeiling?: string,\n ): Promise<GitignoreManager | null> {\n const manager = new GitignoreManager();\n try {\n const gitignorePaths: string[] = [];\n const gitignoreEntries = fsGlob('**/.gitignore', {\n cwd: root,\n // Skip what the walk itself skips, and stop one level past its depth\n // bound: a .gitignore at depth d only affects entries at depth >= d.\n exclude: (entry: string) => {\n const name = basename(entry);\n if (name === '.hg' || name === '.svn' || DEFAULT_EXCLUDED_NAMES.has(name)) return true;\n return maxDepth !== undefined && toPosixPath(entry).split('/').length - 1 > maxDepth;\n },\n });\n for await (const match of gitignoreEntries) {\n if (signal?.aborted) break;\n gitignorePaths.push(match);\n }\n\n await loadGitignoreFiles(root, gitignorePaths, manager, signal);\n if (ignoreCeiling !== undefined) {\n await loadAncestorGitignores(root, ignoreCeiling, manager, signal);\n }\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') throw error;\n Logger.warn(\n `Failed to enumerate .gitignore files under ${root}: ${formatUnknownErrorMessage(error)}`,\n );\n }\n return manager.matchers.size === 0 && manager.ancestors.length === 0 ? null : manager;\n }\n\n isIgnored(relativePath: string, isDirectory: boolean): boolean {\n const normalized = toPosixPath(relativePath);\n if (normalized === '' || normalized === '.') return false;\n const parts = normalized.split('/');\n\n // 1. Check parent directories first\n let currentDir = '';\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!part) continue;\n currentDir = currentDir ? `${currentDir}/${part}` : part;\n\n if (this.checkPath(currentDir, true)) {\n return true;\n }\n }\n\n // 2. Check the file/directory itself\n return this.checkPath(normalized, isDirectory);\n }\n\n private checkPath(posixPath: string, isDirectory: boolean): boolean {\n const parts = posixPath.split('/');\n const pathToCheck = isDirectory\n ? posixPath.endsWith('/')\n ? posixPath\n : `${posixPath}/`\n : posixPath;\n\n let ignored = false;\n\n for (const { prefix, matcher } of this.ancestors) {\n const res = matcher.test(`${prefix}/${pathToCheck}`);\n if (res.ignored) ignored = true;\n if (res.unignored) ignored = false;\n }\n\n // Check root level\n const rootMatcher = this.matchers.get('');\n if (rootMatcher) {\n const res = rootMatcher.test(pathToCheck);\n if (res.ignored) ignored = true;\n if (res.unignored) ignored = false;\n }\n\n // Check subdirectories\n let currentDir = '';\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n if (!part) continue;\n currentDir = currentDir ? `${currentDir}/${part}` : part;\n\n const matcher = this.matchers.get(currentDir);\n if (matcher) {\n const relParts = parts.slice(i + 1);\n const relPath = relParts.join('/');\n const relPathToCheck = isDirectory\n ? relPath.endsWith('/')\n ? relPath\n : `${relPath}/`\n : relPath;\n\n const res = matcher.test(relPathToCheck);\n if (res.ignored) ignored = true;\n if (res.unignored) ignored = false;\n }\n }\n\n return ignored;\n }\n}\n\ninterface GlobDirentLike extends DirentLike {\n name: string;\n parentPath: string;\n}\n\nexport interface GlobEntry {\n path: string;\n dirent: DirentLike;\n}\n\nexport interface GlobEntriesOptions {\n cwd: string;\n pattern: string;\n includeHidden?: boolean;\n baseNameMatch?: boolean;\n maxDepth?: number;\n onlyFiles?: boolean;\n suppressErrors?: boolean;\n /** Skip what a walk should not surface: DEFAULT_EXCLUDED_NAMES and .gitignore. */\n skipIgnored?: boolean;\n /**\n * Topmost directory whose `.gitignore` may apply to this walk — the allowed\n * root containing `cwd`. Ancestors of `cwd` up to and including it are\n * consulted; nothing above it is ever read. Ignored without `skipIgnored`.\n */\n ignoreCeiling?: string;\n /** Bounds the `.gitignore` discovery `skipIgnored` runs before the walk. */\n signal?: AbortSignal;\n}\n\ninterface NormalizedGlob {\n cwd: string;\n patterns: readonly string[];\n suppressErrors: boolean;\n maxDepth?: number;\n}\n\nconst GLOB_MAGIC_RE = /[*?[\\]{}!]/u;\nconst GLOB_BATCH_CONCURRENCY = 64;\nconst SEP = '/';\nconst DOT_CHAR_CODE = 46;\nfunction normalizePattern(pattern: string, baseNameMatch: boolean): string {\n const normalized = toPosixPath(pattern);\n\n if (!baseNameMatch) return normalized;\n if (normalized.includes(SEP)) return normalized;\n return `**/${normalized}`;\n}\n\nfunction splitPatternPrefix(normalizedPattern: string): {\n prefix: string;\n remainder: string;\n} {\n if (!GLOB_MAGIC_RE.test(normalizedPattern)) {\n return { prefix: '', remainder: normalizedPattern };\n }\n\n const segments = normalizedPattern.split(SEP);\n const splitIndex = segments.findIndex((seg) => GLOB_MAGIC_RE.test(seg));\n\n if (splitIndex <= 0) {\n return { prefix: '', remainder: normalizedPattern };\n }\n\n return {\n prefix: segments.slice(0, splitIndex).join(SEP) + SEP,\n remainder: segments.slice(splitIndex).join(SEP),\n };\n}\n\nfunction addFirstDotSegment(patterns: Set<string>, prefix: string, remainder: string): void {\n if (remainder.length === 0) return;\n const segments = remainder.split(SEP);\n const idx = segments.findIndex((seg) => seg !== '**' && seg.length > 0);\n\n if (idx !== -1) {\n const original = segments[idx];\n if (original && original.charCodeAt(0) !== DOT_CHAR_CODE) {\n const newSegments = [...segments];\n newSegments[idx] = `.${original}`;\n patterns.add(`${prefix}${newSegments.join(SEP)}`);\n }\n }\n}\n\nfunction expandHiddenGlobstars(patterns: Set<string>, prefix: string, remainder: string): void {\n // Trailing bare globstar — `src/**`, `**` (remainder is exactly `**`, no\n // following segment). The pattern itself already matches every non-dot\n // entry under the prefix; add the two hidden complements fs.glob skips:\n // dotfiles/dot-dirs anywhere, and the contents of dot-dirs anywhere.\n if (remainder === '**') {\n patterns.add(`${prefix}**/.*`);\n patterns.add(`${prefix}**/.*/**`);\n return;\n }\n\n if (!remainder.startsWith('**/')) return;\n\n const afterGlobstar = remainder.slice(3);\n // Node fs.glob skips leading-dot entries unless the matching segment itself\n // starts with '.', and its `dot` option is not honored. So `**/*` alone misses\n // hidden files. Two depth-agnostic patterns cover everything the per-depth\n // unroll did: contents of dot-directories anywhere, and dotfiles/dotdirs\n // anywhere.\n patterns.add(`${prefix}**/.*/**/${afterGlobstar}`);\n const addDotFile = afterGlobstar.length > 0 && afterGlobstar.charCodeAt(0) !== DOT_CHAR_CODE;\n if (addDotFile) patterns.add(`${prefix}**/.${afterGlobstar}`);\n}\n\nfunction buildHiddenPatterns(normalizedPattern: string): readonly string[] {\n const patterns = new Set<string>([normalizedPattern]);\n const { prefix, remainder } = splitPatternPrefix(normalizedPattern);\n\n addFirstDotSegment(patterns, prefix, remainder);\n expandHiddenGlobstars(patterns, prefix, remainder);\n\n return Array.from(patterns);\n}\n\nfunction normalizeGlobOptions(options: GlobEntriesOptions): NormalizedGlob {\n const cwd = resolve(options.cwd);\n const normalizedPattern = normalizePattern(options.pattern, options.baseNameMatch ?? false);\n\n const patterns = options.includeHidden\n ? buildHiddenPatterns(normalizedPattern)\n : [normalizedPattern];\n\n const normalized: NormalizedGlob = {\n cwd,\n patterns,\n suppressErrors: options.suppressErrors ?? false,\n };\n\n if (options.maxDepth !== undefined) {\n normalized.maxDepth = options.maxDepth;\n }\n\n return normalized;\n}\n\nfunction* processDirentMatch(\n match: GlobDirentLike,\n cwd: string,\n maxDepth: number | undefined,\n seen: Set<string>,\n onlyFiles: boolean,\n): Generator<GlobEntry> {\n const absolutePath = resolve(cwd, match.parentPath, match.name);\n\n if (maxDepth !== undefined) {\n const rel = relative(cwd, absolutePath);\n if (rel.split(/[/\\\\]/u).length - 1 > maxDepth) return;\n }\n\n if (seen.has(absolutePath)) return;\n seen.add(absolutePath);\n\n if (onlyFiles && !match.isFile()) return;\n yield { path: absolutePath, dirent: match };\n}\n\ninterface WalkFilter {\n /** Given to fs.glob: true stops descent into a directory. */\n prune: (match: GlobDirentLike) => boolean;\n /** Re-applied to yielded entries: the ignore rules only, never the depth bound. */\n isExcluded: (match: GlobDirentLike) => boolean;\n}\n\nfunction createWalkFilter(\n cwd: string,\n skipIgnored: boolean,\n gitignoreMatcher: GitignoreManager | null,\n maxDepth: number | undefined,\n): WalkFilter | undefined {\n if (!skipIgnored && maxDepth === undefined) return undefined;\n\n // fs.glob can hand the predicate a dirent whose parentPath is \".\" — the walk\n // root, not the process cwd — when it re-visits a directory under `**` whose\n // name also exists in the process cwd. Resolving against `cwd` names the\n // entry the dirent describes; `join` would resolve it against the process.\n const relativeOf = (match: GlobDirentLike): string =>\n toPosixPath(relative(cwd, resolve(cwd, match.parentPath, match.name)));\n // Every default exclude is a bare name that applies at any depth, so a Set\n // lookup per segment replaces compiling dozens of globs per entry.\n const excluded = (posixRel: string, isDir: boolean): boolean =>\n skipIgnored &&\n (posixRel.split('/').some((segment) => DEFAULT_EXCLUDED_NAMES.has(segment)) ||\n (gitignoreMatcher?.isIgnored(posixRel, isDir) ?? false));\n\n return {\n prune: (match) => {\n const posixRel = relativeOf(match);\n const isDir = match.isDirectory();\n if (excluded(posixRel, isDir)) return true;\n // Stop descent one level past the depth bound. Pruning a directory *at*\n // the bound would drop it where fs.glob treats it as top-level, so prune\n // its children instead; processDirentMatch drops that extra level.\n if (maxDepth === undefined || !isDir) return false;\n return posixRel.split('/').length - 1 > maxDepth;\n },\n isExcluded: (match) => excluded(relativeOf(match), match.isDirectory()),\n };\n}\n\nasync function* processGlobPattern(\n pattern: string,\n plan: NormalizedGlob,\n seen: Set<string>,\n onlyFiles: boolean,\n filter: WalkFilter | undefined,\n): AsyncGenerator<GlobEntry> {\n const { cwd, maxDepth, suppressErrors } = plan;\n let iterable: AsyncIterable<GlobDirentLike>;\n try {\n iterable = fsGlob(pattern, {\n cwd,\n ...(filter ? { exclude: filter.prune } : {}),\n withFileTypes: true,\n }) as AsyncIterable<GlobDirentLike>;\n } catch (error) {\n if (suppressErrors) return;\n throw error;\n }\n\n try {\n for await (const match of iterable) {\n // A function `exclude` only prunes descent in fs.glob — it still yields\n // the rejected dirent itself, and any rejected entry below the top level.\n // Re-apply the ignore rules (not the depth bound) to drop those.\n if (filter?.isExcluded(match)) continue;\n yield* processDirentMatch(match, cwd, maxDepth, seen, onlyFiles);\n }\n } catch (error) {\n if (!suppressErrors) throw error;\n Logger.warn(\n `globEntries: suppressed mid-walk error for pattern \"${pattern}\": ${formatUnknownErrorMessage(error)}`,\n );\n }\n}\n\nexport async function* globEntries(options: GlobEntriesOptions): AsyncGenerator<GlobEntry> {\n const gitignoreMatcher = options.skipIgnored\n ? await GitignoreManager.load(\n options.cwd,\n options.signal,\n options.maxDepth,\n options.ignoreCeiling,\n )\n : null;\n\n const plan = normalizeGlobOptions(options);\n const seen = new Set<string>();\n const onlyFiles = options.onlyFiles ?? true;\n const filter = createWalkFilter(\n plan.cwd,\n options.skipIgnored ?? false,\n gitignoreMatcher,\n plan.maxDepth,\n );\n\n for (const pattern of plan.patterns) {\n yield* processGlobPattern(pattern, plan, seen, onlyFiles, filter);\n }\n}\n\n/** Names a `skipIgnored` walk never enters or yields, at any depth. */\nconst DEFAULT_EXCLUDED_NAMES: ReadonlySet<string> = new Set([\n 'node_modules',\n 'dist',\n 'build',\n 'coverage',\n '.git',\n '.vscode',\n '.idea',\n '.DS_Store',\n '.next',\n '.nuxt',\n '.output',\n '.svelte-kit',\n '.cache',\n '.yarn',\n 'jspm_packages',\n 'bower_components',\n 'out',\n 'tmp',\n '.temp',\n 'npm-debug.log',\n 'yarn-debug.log',\n 'yarn-error.log',\n 'Thumbs.db',\n]);\n"]}
|
|
@@ -10,6 +10,12 @@ type PendingOp = 'delete' | 'move' | 'copy' | 'create' | 'grant';
|
|
|
10
10
|
export interface PendingState {
|
|
11
11
|
readonly op: PendingOp;
|
|
12
12
|
readonly paths: readonly string[];
|
|
13
|
+
/**
|
|
14
|
+
* Set on the state of a round minted because the previous round's answer
|
|
15
|
+
* was dropped by the SDK (`droppedInputResponseKeys`). Sealed in the HMAC
|
|
16
|
+
* payload, so a client cannot clear it: the re-issue happens once.
|
|
17
|
+
*/
|
|
18
|
+
readonly reissued?: true;
|
|
13
19
|
}
|
|
14
20
|
/** One embedded form-mode confirmation, keyed within the call. */
|
|
15
21
|
export interface PendingInput {
|
|
@@ -62,10 +68,12 @@ interface PendingRoundTripOpts {
|
|
|
62
68
|
readonly requestState: (() => PendingState | undefined) | undefined;
|
|
63
69
|
/**
|
|
64
70
|
* What the client declared it can do, or `undefined` when this connection
|
|
65
|
-
* cannot say. Only
|
|
71
|
+
* cannot say. Only positively-absent form support short-circuits; see
|
|
66
72
|
* {@link assertCanElicit}.
|
|
67
73
|
*/
|
|
68
74
|
readonly clientCapabilities?: ClientCapabilities | undefined;
|
|
75
|
+
/** `ctx.mcpReq.droppedInputResponseKeys` for this round; see `ToolCtx`. */
|
|
76
|
+
readonly droppedInputResponseKeys?: readonly string[] | undefined;
|
|
69
77
|
readonly buildInputs: (pending: readonly string[]) => readonly PendingInput[];
|
|
70
78
|
/** The live handler context; the codec binds the minted state to its method and caller. */
|
|
71
79
|
readonly serverCtx: ServerContext;
|
|
@@ -114,7 +122,11 @@ export declare function readAcceptedChoice(responses: Record<string, unknown> |
|
|
|
114
122
|
* expected set before acting.
|
|
115
123
|
*/
|
|
116
124
|
export declare function readAcceptedMultiChoice(responses: Record<string, unknown> | undefined, key: string): string[] | undefined;
|
|
117
|
-
/**
|
|
118
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Refusal wording for the `CANCELLED` error; call after a `readAccepted*` reader
|
|
127
|
+
* returned nothing. Pass the round's `droppedInputResponseKeys` so a dropped
|
|
128
|
+
* answer is named as such rather than as 'not answered'.
|
|
129
|
+
*/
|
|
130
|
+
export declare function describeRefusal(responses: Record<string, unknown> | undefined, key: string, droppedKeys?: readonly string[]): string;
|
|
119
131
|
export {};
|
|
120
132
|
//# sourceMappingURL=input-required.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-required.d.ts","sourceRoot":"","sources":["../../src/core/input-required.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,kBAAkB,EAElB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACd,MAAM,8BAA8B,CAAC;AAetC,mEAAmE;AACnE,KAAK,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"input-required.d.ts","sourceRoot":"","sources":["../../src/core/input-required.ts"],"names":[],"mappings":"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"}
|
|
@@ -80,7 +80,11 @@ export async function buildInputRequired(pending, inputs, ctx) {
|
|
|
80
80
|
requestedSchema: requestedSchemaFor(input),
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
const requestState = await requestStateCodec.mint({
|
|
83
|
+
const requestState = await requestStateCodec.mint({
|
|
84
|
+
op: pending.op,
|
|
85
|
+
paths: [...pending.paths].sort(),
|
|
86
|
+
...(pending.reissued ? { reissued: true } : {}),
|
|
87
|
+
}, ctx);
|
|
84
88
|
return inputRequired({ inputRequests, requestState });
|
|
85
89
|
}
|
|
86
90
|
/**
|
|
@@ -101,7 +105,7 @@ const NO_ELICITATION_HINT = {
|
|
|
101
105
|
'Call list_roots and use a path under one of the roots it returns.',
|
|
102
106
|
};
|
|
103
107
|
/**
|
|
104
|
-
* Fail early, and legibly, when the client cannot answer an embedded
|
|
108
|
+
* Fail early, and legibly, when the client cannot answer an embedded form.
|
|
105
109
|
* The SDK checks each `inputRequests` entry against the declared client
|
|
106
110
|
* capabilities and rejects the whole call with `-32021` before anything reaches
|
|
107
111
|
* the wire — a protocol error the model never sees. Throwing `FsError` here
|
|
@@ -115,8 +119,11 @@ const NO_ELICITATION_HINT = {
|
|
|
115
119
|
function assertCanElicit(op, capabilities) {
|
|
116
120
|
if (capabilities === undefined)
|
|
117
121
|
return;
|
|
118
|
-
|
|
122
|
+
const elicitation = capabilities.elicitation;
|
|
123
|
+
if (elicitation !== undefined &&
|
|
124
|
+
(elicitation.form !== undefined || elicitation.url === undefined)) {
|
|
119
125
|
return;
|
|
126
|
+
}
|
|
120
127
|
throw new FsError(ErrorCode.INVALID_INPUT, `${op}: ${NO_ELICITATION_HINT[op]}`);
|
|
121
128
|
}
|
|
122
129
|
export async function pendingRoundTrip(opts) {
|
|
@@ -136,6 +143,17 @@ export async function pendingRoundTrip(opts) {
|
|
|
136
143
|
if (!pathsEqual(state.paths, opts.pending)) {
|
|
137
144
|
throw new FsError(ErrorCode.INVALID_INPUT, `${opts.op}: confirmation does not match the requested paths`);
|
|
138
145
|
}
|
|
146
|
+
// The client answered, but in a shape the SDK discards before the handler
|
|
147
|
+
// runs (`{ method, result }` around the bare result). Ask the same question
|
|
148
|
+
// once more rather than report a refusal the user never made; the sealed
|
|
149
|
+
// `reissued` flag stops a second retry from looping.
|
|
150
|
+
if (state.reissued !== true && opts.droppedInputResponseKeys?.length) {
|
|
151
|
+
const dropped = new Set(opts.droppedInputResponseKeys);
|
|
152
|
+
const inputs = opts.buildInputs(opts.pending);
|
|
153
|
+
if (inputs.some((input) => dropped.has(input.key))) {
|
|
154
|
+
return buildInputRequired({ op: opts.op, paths: opts.pending, reissued: true }, inputs, opts.serverCtx);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
139
157
|
return undefined;
|
|
140
158
|
}
|
|
141
159
|
/**
|
|
@@ -189,8 +207,15 @@ export function readAcceptedChoice(responses, key) {
|
|
|
189
207
|
export function readAcceptedMultiChoice(responses, key) {
|
|
190
208
|
return acceptedContent(responses, key, MultiChoiceContent)?.choice;
|
|
191
209
|
}
|
|
192
|
-
/**
|
|
193
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Refusal wording for the `CANCELLED` error; call after a `readAccepted*` reader
|
|
212
|
+
* returned nothing. Pass the round's `droppedInputResponseKeys` so a dropped
|
|
213
|
+
* answer is named as such rather than as 'not answered'.
|
|
214
|
+
*/
|
|
215
|
+
export function describeRefusal(responses, key, droppedKeys) {
|
|
216
|
+
if (droppedKeys?.includes(key)) {
|
|
217
|
+
return 'answered in a shape this server cannot read (a wrapped result instead of the bare elicitation result), twice';
|
|
218
|
+
}
|
|
194
219
|
const view = inputResponse(responses, key);
|
|
195
220
|
if (view.kind !== 'elicit')
|
|
196
221
|
return 'not answered';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-required.js","sourceRoot":"","sources":["../../src/core/input-required.ts"],"names":[],"mappings":"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","sourcesContent":["// Shared infrastructure for the SEP-2577 `input_required` multi-round-trip\n// destructive-confirmation flows (recursive delete, move overwrite, out-of-root\n// access grant). A handler returns `inputRequired(...)` instead of the deprecated\n// push-style server-to-client elicitation request; the client retries the same\n// `tools/call` carrying `inputResponses`, and the handler re-enters from the top\n// reading the verified `requestState` and the accepted responses.\n//\n// `requestState` round-trips through the client (attacker-controlled on\n// re-entry), so it is sealed with the SDK's HMAC-SHA256 codec. The payload binds\n// each confirmation to its operation kind and sorted target-path set (spec R9,\n// R10); the handler additionally rejects any retry whose decoded paths do not\n// match the retried request's parameters (the codec only proves the state was\n// not tampered — it cannot see the current args).\nimport type {\n ClientCapabilities,\n InputRequest,\n InputRequiredResult,\n RequestStateCodec,\n ServerContext,\n} from '@modelcontextprotocol/server';\nimport {\n acceptedContent,\n createRequestStateCodec,\n inputRequired,\n inputResponse,\n} from '@modelcontextprotocol/server';\n\nimport { randomBytes } from 'node:crypto';\n\nimport * as z from 'zod/v4';\n\nimport { ErrorCode, FsError } from './errors.ts';\nimport { Logger } from './observability.ts';\n\n/** The destructive operation a pending confirmation authorizes. */\ntype PendingOp = 'delete' | 'move' | 'copy' | 'create' | 'grant';\n\n/**\n * Integrity-protected state minted into an `input_required` result and echoed\n * back by the client on retry. `paths` is the sorted canonical set of target\n * paths the confirmation covers; the handler compares it to the retried\n * request's parameters and rejects a mismatch (R9).\n */\nexport interface PendingState {\n readonly op: PendingOp;\n readonly paths: readonly string[];\n}\n\n/** One embedded form-mode confirmation, keyed within the call. */\nexport interface PendingInput {\n /** Server-assigned key, unique within the `tools/call`. */\n readonly key: string;\n /** Human-readable prompt for this item. */\n readonly message: string;\n /**\n * When set, the form offers a single-select enum (`choice` field) over\n * these values instead of a boolean `confirm`.\n */\n readonly choices?: readonly string[];\n /**\n * When set with `choices`, the form offers a multi-select enum: `choice` is\n * a string array (`MultiSelectEnumSchema` shape) and the caller reads the\n * accepted set with `readAcceptedMultiChoice`. Single-select otherwise.\n */\n readonly multi?: boolean;\n}\n\n/**\n * HMAC key for the requestState codec. Read once from\n * `FS_REQUEST_STATE_KEY` (UTF-8, must be >=32 bytes); a random\n * 32-byte key is generated at boot when the env var is unset or too short. A\n * per-process key is correct for stdio and the single-node HTTP leg (decision\n * record 11). A server restart invalidates in-flight tokens; the client\n * re-requests, which is fail-closed and safe.\n */\nfunction configuredRequestStateKey(): Uint8Array | undefined {\n const env = process.env['FS_REQUEST_STATE_KEY'];\n if (env) {\n const bytes = Buffer.from(env, 'utf8');\n if (bytes.length >= 32) return bytes;\n Logger.warn(\n `FS_REQUEST_STATE_KEY is ${String(bytes.length)} bytes; 32 are required. Falling back to a random per-boot key — in-flight input_required rounds will not survive a restart.`,\n );\n }\n return undefined;\n}\n\n/**\n * What a minted `requestState` is bound to: the JSON-RPC method of the\n * request that minted it and the authenticated caller (`ctx.http` is absent\n * on stdio, so the caller part is empty there and constant across rounds).\n * The SDK stores an HMAC tag of this value in the token and refuses an echo\n * whose context yields a different value.\n */\nfunction requestStateBinding(ctx: ServerContext): string {\n return `${ctx.mcpReq.method}\\0${ctx.http?.authInfo?.clientId ?? ''}`;\n}\n\n/**\n * The codec: `mint` seals a `PendingState` into the opaque wire string a\n * handler returns from `inputRequired({ requestState })`; `verify` drops into\n * `ServerOptions.requestState.verify` and throws on tamper, expiry, or bind\n * mismatch (the seam answers with the frozen `-32602`).\n */\nexport const requestStateCodec: RequestStateCodec<PendingState> =\n createRequestStateCodec<PendingState>({\n key: configuredRequestStateKey() ?? randomBytes(32),\n bind: requestStateBinding,\n });\n\n// Response shapes handed to the SDK's schema-aware `acceptedContent` overload:\n// it returns `undefined` for a missing key, a decline/cancel, a non-elicit\n// response, AND a payload that fails validation — one call covers every refusal\n// case the readers below used to hand-check. `buildInputRequired` reuses\n// `ConfirmContent` as the no-choices form schema (below), so these sit above it.\nconst ConfirmContent = z.object({ confirm: z.boolean().meta({ title: 'Confirm' }) });\nconst ChoiceContent = z.object({ choice: z.string() });\nconst MultiChoiceContent = z.object({ choice: z.array(z.string()) });\n\n/**\n * The form the client renders for one pending input, as the Zod schema the\n * SDK converts to the elicitation wire shape. A boolean `confirm` when no\n * choices are offered; otherwise a `choice` enum over the offered values,\n * wrapped in an array for multi-select so the client may accept a subset.\n * The offered lists are never empty by construction (single-select always\n * offers two literals; multi-select only runs with two or more grant dirs),\n * so no empty-array guard is added. Each field carries a `title` so a host\n * that renders the form labels it instead of showing the property name.\n */\nfunction requestedSchemaFor(input: PendingInput): z.ZodObject {\n if (!input.choices) return ConfirmContent;\n const value = z.enum(input.choices);\n return z.object({\n choice: input.multi ? z.array(value).meta({ title: 'Allow' }) : value.meta({ title: 'Action' }),\n });\n}\n\n/**\n * Build an `input_required` result carrying one boolean confirmation per pending\n * item, plus the integrity-protected `requestState` sealing the operation kind\n * and sorted target paths. `mint` is async (HMAC + base64url).\n */\nexport async function buildInputRequired(\n pending: PendingState,\n inputs: readonly PendingInput[],\n ctx: ServerContext,\n): Promise<InputRequiredResult> {\n const inputRequests: Record<string, InputRequest> = {};\n for (const input of inputs) {\n inputRequests[input.key] = inputRequired.elicit({\n message: input.message,\n requestedSchema: requestedSchemaFor(input),\n });\n }\n const requestState = await requestStateCodec.mint(\n { op: pending.op, paths: [...pending.paths].sort() },\n ctx,\n );\n return inputRequired({ inputRequests, requestState });\n}\n\n/**\n * The shared read-state → `buildInputRequired` → mismatch-throw flow used by\n * every destructive-confirmation handler (delete, move, grant). No verified\n * state, OR a verified state belonging to a different `op` (e.g. a chained\n * call's grant round already resolved and this is now that same call's own\n * delete/move confirmation round), mints a fresh `input_required` for this\n * op. A retry whose verified state matches this op but not the pending path\n * set throws `FsError(INVALID_INPUT)` (R9) — uniformly surfaced as an\n * `isError` tool result by the handler's catch. Returns `undefined` on a\n * matching same-op retry so the caller proceeds.\n *\n * One home for the R9 binding check means a future fix cannot miss two of three\n * sites. The caller supplies `buildInputs` so only the prompt text varies.\n */\ninterface PendingRoundTripOpts {\n readonly op: PendingOp;\n readonly pending: readonly string[];\n readonly requestState: (() => PendingState | undefined) | undefined;\n /**\n * What the client declared it can do, or `undefined` when this connection\n * cannot say. Only a positively-absent `elicitation` short-circuits; see\n * {@link assertCanElicit}.\n */\n readonly clientCapabilities?: ClientCapabilities | undefined;\n readonly buildInputs: (pending: readonly string[]) => readonly PendingInput[];\n /** The live handler context; the codec binds the minted state to its method and caller. */\n readonly serverCtx: ServerContext;\n}\n\n/**\n * What to tell the model when the round-trip cannot happen. Each names the way\n * forward that does not need a confirmation, or says plainly that there is\n * none — a dead end the model can report is worth more than a retry loop.\n */\nconst NO_ELICITATION_HINT: Readonly<Record<PendingOp, string>> = {\n delete:\n 'Deleting a non-empty directory needs a confirmation this client cannot show. ' +\n 'Delete the entries inside it individually, or connect a client that declares the elicitation capability.',\n move:\n 'Overwriting an existing destination needs a confirmation this client cannot show. ' +\n 'Delete the destination first, or move to a path that does not exist yet.',\n copy:\n 'Overwriting an existing destination needs a confirmation this client cannot show. ' +\n 'Pass overwrite=true to replace it without confirming, or copy to a path that does not exist yet.',\n create:\n 'Overwriting an existing file needs a confirmation this client cannot show. ' +\n 'Pass overwrite: true on that entry to replace it without confirming, append: true to add to it, or read it and use edit.',\n grant:\n 'Granting access to a directory outside the allowed roots needs a confirmation this client cannot show. ' +\n 'Call list_roots and use a path under one of the roots it returns.',\n};\n\n/**\n * Fail early, and legibly, when the client cannot answer an embedded request.\n * The SDK checks each `inputRequests` entry against the declared client\n * capabilities and rejects the whole call with `-32021` before anything reaches\n * the wire — a protocol error the model never sees. Throwing `FsError` here\n * instead lands in the tool executor's catch and reaches the model as an\n * `isError` result carrying the workaround.\n *\n * `undefined` capabilities mean the connection cannot report them, NOT that the\n * client has none: proceed and let the SDK decide, exactly as before this check\n * existed.\n */\nfunction assertCanElicit(op: PendingOp, capabilities: ClientCapabilities | undefined): void {\n if (capabilities === undefined) return;\n if (capabilities.elicitation !== undefined) return;\n throw new FsError(ErrorCode.INVALID_INPUT, `${op}: ${NO_ELICITATION_HINT[op]}`);\n}\n\nexport async function pendingRoundTrip(\n opts: PendingRoundTripOpts,\n): Promise<InputRequiredResult | undefined> {\n const state = opts.requestState?.();\n // No verified state yet, OR the verified state belongs to a different\n // flow (e.g. an access-grant round's state is still the retried request's\n // requestState after the grant was applied, and this call is now the\n // destructive-confirmation round for the SAME tool call) — either way,\n // this op has not yet had its own round-trip, so mint a fresh\n // input_required rather than treating a foreign-but-valid state as a\n // tamper/mismatch error.\n if (state?.op !== opts.op) {\n assertCanElicit(opts.op, opts.clientCapabilities);\n return buildInputRequired(\n { op: opts.op, paths: opts.pending },\n opts.buildInputs(opts.pending),\n opts.serverCtx,\n );\n }\n // Retry for THIS op (R9): the verified state must bind the same pending set.\n if (!pathsEqual(state.paths, opts.pending)) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n `${opts.op}: confirmation does not match the requested paths`,\n );\n }\n return undefined;\n}\n\n/**\n * Round-trip key for `pendingSorted[index]` — the single home of the\n * `confirm_${i}` convention. The build side mints it with the map index; the\n * read side re-derives it from the same sorted pending set the requestState\n * binds (R9), so a format change lands here once instead of at six call\n * sites.\n */\nexport function confirmKey(index: number): string {\n return `confirm_${index}`;\n}\n\n/**\n * Read one pending item's boolean confirmation from a retried request's\n * `inputResponses`. Returns `true` only when the client explicitly accepted AND\n * the `confirm` field is `true`; every other outcome (decline, cancel, missing\n * key, accept-without-confirm) returns `false`, which the caller reports as\n * `CANCELLED` (R3 proceed, R4/R5 cancelled).\n */\nexport function readAcceptedConfirm(\n responses: Record<string, unknown> | undefined,\n key: string,\n): boolean {\n return acceptedContent(responses, key, ConfirmContent)?.confirm === true;\n}\n\n/**\n * Read one pending item's enum selection from a retried request's\n * `inputResponses`. Returns the chosen `value` only when the client explicitly\n * accepted AND the `choice` field is a string; every other outcome (decline,\n * cancel, missing key, accept-without-choice) returns `undefined`, which the\n * caller reports as `CANCELLED` — same contract as the boolean reader.\n *\n * The shape is SDK-validated, but the returned value is NOT checked for\n * membership in the `choices` offered in the request schema. Callers must\n * compare against the expected values (e.g. `choice === 'overwrite'`) before\n * acting — never echo the string back into a path or trust it as an enum\n * member.\n */\nexport function readAcceptedChoice(\n responses: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n return acceptedContent(responses, key, ChoiceContent)?.choice;\n}\n\n/**\n * Read one pending item's multi-select enum selection from a retried request's\n * `inputResponses`. Returns the accepted `value`s only when the client\n * explicitly accepted AND `choice` is a string array of strings; every other\n * outcome (decline, cancel, missing key, accept-without-choice, non-array\n * `choice`, non-string elements) returns `undefined`, which the caller reports\n * as `CANCELLED` — same contract as the single-select reader.\n *\n * As with `readAcceptedChoice`, the returned values are NOT checked for\n * membership in the offered `choices`; callers must compare against the\n * expected set before acting.\n */\nexport function readAcceptedMultiChoice(\n responses: Record<string, unknown> | undefined,\n key: string,\n): string[] | undefined {\n return acceptedContent(responses, key, MultiChoiceContent)?.choice;\n}\n\n/** Refusal wording for the `CANCELLED` error; call after a `readAccepted*` reader returned nothing. */\nexport function describeRefusal(\n responses: Record<string, unknown> | undefined,\n key: string,\n): string {\n const view = inputResponse(responses, key);\n if (view.kind !== 'elicit') return 'not answered';\n if (view.action === 'decline') return 'declined by the user';\n if (view.action === 'cancel') return 'dismissed by the user';\n return 'answered without a valid choice';\n}\n\n/**\n * Order-independent equality of two sorted, de-duplicated path lists. Used to\n * compare a recomputed pending set against the `requestState`-bound set (R9):\n * both are sorted by construction, so a straight element-wise compare settles\n * it without allocating.\n */\nfunction pathsEqual(a: readonly string[], b: readonly string[]): boolean {\n // The length check is load-bearing, not an early-out: `every` alone returns\n // true whenever `a` is a prefix of a longer `b`, so a confirmation minted for\n // ['/x'] would authorize a retry for ['/x', '/y'] — a direct R9 bypass.\n return a.length === b.length && a.every((value, index) => value === b[index]);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"input-required.js","sourceRoot":"","sources":["../../src/core/input-required.ts"],"names":[],"mappings":"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","sourcesContent":["// Shared infrastructure for the SEP-2577 `input_required` multi-round-trip\n// destructive-confirmation flows (recursive delete, move overwrite, out-of-root\n// access grant). A handler returns `inputRequired(...)` instead of the deprecated\n// push-style server-to-client elicitation request; the client retries the same\n// `tools/call` carrying `inputResponses`, and the handler re-enters from the top\n// reading the verified `requestState` and the accepted responses.\n//\n// `requestState` round-trips through the client (attacker-controlled on\n// re-entry), so it is sealed with the SDK's HMAC-SHA256 codec. The payload binds\n// each confirmation to its operation kind and sorted target-path set (spec R9,\n// R10); the handler additionally rejects any retry whose decoded paths do not\n// match the retried request's parameters (the codec only proves the state was\n// not tampered — it cannot see the current args).\nimport type {\n ClientCapabilities,\n InputRequest,\n InputRequiredResult,\n RequestStateCodec,\n ServerContext,\n} from '@modelcontextprotocol/server';\nimport {\n acceptedContent,\n createRequestStateCodec,\n inputRequired,\n inputResponse,\n} from '@modelcontextprotocol/server';\n\nimport { randomBytes } from 'node:crypto';\n\nimport * as z from 'zod/v4';\n\nimport { ErrorCode, FsError } from './errors.ts';\nimport { Logger } from './observability.ts';\n\n/** The destructive operation a pending confirmation authorizes. */\ntype PendingOp = 'delete' | 'move' | 'copy' | 'create' | 'grant';\n\n/**\n * Integrity-protected state minted into an `input_required` result and echoed\n * back by the client on retry. `paths` is the sorted canonical set of target\n * paths the confirmation covers; the handler compares it to the retried\n * request's parameters and rejects a mismatch (R9).\n */\nexport interface PendingState {\n readonly op: PendingOp;\n readonly paths: readonly string[];\n /**\n * Set on the state of a round minted because the previous round's answer\n * was dropped by the SDK (`droppedInputResponseKeys`). Sealed in the HMAC\n * payload, so a client cannot clear it: the re-issue happens once.\n */\n readonly reissued?: true;\n}\n\n/** One embedded form-mode confirmation, keyed within the call. */\nexport interface PendingInput {\n /** Server-assigned key, unique within the `tools/call`. */\n readonly key: string;\n /** Human-readable prompt for this item. */\n readonly message: string;\n /**\n * When set, the form offers a single-select enum (`choice` field) over\n * these values instead of a boolean `confirm`.\n */\n readonly choices?: readonly string[];\n /**\n * When set with `choices`, the form offers a multi-select enum: `choice` is\n * a string array (`MultiSelectEnumSchema` shape) and the caller reads the\n * accepted set with `readAcceptedMultiChoice`. Single-select otherwise.\n */\n readonly multi?: boolean;\n}\n\n/**\n * HMAC key for the requestState codec. Read once from\n * `FS_REQUEST_STATE_KEY` (UTF-8, must be >=32 bytes); a random\n * 32-byte key is generated at boot when the env var is unset or too short. A\n * per-process key is correct for stdio and the single-node HTTP leg (decision\n * record 11). A server restart invalidates in-flight tokens; the client\n * re-requests, which is fail-closed and safe.\n */\nfunction configuredRequestStateKey(): Uint8Array | undefined {\n const env = process.env['FS_REQUEST_STATE_KEY'];\n if (env) {\n const bytes = Buffer.from(env, 'utf8');\n if (bytes.length >= 32) return bytes;\n Logger.warn(\n `FS_REQUEST_STATE_KEY is ${String(bytes.length)} bytes; 32 are required. Falling back to a random per-boot key — in-flight input_required rounds will not survive a restart.`,\n );\n }\n return undefined;\n}\n\n/**\n * What a minted `requestState` is bound to: the JSON-RPC method of the\n * request that minted it and the authenticated caller (`ctx.http` is absent\n * on stdio, so the caller part is empty there and constant across rounds).\n * The SDK stores an HMAC tag of this value in the token and refuses an echo\n * whose context yields a different value.\n */\nfunction requestStateBinding(ctx: ServerContext): string {\n return `${ctx.mcpReq.method}\\0${ctx.http?.authInfo?.clientId ?? ''}`;\n}\n\n/**\n * The codec: `mint` seals a `PendingState` into the opaque wire string a\n * handler returns from `inputRequired({ requestState })`; `verify` drops into\n * `ServerOptions.requestState.verify` and throws on tamper, expiry, or bind\n * mismatch (the seam answers with the frozen `-32602`).\n */\nexport const requestStateCodec: RequestStateCodec<PendingState> =\n createRequestStateCodec<PendingState>({\n key: configuredRequestStateKey() ?? randomBytes(32),\n bind: requestStateBinding,\n });\n\n// Response shapes handed to the SDK's schema-aware `acceptedContent` overload:\n// it returns `undefined` for a missing key, a decline/cancel, a non-elicit\n// response, AND a payload that fails validation — one call covers every refusal\n// case the readers below used to hand-check. `buildInputRequired` reuses\n// `ConfirmContent` as the no-choices form schema (below), so these sit above it.\nconst ConfirmContent = z.object({ confirm: z.boolean().meta({ title: 'Confirm' }) });\nconst ChoiceContent = z.object({ choice: z.string() });\nconst MultiChoiceContent = z.object({ choice: z.array(z.string()) });\n\n/**\n * The form the client renders for one pending input, as the Zod schema the\n * SDK converts to the elicitation wire shape. A boolean `confirm` when no\n * choices are offered; otherwise a `choice` enum over the offered values,\n * wrapped in an array for multi-select so the client may accept a subset.\n * The offered lists are never empty by construction (single-select always\n * offers two literals; multi-select only runs with two or more grant dirs),\n * so no empty-array guard is added. Each field carries a `title` so a host\n * that renders the form labels it instead of showing the property name.\n */\nfunction requestedSchemaFor(input: PendingInput): z.ZodObject {\n if (!input.choices) return ConfirmContent;\n const value = z.enum(input.choices);\n return z.object({\n choice: input.multi ? z.array(value).meta({ title: 'Allow' }) : value.meta({ title: 'Action' }),\n });\n}\n\n/**\n * Build an `input_required` result carrying one boolean confirmation per pending\n * item, plus the integrity-protected `requestState` sealing the operation kind\n * and sorted target paths. `mint` is async (HMAC + base64url).\n */\nexport async function buildInputRequired(\n pending: PendingState,\n inputs: readonly PendingInput[],\n ctx: ServerContext,\n): Promise<InputRequiredResult> {\n const inputRequests: Record<string, InputRequest> = {};\n for (const input of inputs) {\n inputRequests[input.key] = inputRequired.elicit({\n message: input.message,\n requestedSchema: requestedSchemaFor(input),\n });\n }\n const requestState = await requestStateCodec.mint(\n {\n op: pending.op,\n paths: [...pending.paths].sort(),\n ...(pending.reissued ? { reissued: true as const } : {}),\n },\n ctx,\n );\n return inputRequired({ inputRequests, requestState });\n}\n\n/**\n * The shared read-state → `buildInputRequired` → mismatch-throw flow used by\n * every destructive-confirmation handler (delete, move, grant). No verified\n * state, OR a verified state belonging to a different `op` (e.g. a chained\n * call's grant round already resolved and this is now that same call's own\n * delete/move confirmation round), mints a fresh `input_required` for this\n * op. A retry whose verified state matches this op but not the pending path\n * set throws `FsError(INVALID_INPUT)` (R9) — uniformly surfaced as an\n * `isError` tool result by the handler's catch. Returns `undefined` on a\n * matching same-op retry so the caller proceeds.\n *\n * One home for the R9 binding check means a future fix cannot miss two of three\n * sites. The caller supplies `buildInputs` so only the prompt text varies.\n */\ninterface PendingRoundTripOpts {\n readonly op: PendingOp;\n readonly pending: readonly string[];\n readonly requestState: (() => PendingState | undefined) | undefined;\n /**\n * What the client declared it can do, or `undefined` when this connection\n * cannot say. Only positively-absent form support short-circuits; see\n * {@link assertCanElicit}.\n */\n readonly clientCapabilities?: ClientCapabilities | undefined;\n /** `ctx.mcpReq.droppedInputResponseKeys` for this round; see `ToolCtx`. */\n readonly droppedInputResponseKeys?: readonly string[] | undefined;\n readonly buildInputs: (pending: readonly string[]) => readonly PendingInput[];\n /** The live handler context; the codec binds the minted state to its method and caller. */\n readonly serverCtx: ServerContext;\n}\n\n/**\n * What to tell the model when the round-trip cannot happen. Each names the way\n * forward that does not need a confirmation, or says plainly that there is\n * none — a dead end the model can report is worth more than a retry loop.\n */\nconst NO_ELICITATION_HINT: Readonly<Record<PendingOp, string>> = {\n delete:\n 'Deleting a non-empty directory needs a confirmation this client cannot show. ' +\n 'Delete the entries inside it individually, or connect a client that declares the elicitation capability.',\n move:\n 'Overwriting an existing destination needs a confirmation this client cannot show. ' +\n 'Delete the destination first, or move to a path that does not exist yet.',\n copy:\n 'Overwriting an existing destination needs a confirmation this client cannot show. ' +\n 'Pass overwrite=true to replace it without confirming, or copy to a path that does not exist yet.',\n create:\n 'Overwriting an existing file needs a confirmation this client cannot show. ' +\n 'Pass overwrite: true on that entry to replace it without confirming, append: true to add to it, or read it and use edit.',\n grant:\n 'Granting access to a directory outside the allowed roots needs a confirmation this client cannot show. ' +\n 'Call list_roots and use a path under one of the roots it returns.',\n};\n\n/**\n * Fail early, and legibly, when the client cannot answer an embedded form.\n * The SDK checks each `inputRequests` entry against the declared client\n * capabilities and rejects the whole call with `-32021` before anything reaches\n * the wire — a protocol error the model never sees. Throwing `FsError` here\n * instead lands in the tool executor's catch and reaches the model as an\n * `isError` result carrying the workaround.\n *\n * `undefined` capabilities mean the connection cannot report them, NOT that the\n * client has none: proceed and let the SDK decide, exactly as before this check\n * existed.\n */\nfunction assertCanElicit(op: PendingOp, capabilities: ClientCapabilities | undefined): void {\n if (capabilities === undefined) return;\n const elicitation = capabilities.elicitation;\n if (\n elicitation !== undefined &&\n (elicitation.form !== undefined || elicitation.url === undefined)\n ) {\n return;\n }\n throw new FsError(ErrorCode.INVALID_INPUT, `${op}: ${NO_ELICITATION_HINT[op]}`);\n}\n\nexport async function pendingRoundTrip(\n opts: PendingRoundTripOpts,\n): Promise<InputRequiredResult | undefined> {\n const state = opts.requestState?.();\n // No verified state yet, OR the verified state belongs to a different\n // flow (e.g. an access-grant round's state is still the retried request's\n // requestState after the grant was applied, and this call is now the\n // destructive-confirmation round for the SAME tool call) — either way,\n // this op has not yet had its own round-trip, so mint a fresh\n // input_required rather than treating a foreign-but-valid state as a\n // tamper/mismatch error.\n if (state?.op !== opts.op) {\n assertCanElicit(opts.op, opts.clientCapabilities);\n return buildInputRequired(\n { op: opts.op, paths: opts.pending },\n opts.buildInputs(opts.pending),\n opts.serverCtx,\n );\n }\n // Retry for THIS op (R9): the verified state must bind the same pending set.\n if (!pathsEqual(state.paths, opts.pending)) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n `${opts.op}: confirmation does not match the requested paths`,\n );\n }\n // The client answered, but in a shape the SDK discards before the handler\n // runs (`{ method, result }` around the bare result). Ask the same question\n // once more rather than report a refusal the user never made; the sealed\n // `reissued` flag stops a second retry from looping.\n if (state.reissued !== true && opts.droppedInputResponseKeys?.length) {\n const dropped = new Set(opts.droppedInputResponseKeys);\n const inputs = opts.buildInputs(opts.pending);\n if (inputs.some((input) => dropped.has(input.key))) {\n return buildInputRequired(\n { op: opts.op, paths: opts.pending, reissued: true },\n inputs,\n opts.serverCtx,\n );\n }\n }\n return undefined;\n}\n\n/**\n * Round-trip key for `pendingSorted[index]` — the single home of the\n * `confirm_${i}` convention. The build side mints it with the map index; the\n * read side re-derives it from the same sorted pending set the requestState\n * binds (R9), so a format change lands here once instead of at six call\n * sites.\n */\nexport function confirmKey(index: number): string {\n return `confirm_${index}`;\n}\n\n/**\n * Read one pending item's boolean confirmation from a retried request's\n * `inputResponses`. Returns `true` only when the client explicitly accepted AND\n * the `confirm` field is `true`; every other outcome (decline, cancel, missing\n * key, accept-without-confirm) returns `false`, which the caller reports as\n * `CANCELLED` (R3 proceed, R4/R5 cancelled).\n */\nexport function readAcceptedConfirm(\n responses: Record<string, unknown> | undefined,\n key: string,\n): boolean {\n return acceptedContent(responses, key, ConfirmContent)?.confirm === true;\n}\n\n/**\n * Read one pending item's enum selection from a retried request's\n * `inputResponses`. Returns the chosen `value` only when the client explicitly\n * accepted AND the `choice` field is a string; every other outcome (decline,\n * cancel, missing key, accept-without-choice) returns `undefined`, which the\n * caller reports as `CANCELLED` — same contract as the boolean reader.\n *\n * The shape is SDK-validated, but the returned value is NOT checked for\n * membership in the `choices` offered in the request schema. Callers must\n * compare against the expected values (e.g. `choice === 'overwrite'`) before\n * acting — never echo the string back into a path or trust it as an enum\n * member.\n */\nexport function readAcceptedChoice(\n responses: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n return acceptedContent(responses, key, ChoiceContent)?.choice;\n}\n\n/**\n * Read one pending item's multi-select enum selection from a retried request's\n * `inputResponses`. Returns the accepted `value`s only when the client\n * explicitly accepted AND `choice` is a string array of strings; every other\n * outcome (decline, cancel, missing key, accept-without-choice, non-array\n * `choice`, non-string elements) returns `undefined`, which the caller reports\n * as `CANCELLED` — same contract as the single-select reader.\n *\n * As with `readAcceptedChoice`, the returned values are NOT checked for\n * membership in the offered `choices`; callers must compare against the\n * expected set before acting.\n */\nexport function readAcceptedMultiChoice(\n responses: Record<string, unknown> | undefined,\n key: string,\n): string[] | undefined {\n return acceptedContent(responses, key, MultiChoiceContent)?.choice;\n}\n\n/**\n * Refusal wording for the `CANCELLED` error; call after a `readAccepted*` reader\n * returned nothing. Pass the round's `droppedInputResponseKeys` so a dropped\n * answer is named as such rather than as 'not answered'.\n */\nexport function describeRefusal(\n responses: Record<string, unknown> | undefined,\n key: string,\n droppedKeys?: readonly string[],\n): string {\n if (droppedKeys?.includes(key)) {\n return 'answered in a shape this server cannot read (a wrapped result instead of the bare elicitation result), twice';\n }\n const view = inputResponse(responses, key);\n if (view.kind !== 'elicit') return 'not answered';\n if (view.action === 'decline') return 'declined by the user';\n if (view.action === 'cancel') return 'dismissed by the user';\n return 'answered without a valid choice';\n}\n\n/**\n * Order-independent equality of two sorted, de-duplicated path lists. Used to\n * compare a recomputed pending set against the `requestState`-bound set (R9):\n * both are sorted by construction, so a straight element-wise compare settles\n * it without allocating.\n */\nfunction pathsEqual(a: readonly string[], b: readonly string[]): boolean {\n // The length check is load-bearing, not an early-out: `every` alone returns\n // true whenever `a` is a prefix of a longer `b`, so a confirmation minted for\n // ['/x'] would authorize a retry for ['/x', '/y'] — a direct R9 bypass.\n return a.length === b.length && a.every((value, index) => value === b[index]);\n}\n"]}
|
package/dist/core/mime.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
|
-
export
|
|
3
|
-
type MimeKind = (typeof MIME_KINDS)[number];
|
|
2
|
+
export type FileKind = 'text' | 'binary' | 'image' | 'audio' | 'pdf';
|
|
4
3
|
export interface MimeInfo {
|
|
5
4
|
mimeType: string;
|
|
6
|
-
kind:
|
|
5
|
+
kind: FileKind;
|
|
7
6
|
}
|
|
8
7
|
export declare const MIME_SAMPLE_SIZE = 512;
|
|
9
8
|
export declare function isKnownBinaryExtension(filePath: string): boolean;
|
|
@@ -12,5 +11,4 @@ export declare function hasUtf16Bom(slice: Buffer): boolean;
|
|
|
12
11
|
export declare function isBinarySample(slice: Buffer): boolean;
|
|
13
12
|
export declare function detectMimeType(path: string, sample?: Buffer): MimeInfo;
|
|
14
13
|
export declare function detectMimeFromContent(path: string, content: string | Buffer): MimeInfo;
|
|
15
|
-
export {};
|
|
16
14
|
//# sourceMappingURL=mime.d.ts.map
|
package/dist/core/mime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../../src/core/mime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAKrC,
|
|
1
|
+
{"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../../src/core/mime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAKrC,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;AAErE,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;CAChB;AA0GD,eAAO,MAAM,gBAAgB,MAAM,CAAC;AA0CpC,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGhE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKlD;AAgBD,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKrD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CActE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAOtF"}
|
package/dist/core/mime.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { extname } from 'node:path';
|
|
3
|
-
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
4
|
-
export const MIME_KINDS = ['text', 'binary', 'image', 'audio', 'pdf'];
|
|
5
3
|
// ─── Extension Map ──────────────────────────────────────────────────────────
|
|
6
4
|
// Maps file extensions to MIME types (80+ common extensions)
|
|
7
5
|
const EXT_MAP = {
|
|
@@ -166,12 +164,9 @@ export function isBinarySample(slice) {
|
|
|
166
164
|
export function detectMimeType(path, sample) {
|
|
167
165
|
const lastDot = path.lastIndexOf('.');
|
|
168
166
|
const ext = lastDot > -1 ? path.slice(lastDot + 1).toLowerCase() : '';
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return entry;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
167
|
+
const known = Object.hasOwn(EXT_MAP, ext) ? EXT_MAP[ext] : undefined;
|
|
168
|
+
if (known)
|
|
169
|
+
return known;
|
|
175
170
|
// No known extension: fall back to a binary/text probe of the content.
|
|
176
171
|
if (sample) {
|
|
177
172
|
return isBinarySample(sample.subarray(0, MIME_SAMPLE_SIZE))
|
package/dist/core/mime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mime.js","sourceRoot":"","sources":["../../src/core/mime.ts"],"names":[],"mappings":"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","sourcesContent":["import { Buffer } from 'node:buffer';\nimport { extname } from 'node:path';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport const MIME_KINDS = ['text', 'binary', 'image', 'audio', 'pdf'] as const;\ntype MimeKind = (typeof MIME_KINDS)[number];\n\nexport interface MimeInfo {\n mimeType: string;\n kind: MimeKind;\n}\n\n// ─── Extension Map ──────────────────────────────────────────────────────────\n// Maps file extensions to MIME types (80+ common extensions)\n\nconst EXT_MAP: Record<string, { mimeType: string; kind: MimeKind }> = {\n // Text: Web & Markup\n html: { mimeType: 'text/html', kind: 'text' },\n htm: { mimeType: 'text/html', kind: 'text' },\n xml: { mimeType: 'text/xml', kind: 'text' },\n css: { mimeType: 'text/css', kind: 'text' },\n svg: { mimeType: 'image/svg+xml', kind: 'image' },\n md: { mimeType: 'text/markdown', kind: 'text' },\n markdown: { mimeType: 'text/markdown', kind: 'text' },\n mdown: { mimeType: 'text/markdown', kind: 'text' },\n\n // Text: Programming Languages\n js: { mimeType: 'text/javascript', kind: 'text' },\n mjs: { mimeType: 'text/javascript', kind: 'text' },\n jsx: { mimeType: 'text/jsx', kind: 'text' },\n ts: { mimeType: 'text/typescript', kind: 'text' },\n tsx: { mimeType: 'text/tsx', kind: 'text' },\n py: { mimeType: 'text/x-python', kind: 'text' },\n java: { mimeType: 'text/x-java', kind: 'text' },\n c: { mimeType: 'text/x-c', kind: 'text' },\n cpp: { mimeType: 'text/x-cpp', kind: 'text' },\n cc: { mimeType: 'text/x-cpp', kind: 'text' },\n cxx: { mimeType: 'text/x-cpp', kind: 'text' },\n h: { mimeType: 'text/x-c', kind: 'text' },\n hpp: { mimeType: 'text/x-cpp', kind: 'text' },\n go: { mimeType: 'text/x-go', kind: 'text' },\n rs: { mimeType: 'text/x-rust', kind: 'text' },\n rb: { mimeType: 'text/x-ruby', kind: 'text' },\n php: { mimeType: 'text/x-php', kind: 'text' },\n sh: { mimeType: 'text/x-shellscript', kind: 'text' },\n bash: { mimeType: 'text/x-shellscript', kind: 'text' },\n zsh: { mimeType: 'text/x-shellscript', kind: 'text' },\n ps1: { mimeType: 'text/x-powershell', kind: 'text' },\n sql: { mimeType: 'text/x-sql', kind: 'text' },\n\n // Text: Data formats\n json: { mimeType: 'application/json', kind: 'text' },\n jsonc: { mimeType: 'application/json', kind: 'text' },\n ndjson: { mimeType: 'application/x-ndjson', kind: 'text' },\n yaml: { mimeType: 'text/yaml', kind: 'text' },\n yml: { mimeType: 'text/yaml', kind: 'text' },\n toml: { mimeType: 'text/toml', kind: 'text' },\n ini: { mimeType: 'text/plain', kind: 'text' },\n cfg: { mimeType: 'text/plain', kind: 'text' },\n conf: { mimeType: 'text/plain', kind: 'text' },\n csv: { mimeType: 'text/csv', kind: 'text' },\n\n // Text: Diff & Patches\n diff: { mimeType: 'text/x-diff', kind: 'text' },\n patch: { mimeType: 'text/x-diff', kind: 'text' },\n\n // Text: Documentation\n txt: { mimeType: 'text/plain', kind: 'text' },\n text: { mimeType: 'text/plain', kind: 'text' },\n log: { mimeType: 'text/plain', kind: 'text' },\n rst: { mimeType: 'text/x-rst', kind: 'text' },\n\n // Image formats\n png: { mimeType: 'image/png', kind: 'image' },\n jpg: { mimeType: 'image/jpeg', kind: 'image' },\n jpeg: { mimeType: 'image/jpeg', kind: 'image' },\n gif: { mimeType: 'image/gif', kind: 'image' },\n webp: { mimeType: 'image/webp', kind: 'image' },\n ico: { mimeType: 'image/x-icon', kind: 'image' },\n bmp: { mimeType: 'image/bmp', kind: 'image' },\n tiff: { mimeType: 'image/tiff', kind: 'image' },\n tif: { mimeType: 'image/tiff', kind: 'image' },\n\n // Audio formats\n mp3: { mimeType: 'audio/mpeg', kind: 'audio' },\n wav: { mimeType: 'audio/wav', kind: 'audio' },\n flac: { mimeType: 'audio/flac', kind: 'audio' },\n aac: { mimeType: 'audio/aac', kind: 'audio' },\n ogg: { mimeType: 'audio/ogg', kind: 'audio' },\n m4a: { mimeType: 'audio/mp4', kind: 'audio' },\n\n // PDF\n pdf: { mimeType: 'application/pdf', kind: 'pdf' },\n\n // Archives\n zip: { mimeType: 'application/zip', kind: 'binary' },\n tar: { mimeType: 'application/x-tar', kind: 'binary' },\n gz: { mimeType: 'application/gzip', kind: 'binary' },\n gzip: { mimeType: 'application/gzip', kind: 'binary' },\n '7z': { mimeType: 'application/x-7z-compressed', kind: 'binary' },\n rar: { mimeType: 'application/x-rar-compressed', kind: 'binary' },\n bz2: { mimeType: 'application/x-bzip2', kind: 'binary' },\n xz: { mimeType: 'application/x-xz', kind: 'binary' },\n\n // Other binary formats\n wasm: { mimeType: 'application/wasm', kind: 'binary' },\n so: { mimeType: 'application/octet-stream', kind: 'binary' },\n dylib: { mimeType: 'application/octet-stream', kind: 'binary' },\n dll: { mimeType: 'application/octet-stream', kind: 'binary' },\n exe: { mimeType: 'application/octet-stream', kind: 'binary' },\n msi: { mimeType: 'application/octet-stream', kind: 'binary' },\n dmg: { mimeType: 'application/octet-stream', kind: 'binary' },\n};\n\n// ─── Helper Functions ───────────────────────────────────────────────────────\n\nexport const MIME_SAMPLE_SIZE = 512;\n\n// Every non-text kind is binary for read purposes, except SVG — an image kind\n// whose bytes are text, and which the read path must not fast-path as binary.\n// EXT_MAP covers the extensions it knows (image/audio/pdf/binary kinds all\n// become binary here, image-kind SVG excepted); EXTRA_BINARY_EXTENSIONS lists\n// the rest that EXT_MAP does not carry but the read path must still treat as\n// binary. The two tables had drifted; this derivation resolves the drift toward\n// binary (only changes whether a file skips its content probe).\nconst EXTRA_BINARY_EXTENSIONS = [\n 'mov',\n 'avi',\n 'mkv',\n 'webm',\n 'ttf',\n 'otf',\n 'woff',\n 'woff2',\n 'doc',\n 'docx',\n 'xls',\n 'xlsx',\n 'ppt',\n 'pptx',\n 'sqlite',\n 'db',\n 'bin',\n 'dat',\n 'mp4',\n];\n\nconst KNOWN_BINARY_EXTENSIONS: ReadonlySet<string> = new Set(\n [\n ...Object.entries(EXT_MAP)\n .filter(([, v]) => v.kind !== 'text')\n .map(([k]) => k),\n ...EXTRA_BINARY_EXTENSIONS,\n ]\n .filter((ext) => ext !== 'svg')\n .map((ext) => `.${ext}`),\n);\n\nexport function isKnownBinaryExtension(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return KNOWN_BINARY_EXTENSIONS.has(ext);\n}\n\nexport function hasUtf16Bom(slice: Buffer): boolean {\n return (\n slice.length >= 2 &&\n ((slice[0] === 0xff && slice[1] === 0xfe) || (slice[0] === 0xfe && slice[1] === 0xff))\n );\n}\n\n/**\n * True when `slice` is valid UTF-8 *as a prefix*: `stream: true` parks a\n * multi-byte sequence cut by the sample boundary in the decoder's buffer\n * instead of reporting it, while `fatal: true` still throws on invalid bytes.\n */\nfunction isUtf8Prefix(slice: Buffer): boolean {\n try {\n new TextDecoder('utf-8', { fatal: true }).decode(slice, { stream: true });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Single binary-vs-text verdict, shared by `detectMimeType` and the read path. */\nexport function isBinarySample(slice: Buffer): boolean {\n if (slice.length === 0) return false;\n if (hasUtf16Bom(slice)) return false;\n if (slice.includes(0)) return true;\n return !isUtf8Prefix(slice);\n}\n\nexport function detectMimeType(path: string, sample?: Buffer): MimeInfo {\n const lastDot = path.lastIndexOf('.');\n const ext = lastDot > -1 ? path.slice(lastDot + 1).toLowerCase() : '';\n\n if (ext && Object.hasOwn(EXT_MAP, ext)) {\n const entry = EXT_MAP[ext];\n if (entry !== undefined) {\n return entry;\n }\n }\n\n // No known extension: fall back to a binary/text probe of the content.\n if (sample) {\n return isBinarySample(sample.subarray(0, MIME_SAMPLE_SIZE))\n ? { mimeType: 'application/octet-stream', kind: 'binary' }\n : { mimeType: 'text/plain', kind: 'text' };\n }\n\n return { mimeType: 'application/octet-stream', kind: 'binary' };\n}\n\nexport function detectMimeFromContent(path: string, content: string | Buffer): MimeInfo {\n return detectMimeType(\n path,\n Buffer.isBuffer(content)\n ? content.subarray(0, MIME_SAMPLE_SIZE)\n : Buffer.from(content.slice(0, MIME_SAMPLE_SIZE)),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mime.js","sourceRoot":"","sources":["../../src/core/mime.ts"],"names":[],"mappings":"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","sourcesContent":["import { Buffer } from 'node:buffer';\nimport { extname } from 'node:path';\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport type FileKind = 'text' | 'binary' | 'image' | 'audio' | 'pdf';\n\nexport interface MimeInfo {\n mimeType: string;\n kind: FileKind;\n}\n\n// ─── Extension Map ──────────────────────────────────────────────────────────\n// Maps file extensions to MIME types (80+ common extensions)\n\nconst EXT_MAP: Record<string, MimeInfo> = {\n // Text: Web & Markup\n html: { mimeType: 'text/html', kind: 'text' },\n htm: { mimeType: 'text/html', kind: 'text' },\n xml: { mimeType: 'text/xml', kind: 'text' },\n css: { mimeType: 'text/css', kind: 'text' },\n svg: { mimeType: 'image/svg+xml', kind: 'image' },\n md: { mimeType: 'text/markdown', kind: 'text' },\n markdown: { mimeType: 'text/markdown', kind: 'text' },\n mdown: { mimeType: 'text/markdown', kind: 'text' },\n\n // Text: Programming Languages\n js: { mimeType: 'text/javascript', kind: 'text' },\n mjs: { mimeType: 'text/javascript', kind: 'text' },\n jsx: { mimeType: 'text/jsx', kind: 'text' },\n ts: { mimeType: 'text/typescript', kind: 'text' },\n tsx: { mimeType: 'text/tsx', kind: 'text' },\n py: { mimeType: 'text/x-python', kind: 'text' },\n java: { mimeType: 'text/x-java', kind: 'text' },\n c: { mimeType: 'text/x-c', kind: 'text' },\n cpp: { mimeType: 'text/x-cpp', kind: 'text' },\n cc: { mimeType: 'text/x-cpp', kind: 'text' },\n cxx: { mimeType: 'text/x-cpp', kind: 'text' },\n h: { mimeType: 'text/x-c', kind: 'text' },\n hpp: { mimeType: 'text/x-cpp', kind: 'text' },\n go: { mimeType: 'text/x-go', kind: 'text' },\n rs: { mimeType: 'text/x-rust', kind: 'text' },\n rb: { mimeType: 'text/x-ruby', kind: 'text' },\n php: { mimeType: 'text/x-php', kind: 'text' },\n sh: { mimeType: 'text/x-shellscript', kind: 'text' },\n bash: { mimeType: 'text/x-shellscript', kind: 'text' },\n zsh: { mimeType: 'text/x-shellscript', kind: 'text' },\n ps1: { mimeType: 'text/x-powershell', kind: 'text' },\n sql: { mimeType: 'text/x-sql', kind: 'text' },\n\n // Text: Data formats\n json: { mimeType: 'application/json', kind: 'text' },\n jsonc: { mimeType: 'application/json', kind: 'text' },\n ndjson: { mimeType: 'application/x-ndjson', kind: 'text' },\n yaml: { mimeType: 'text/yaml', kind: 'text' },\n yml: { mimeType: 'text/yaml', kind: 'text' },\n toml: { mimeType: 'text/toml', kind: 'text' },\n ini: { mimeType: 'text/plain', kind: 'text' },\n cfg: { mimeType: 'text/plain', kind: 'text' },\n conf: { mimeType: 'text/plain', kind: 'text' },\n csv: { mimeType: 'text/csv', kind: 'text' },\n\n // Text: Diff & Patches\n diff: { mimeType: 'text/x-diff', kind: 'text' },\n patch: { mimeType: 'text/x-diff', kind: 'text' },\n\n // Text: Documentation\n txt: { mimeType: 'text/plain', kind: 'text' },\n text: { mimeType: 'text/plain', kind: 'text' },\n log: { mimeType: 'text/plain', kind: 'text' },\n rst: { mimeType: 'text/x-rst', kind: 'text' },\n\n // Image formats\n png: { mimeType: 'image/png', kind: 'image' },\n jpg: { mimeType: 'image/jpeg', kind: 'image' },\n jpeg: { mimeType: 'image/jpeg', kind: 'image' },\n gif: { mimeType: 'image/gif', kind: 'image' },\n webp: { mimeType: 'image/webp', kind: 'image' },\n ico: { mimeType: 'image/x-icon', kind: 'image' },\n bmp: { mimeType: 'image/bmp', kind: 'image' },\n tiff: { mimeType: 'image/tiff', kind: 'image' },\n tif: { mimeType: 'image/tiff', kind: 'image' },\n\n // Audio formats\n mp3: { mimeType: 'audio/mpeg', kind: 'audio' },\n wav: { mimeType: 'audio/wav', kind: 'audio' },\n flac: { mimeType: 'audio/flac', kind: 'audio' },\n aac: { mimeType: 'audio/aac', kind: 'audio' },\n ogg: { mimeType: 'audio/ogg', kind: 'audio' },\n m4a: { mimeType: 'audio/mp4', kind: 'audio' },\n\n // PDF\n pdf: { mimeType: 'application/pdf', kind: 'pdf' },\n\n // Archives\n zip: { mimeType: 'application/zip', kind: 'binary' },\n tar: { mimeType: 'application/x-tar', kind: 'binary' },\n gz: { mimeType: 'application/gzip', kind: 'binary' },\n gzip: { mimeType: 'application/gzip', kind: 'binary' },\n '7z': { mimeType: 'application/x-7z-compressed', kind: 'binary' },\n rar: { mimeType: 'application/x-rar-compressed', kind: 'binary' },\n bz2: { mimeType: 'application/x-bzip2', kind: 'binary' },\n xz: { mimeType: 'application/x-xz', kind: 'binary' },\n\n // Other binary formats\n wasm: { mimeType: 'application/wasm', kind: 'binary' },\n so: { mimeType: 'application/octet-stream', kind: 'binary' },\n dylib: { mimeType: 'application/octet-stream', kind: 'binary' },\n dll: { mimeType: 'application/octet-stream', kind: 'binary' },\n exe: { mimeType: 'application/octet-stream', kind: 'binary' },\n msi: { mimeType: 'application/octet-stream', kind: 'binary' },\n dmg: { mimeType: 'application/octet-stream', kind: 'binary' },\n};\n\n// ─── Helper Functions ───────────────────────────────────────────────────────\n\nexport const MIME_SAMPLE_SIZE = 512;\n\n// Every non-text kind is binary for read purposes, except SVG — an image kind\n// whose bytes are text, and which the read path must not fast-path as binary.\n// EXT_MAP covers the extensions it knows (image/audio/pdf/binary kinds all\n// become binary here, image-kind SVG excepted); EXTRA_BINARY_EXTENSIONS lists\n// the rest that EXT_MAP does not carry but the read path must still treat as\n// binary. The two tables had drifted; this derivation resolves the drift toward\n// binary (only changes whether a file skips its content probe).\nconst EXTRA_BINARY_EXTENSIONS = [\n 'mov',\n 'avi',\n 'mkv',\n 'webm',\n 'ttf',\n 'otf',\n 'woff',\n 'woff2',\n 'doc',\n 'docx',\n 'xls',\n 'xlsx',\n 'ppt',\n 'pptx',\n 'sqlite',\n 'db',\n 'bin',\n 'dat',\n 'mp4',\n];\n\nconst KNOWN_BINARY_EXTENSIONS: ReadonlySet<string> = new Set(\n [\n ...Object.entries(EXT_MAP)\n .filter(([, v]) => v.kind !== 'text')\n .map(([k]) => k),\n ...EXTRA_BINARY_EXTENSIONS,\n ]\n .filter((ext) => ext !== 'svg')\n .map((ext) => `.${ext}`),\n);\n\nexport function isKnownBinaryExtension(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return KNOWN_BINARY_EXTENSIONS.has(ext);\n}\n\nexport function hasUtf16Bom(slice: Buffer): boolean {\n return (\n slice.length >= 2 &&\n ((slice[0] === 0xff && slice[1] === 0xfe) || (slice[0] === 0xfe && slice[1] === 0xff))\n );\n}\n\n/**\n * True when `slice` is valid UTF-8 *as a prefix*: `stream: true` parks a\n * multi-byte sequence cut by the sample boundary in the decoder's buffer\n * instead of reporting it, while `fatal: true` still throws on invalid bytes.\n */\nfunction isUtf8Prefix(slice: Buffer): boolean {\n try {\n new TextDecoder('utf-8', { fatal: true }).decode(slice, { stream: true });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Single binary-vs-text verdict, shared by `detectMimeType` and the read path. */\nexport function isBinarySample(slice: Buffer): boolean {\n if (slice.length === 0) return false;\n if (hasUtf16Bom(slice)) return false;\n if (slice.includes(0)) return true;\n return !isUtf8Prefix(slice);\n}\n\nexport function detectMimeType(path: string, sample?: Buffer): MimeInfo {\n const lastDot = path.lastIndexOf('.');\n const ext = lastDot > -1 ? path.slice(lastDot + 1).toLowerCase() : '';\n const known = Object.hasOwn(EXT_MAP, ext) ? EXT_MAP[ext] : undefined;\n if (known) return known;\n\n // No known extension: fall back to a binary/text probe of the content.\n if (sample) {\n return isBinarySample(sample.subarray(0, MIME_SAMPLE_SIZE))\n ? { mimeType: 'application/octet-stream', kind: 'binary' }\n : { mimeType: 'text/plain', kind: 'text' };\n }\n\n return { mimeType: 'application/octet-stream', kind: 'binary' };\n}\n\nexport function detectMimeFromContent(path: string, content: string | Buffer): MimeInfo {\n return detectMimeType(\n path,\n Buffer.isBuffer(content)\n ? content.subarray(0, MIME_SAMPLE_SIZE)\n : Buffer.from(content.slice(0, MIME_SAMPLE_SIZE)),\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-discovery.d.ts","sourceRoot":"","sources":["../../src/core/path-discovery.ts"],"names":[],"mappings":"AAuBA,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9E,OAAO,CAAC,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"path-discovery.d.ts","sourceRoot":"","sources":["../../src/core/path-discovery.ts"],"names":[],"mappings":"AAuBA,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9E,OAAO,CAAC,MAAM,EAAE,CAAC,CAuBnB;AAiBD,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAkB9D;AAID,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC1F"}
|
|
@@ -23,7 +23,7 @@ export async function resolveConfiguredDirs(envVar, opts = {}) {
|
|
|
23
23
|
result.push(opts.resolveReal ? normalizePath(await realpath(normalized)) : normalized);
|
|
24
24
|
}
|
|
25
25
|
else {
|
|
26
|
-
Logger.
|
|
26
|
+
Logger.warn(`Path configured in ${envVar} is not a directory: ${rawPath}`);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
catch (error) {
|
|
@@ -31,7 +31,7 @@ export async function resolveConfiguredDirs(envVar, opts = {}) {
|
|
|
31
31
|
result.push(normalized);
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
Logger.
|
|
34
|
+
Logger.warn(`Path configured in ${envVar} is invalid or does not exist: ${rawPath} (${formatUnknownErrorMessage(error)})`);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-discovery.js","sourceRoot":"","sources":["../../src/core/path-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,mFAAmF;AACnF,+EAA+E;AAC/E,+EAA+E;AAC/E,wEAAwE;AACxE,4EAA4E;AAC5E,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAc,EACd,OAA6E,EAAE;IAE/E,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,OAAO,IAAI,GAAG,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;YACjC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACzF,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"path-discovery.js","sourceRoot":"","sources":["../../src/core/path-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpath, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join, parse } from 'node:path';\n\nimport { formatUnknownErrorMessage } from './errors.ts';\nimport { Logger } from './observability.ts';\nimport {\n IS_WINDOWS,\n isPathInsideDirectory,\n isPathWithinDirectories,\n isSamePath,\n normalizePath,\n splitDirList,\n} from './path-utils.ts';\n\n// Resolve a configured env-var directory list (FS_ALLOWED_DIRS / FS_ROOT_BOUNDARY)\n// into normalized, verified directories. Each entry is stat'd; a non-directory\n// warns and is dropped, a missing entry warns unless `allowMissing` is set (in\n// which case the normalized path is kept). When `resolveReal` is set, a\n// directory entry is pushed as its realpath (normalized) instead of the raw\n// path — FS_ROOT_BOUNDARY uses this so a symlinked root resolves to its target.\n// A CLI override supplies `rawValue`, which beats the environment entirely.\n// Both warning messages are templated on `envVar` so operator output is stable.\nexport async function resolveConfiguredDirs(\n envVar: string,\n opts: { allowMissing?: boolean; resolveReal?: boolean; rawValue?: string } = {},\n): Promise<string[]> {\n const raw = splitDirList(opts.rawValue ?? process.env[envVar]);\n const result: string[] = [];\n for (const rawPath of raw) {\n const normalized = normalizePath(rawPath);\n try {\n const s = await stat(normalized);\n if (s.isDirectory()) {\n result.push(opts.resolveReal ? normalizePath(await realpath(normalized)) : normalized);\n } else {\n Logger.warn(`Path configured in ${envVar} is not a directory: ${rawPath}`);\n }\n } catch (error) {\n if (opts.allowMissing) {\n result.push(normalized);\n } else {\n Logger.warn(\n `Path configured in ${envVar} is invalid or does not exist: ${rawPath} (${formatUnknownErrorMessage(error)})`,\n );\n }\n }\n }\n return result;\n}\n\n// Directories a grant (or --allow-cwd) must never admit, as subtrees: a target\n// inside one of these is unsafe, and so is a target that *contains* one — the\n// nearest existing ancestor of a made-up path under C:\\Users is C:\\Users.\n//\n// Per platform on purpose: on POSIX `normalizePath('C:\\\\Windows')` resolves\n// against the cwd, so a cross-platform list would make the cwd itself\n// \"contain a system dir\" and refuse --allow-cwd.\nconst UNSAFE_SYSTEM_DIRS = IS_WINDOWS\n ? ['C:\\\\Windows', 'C:\\\\Program Files', 'C:\\\\Program Files (x86)', 'C:\\\\ProgramData']\n : ['/usr', '/etc', '/bin', '/sbin', '/System'];\n\n// Subtrees of home that hold credentials. Home itself and its other\n// subdirectories stay grantable: projects live there.\nconst UNSAFE_HOME_SUBDIRS = ['.ssh', '.aws', '.gnupg', '.kube', '.docker', '.config/gcloud'];\n\nexport function isUnsafeCwdPath(normalizedCwd: string): boolean {\n const candidate = normalizePath(normalizedCwd);\n\n // 1. A filesystem root, or anything that contains home or a system dir.\n const home = normalizePath(homedir());\n if (isSamePath(candidate, parse(candidate).root)) return true;\n if (isPathInsideDirectory(candidate, home)) return true;\n for (const dir of UNSAFE_SYSTEM_DIRS) {\n const system = normalizePath(dir);\n if (isPathInsideDirectory(candidate, system)) return true;\n if (isPathInsideDirectory(system, candidate)) return true;\n }\n\n // 2. Credential subtrees of home.\n for (const sub of UNSAFE_HOME_SUBDIRS) {\n if (isPathInsideDirectory(normalizePath(join(home, sub)), candidate)) return true;\n }\n return false;\n}\n\nconst MAX_PROJECT_ROOT_WALK_DEPTH = 32;\n\nexport async function findProjectRoot(startDir: string, ceiling: string[]): Promise<string> {\n const normCeiling = ceiling.map(normalizePath);\n let current = normalizePath(startDir);\n let depth = 0;\n\n for (;;) {\n if (depth++ >= MAX_PROJECT_ROOT_WALK_DEPTH) {\n break;\n }\n // Check if the current directory contains any markers\n const markers = ['.git', 'package.json', 'pyproject.toml'];\n for (const marker of markers) {\n const markerPath = join(current, marker);\n try {\n const s = await stat(markerPath);\n if (s.isDirectory() || s.isFile()) {\n return current;\n }\n } catch (_error) {\n // Skip and try next marker\n }\n }\n\n // Move to parent directory\n const parent = normalizePath(dirname(current));\n\n // Check if we hit the filesystem root\n if (parent === current) {\n break;\n }\n\n // Check if the parent is still within the ceiling\n if (!isPathWithinDirectories(parent, normCeiling)) {\n break;\n }\n\n current = parent;\n }\n\n return normalizePath(startDir);\n}\n"]}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const ENTRY_TYPES: readonly ["file", "directory", "symlink", "other"];
|
|
3
|
-
export type EntryType = (typeof ENTRY_TYPES)[number];
|
|
1
|
+
export type EntryType = 'file' | 'directory' | 'symlink' | 'other';
|
|
4
2
|
/** The three predicates both `Dirent` and `Stats` expose - all `resolveEntryType` needs. */
|
|
5
3
|
export interface DirentLike {
|
|
6
4
|
isDirectory(): boolean;
|