@j0hanz/filesystem-mcp 2.7.0 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/core/concurrency.d.ts.map +1 -1
- package/dist/core/concurrency.js +53 -37
- package/dist/core/concurrency.js.map +1 -1
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/glob.js +16 -5
- package/dist/core/glob.js.map +1 -1
- package/dist/core/input-required.d.ts +21 -16
- package/dist/core/input-required.d.ts.map +1 -1
- package/dist/core/input-required.js +12 -12
- package/dist/core/input-required.js.map +1 -1
- package/dist/core/path-completer.d.ts.map +1 -1
- package/dist/core/path-completer.js +7 -4
- package/dist/core/path-completer.js.map +1 -1
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +23 -15
- package/dist/core/search.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/batch.d.ts +1 -0
- package/dist/tools/batch.d.ts.map +1 -1
- package/dist/tools/batch.js +5 -9
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/create.d.ts.map +1 -1
- package/dist/tools/create.js +2 -6
- package/dist/tools/create.js.map +1 -1
- package/dist/tools/define.d.ts.map +1 -1
- package/dist/tools/define.js +1 -5
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/delete.d.ts.map +1 -1
- package/dist/tools/delete.js +4 -12
- package/dist/tools/delete.js.map +1 -1
- package/dist/tools/move.d.ts.map +1 -1
- package/dist/tools/move.js +2 -6
- package/dist/tools/move.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +23 -75
- package/dist/tools/read.js.map +1 -1
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +2 -18
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/shared.d.ts +3 -1
- package/dist/transport/shared.d.ts.map +1 -1
- package/dist/transport/shared.js +14 -1
- package/dist/transport/shared.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/move.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move.js","sourceRoot":"","sources":["../../src/tools/move.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InputRequiredResult } from '@modelcontextprotocol/server';\nimport { isInputRequiredResult } from '@modelcontextprotocol/server';\n\nimport { stat } from 'node:fs/promises';\nimport { basename, dirname, relative, resolve } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { processInParallel } from '../core/concurrency.ts';\nimport {\n ErrorCode,\n FsError,\n isFsError,\n isNodeError,\n Problem,\n rethrowIfAborted,\n} from '../core/errors.ts';\nimport { joinRoster, pathLabel } from '../core/fmt.ts';\nimport { destExists } from '../core/fs.ts';\nimport type { GuardedFileSystem } from '../core/fs.ts';\nimport { globEntries } from '../core/glob.ts';\nimport {\n confirmKey,\n describeRefusal,\n pendingRoundTrip,\n readAcceptedChoice,\n} from '../core/input-required.ts';\nimport {\n isPathInsideDirectory,\n isSamePath,\n normalizeCaseForComparison,\n respellCaseOnlyTarget,\n} from '../core/path-utils.ts';\nimport { defaultFalseBoolean, RequiredPath } from '../core/schema.ts';\nimport { PARALLEL_CONCURRENCY } from '../core/util.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\nconst MoveItemSchema = z.strictObject({\n source: RequiredPath.describe('Path of the file or directory to move or copy'),\n destination: RequiredPath.describe('Destination path'),\n});\n\ninterface MoveItemResult {\n from: string;\n to: string;\n}\n\nconst MoveInputSchema = z.strictObject({\n moves: z.array(MoveItemSchema).min(1).max(100).describe('Operations to perform (max 100)'),\n copy: defaultFalseBoolean('Copy instead of move; sources are left in place'),\n overwrite: defaultFalseBoolean(\n 'Copy mode only: overwrite existing destinations without confirmation',\n ),\n});\n\ninterface MoveFailureItem {\n source: string;\n destination: string;\n error: Problem;\n}\n\ninterface MoveOutput {\n moves: MoveItemResult[];\n failures?: MoveFailureItem[];\n skipped?: string[];\n}\n\ntype PairOp = 'move' | 'copy';\n\nconst VERB: Readonly<Record<PairOp, string>> = { move: 'Move', copy: 'Copy' };\n\n/** A move or copy pre-checked up to the point a confirmation decision is needed. */\ninterface TransferPlan {\n pair: { source: string; destination: string };\n /**\n * The path the mutation runs on: the link itself for a move, the resolved\n * target for a copy. Every collision check uses the resolved source instead\n * — see {@link validateTransferSource}.\n */\n opSource: string;\n validDest: string;\n /**\n * A rename that only changes the destination's case. Move must perform it —\n * it is real work — so it is exempt from the destination-exists checks that\n * would otherwise read the source itself as an existing destination. Never\n * true for a copy, which treats a case-only target as a self-copy and skips.\n */\n isCaseOnlyRename: boolean;\n /** Whether the destination existed when planned (drives the TOCTOU guard). */\n destExistedOriginally: boolean;\n /** Destination exists and is not a self/case-only target → needs overwrite confirmation. */\n pending: boolean;\n}\n\n/**\n * Phase 1 (no mutation): validate source and destination, reject self-targets\n * and transfers into a subdirectory of the source, and stat the destination to\n * decide whether this pair needs an overwrite confirmation. No `mkdir` happens\n * here — the old flow created the destination's parent before asking, which\n * mutated the filesystem before a confirmation; that now waits for phase 2 (R14).\n *\n * `overwrite` is copy-only — move has no confirmation bypass — so a move always\n * passes false.\n */\nasync function planTransfer(\n op: PairOp,\n pair: { source: string; destination: string },\n fs: ToolCtx['fs'],\n overwrite: boolean,\n signal: AbortSignal | undefined,\n): Promise<TransferPlanResult> {\n let realSource: string;\n let opSource: string;\n let validDest: string;\n try {\n ({ realSource, opSource } = await validateTransferSource(op, pair.source, fs));\n validDest = await fs.pathGuard.validatePathForWrite(pair.destination);\n if (!(op === 'move' && opSource !== realSource) && (await stat(realSource)).isDirectory()) {\n await assertTreeHasNoProtectedEntries(op, realSource, pair.source, validDest, fs, signal);\n }\n } catch (error) {\n return { status: 'fail', failure: pairFailure(pair, error) };\n }\n\n // Comparisons run on the resolved source; only the fs call in phase 2 uses\n // opSource. validatePathForWrite resolves the destination through a symlink\n // too, so both sides of every check must be resolved to match.\n const resolvedSource = resolve(realSource);\n let resolvedDest = resolve(validDest);\n\n // validatePathForWrite realpaths an existing destination to its on-disk\n // spelling, so a case-only rename resolves to the source itself; re-spell\n // it with the requested basename before deciding self vs. rename.\n if (resolvedSource === resolvedDest) {\n validDest = respellCaseOnlyTarget(pair.destination, validDest);\n resolvedDest = resolve(validDest);\n }\n\n const isSelf = resolvedSource === resolvedDest;\n const isCaseOnlyRename = !isSelf && isSamePath(resolvedSource, resolvedDest);\n\n // A copy onto a case-only variant of its own source is the same file, so it\n // is a no-op; the same rename is real work for move and proceeds.\n if (isSelf || (isCaseOnlyRename && op === 'copy')) {\n return { status: 'noop' };\n }\n\n if (!isCaseOnlyRename && isPathInsideDirectory(resolvedSource, resolvedDest)) {\n return {\n status: 'fail',\n failure: pairFailure(\n pair,\n new FsError(\n ErrorCode.INVALID_INPUT,\n `Cannot ${op} a directory into its own subdirectory`,\n pair.source,\n ),\n ),\n };\n }\n\n const destExistedOriginally = !isCaseOnlyRename && (await destExists(fs, validDest, op));\n const pending = destExistedOriginally && !overwrite;\n\n return {\n status: 'plan',\n plan: { pair, opSource, validDest, isCaseOnlyRename, destExistedOriginally, pending },\n };\n}\n\n/**\n * Phase 2 (mutation): confirm an overwrite if needed, TOCTOU-check the\n * destination, create its parent, then rename (with cross-device fallback) or\n * copy. A declined/missing confirmation throws `CANCELLED`, collected as a\n * per-pair failure by the caller. A destination that appeared between plan and\n * mutation (created during the confirmation gap) also fails closed.\n */\nasync function executeTransfer(\n op: PairOp,\n plan: TransferPlan,\n ctx: Pick<ToolCtx, 'fs' | 'signal' | 'inputResponses' | 'droppedInputResponseKeys' | 'log'>,\n pendingSorted: readonly string[],\n): Promise<TransferExecResult> {\n if (plan.pending) {\n const key = confirmKey(pendingSorted.indexOf(plan.validDest));\n const choice = readAcceptedChoice(ctx.inputResponses, key);\n if (choice === 'skip') {\n return { skipped: plan.pair.destination };\n }\n if (choice !== 'overwrite') {\n throw new FsError(\n ErrorCode.CANCELLED,\n `${VERB[op]} cancelled: overwrite of \"${plan.pair.destination}\" was ${describeRefusal(ctx.inputResponses, key, ctx.droppedInputResponseKeys)}`,\n plan.pair.destination,\n );\n }\n }\n\n // TOCTOU check before any mutation: a destination that did not exist when\n // planned but exists now was created during the confirmation gap.\n if (\n !plan.isCaseOnlyRename &&\n !plan.destExistedOriginally &&\n (await destExists(ctx.fs, plan.validDest, op))\n ) {\n throw new FsError(\n ErrorCode.CANCELLED,\n `${VERB[op]} cancelled: destination \"${plan.pair.destination}\" was created during confirmation.`,\n plan.pair.destination,\n );\n }\n\n await ctx.fs.mkdir(dirname(plan.validDest), { recursive: true });\n\n if (op === 'move') {\n await performRenameWithFallback(plan.opSource, plan.validDest, ctx.fs, plan.pair.source);\n ctx.log('info', `move: ${plan.pair.source} -> ${plan.pair.destination}`, 'move');\n } else {\n await ctx.fs.cp(plan.opSource, plan.validDest, {\n recursive: true,\n verbatimSymlinks: true,\n preserveTimestamps: true,\n force: true,\n });\n }\n return { value: { from: plan.opSource, to: plan.validDest } };\n}\n\ntype TransferPlanResult =\n | { status: 'fail'; failure: MoveFailureItem }\n | { status: 'noop' }\n | { status: 'plan'; plan: TransferPlan };\n\n/** A discriminated union, so the fold below narrows without a generic cast. */\ntype TransferExecResult = { readonly skipped: string } | { readonly value: MoveItemResult };\n\nfunction pairFailure(\n pair: { source: string; destination: string },\n error: unknown,\n): MoveFailureItem {\n return {\n source: pair.source,\n destination: pair.destination,\n error: Problem.fromUnknown(error, ErrorCode.UNKNOWN, pair.source),\n };\n}\n\n/**\n * The source→destination sibling of `runOverPaths`: plan every pair, fail closed\n * on a duplicated destination, round-trip the overwrite confirmations as one\n * set, then execute what survived in parallel. `copy` and `move` differ only in\n * their `plan` and `execute` callbacks.\n */\nasync function runTransfers(\n items: readonly z.infer<typeof MoveItemSchema>[],\n ctx: ToolCtx,\n op: PairOp,\n overwrite: boolean,\n): Promise<\n | { results: MoveItemResult[]; skipped: string[]; failures: MoveFailureItem[] }\n | InputRequiredResult\n> {\n const { results: planned, errors: planErrors } = await processInParallel(\n items,\n (pair) => planTransfer(op, pair, ctx.fs, overwrite, ctx.signal),\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n // plan callbacks are fail-closed (they return { status: 'fail' }, never\n // throw), so planErrors should always be empty. Surface the first rather\n // than silently dropping the item if a future plan callback violates that.\n const firstPlanError = planErrors[0];\n if (firstPlanError) throw firstPlanError.error;\n\n const failures: MoveFailureItem[] = [];\n const candidates: TransferPlan[] = [];\n for (const { value } of planned) {\n if (value.status === 'fail') failures.push(value.failure);\n else if (value.status === 'plan') candidates.push(value.plan);\n // 'noop' (self-copy / self-move) is silently skipped.\n }\n\n // Two sources targeting the same destination in one batch would otherwise\n // collapse to a single shared overwrite confirmation and let the second\n // one silently clobber the first's freshly-written content. Fail closed:\n // only the first plan per destination proceeds; later ones targeting the\n // same destination are reported as a per-item failure.\n const seenDest = new Set<string>();\n const ready: TransferPlan[] = [];\n for (const candidate of candidates) {\n const destKey = normalizeCaseForComparison(candidate.validDest);\n if (seenDest.has(destKey)) {\n failures.push(\n pairFailure(\n candidate.pair,\n new FsError(\n ErrorCode.INVALID_INPUT,\n `${VERB[op]} cancelled: another entry in this batch already targets destination \"${candidate.pair.destination}\"`,\n candidate.pair.destination,\n ),\n ),\n );\n continue;\n }\n seenDest.add(destKey);\n ready.push(candidate);\n }\n\n const pendingSorted = ready\n .filter((p) => p.pending)\n .map((p) => p.validDest)\n .sort();\n if (pendingSorted.length > 0) {\n // Round 1 returns input_required; a retry whose verified state does not\n // bind this overwrite set throws (R9) via `pendingRoundTrip`.\n const round = await pendingRoundTrip({\n op,\n pending: pendingSorted,\n requestState: ctx.requestState,\n droppedInputResponseKeys: ctx.droppedInputResponseKeys,\n clientCapabilities: ctx.clientCapabilities,\n serverCtx: ctx.serverCtx,\n buildInputs: (dests) =>\n dests.map((dest, i) => ({\n key: confirmKey(i),\n message:\n op === 'move'\n ? `\"${dest}\" already exists. Overwrite it?`\n : `Destination \"${dest}\" already exists. Overwrite it?`,\n choices: ['overwrite', 'skip'],\n })),\n });\n if (round !== undefined) return round;\n }\n\n const total = ready.length;\n let completed = 0;\n const tick = (): void => {\n completed += 1;\n ctx.onProgress({ current: completed, total });\n };\n const { results: execResults, errors: execErrors } = await processInParallel(\n ready,\n async (readyPlan) => {\n try {\n return await executeTransfer(op, readyPlan, ctx, pendingSorted);\n } finally {\n tick();\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n for (const { error, index } of execErrors) {\n rethrowIfAborted(error);\n const failed = ready[index];\n if (failed) failures.push(pairFailure(failed.pair, error));\n }\n\n const results: MoveItemResult[] = [];\n const skipped: string[] = [];\n for (const { value } of execResults) {\n if ('skipped' in value) skipped.push(value.skipped);\n else results.push(value.value);\n }\n\n return { results, skipped, failures };\n}\n\nfunction buildSummary(\n verb: 'move' | 'copy',\n results: readonly MoveItemResult[],\n failures: readonly MoveFailureItem[],\n skipped: readonly string[],\n): string {\n const failCount = failures.length;\n // Name each pair. \"move: 2 items\" left the caller to open structuredContent\n // to learn which two, and a partial failure was unreadable without it.\n // Skipped destinations are an outcome the user chose, not a failure — name\n // them, or an all-skipped call reads as \"copy: nothing\".\n const tokens = [\n ...results.map((r) => `${pathLabel(r.from)} → ${pathLabel(r.to)}`),\n ...skipped.map((dest) => `${pathLabel(dest)} SKIPPED`),\n ];\n const parts = [`${verb}: ${joinRoster(tokens) || 'nothing'}`];\n if (failCount > 0) parts.push(`${String(failCount)} failed`);\n return parts.join(' · ');\n}\n\ninterface TransferSource {\n /** Symlink resolved — the identity used for every same-target comparison. */\n realSource: string;\n /** The path the mutation runs on: symlink preserved for move, resolved for copy. */\n opSource: string;\n}\n\n/**\n * A move needs two views of its source. Renaming must operate on the link\n * itself, or moving a symlink would rename the file it points at and leave the\n * link dangling. Every collision check must instead compare the resolved\n * target, or a link moved onto itself (or onto its own target) reads as a real\n * move and renames the link over that target, destroying it. A copy reads\n * through the link, so both views are the resolved one.\n */\nasync function validateTransferSource(\n op: PairOp,\n source: string,\n fs: ToolCtx['fs'],\n): Promise<TransferSource> {\n try {\n const realSource = await fs.pathGuard.validateExistingPath(source);\n const opSource = op === 'move' ? await fs.pathGuard.validatePathForDelete(source) : realSource;\n return { realSource, opSource };\n } catch (error) {\n if (isFsError(error)) throw error;\n throw new FsError(ErrorCode.ACCESS_DENIED, `${VERB[op]} failed for ${source}`, source);\n }\n}\n\n/**\n * A directory transfer may proceed only when every entry keeps the same\n * sensitive-file status before and after relocation. Path-based rules\n * (`secrets/**`, `.aws/credentials`) follow the path, not the file, so refuse\n * any entry that would leave or enter the protected set. Walk the tree once\n * before any mutation and fail the pair closed if anything changes status.\n * Name-based rules need no help — they match after the move too.\n */\nasync function assertTreeHasNoProtectedEntries(\n op: PairOp,\n realSource: string,\n requestedSource: string,\n validDest: string,\n fs: ToolCtx['fs'],\n signal: AbortSignal | undefined,\n): Promise<void> {\n let protectedCount = 0;\n const entries = globEntries({\n cwd: realSource,\n pattern: '**/*',\n includeHidden: true,\n skipIgnored: false,\n onlyFiles: false,\n ...(signal ? { signal } : {}),\n });\n try {\n for await (const entry of entries) {\n signal?.throwIfAborted();\n const entryRelativePath = relative(realSource, entry.path);\n const requestedSourcePath = resolve(requestedSource, entryRelativePath);\n const destinationPath = resolve(validDest, entryRelativePath);\n const protectedBefore =\n fs.pathGuard.isSensitive(entry.path) || fs.pathGuard.isSensitive(requestedSourcePath);\n const protectedAfter = fs.pathGuard.isSensitive(destinationPath);\n if (protectedBefore !== protectedAfter) {\n protectedCount++;\n break;\n }\n }\n } catch (error) {\n rethrowIfAborted(error);\n throw new FsError(\n ErrorCode.ACCESS_DENIED,\n `${VERB[op]} refused: the directory could not be fully inspected for protected entries`,\n requestedSource,\n error,\n );\n }\n if (protectedCount > 0) {\n throw new FsError(\n ErrorCode.ACCESS_DENIED,\n `${VERB[op]} refused: the directory contains protected entries matching the sensitive-file policy; move or copy individual files instead`,\n requestedSource,\n );\n }\n}\n\nexport async function performRenameWithFallback(\n validSource: string,\n validDest: string,\n fsOps: Pick<GuardedFileSystem, 'rename' | 'cp' | 'rm'>,\n originalSource: string,\n): Promise<void> {\n try {\n await fsOps.rename(validSource, validDest);\n } catch (error: unknown) {\n rethrowIfAborted(error);\n\n if (!isNodeError(error) || error.code !== 'EXDEV') {\n throw error;\n }\n\n // EXDEV: cross-device rename. Copy then remove, preserving symlinks and\n // timestamps so link semantics survive the move.\n let copied = false;\n try {\n await fsOps.cp(validSource, validDest, {\n recursive: true,\n verbatimSymlinks: true,\n preserveTimestamps: true,\n });\n copied = true;\n await fsOps.rm(validSource, { recursive: true, force: true });\n } catch (copyOrRemoveError) {\n rethrowIfAborted(copyOrRemoveError);\n if (copied) {\n // cp succeeded but rm failed: the destination already holds a complete\n // copy and the source remains. Surface the rm error as the cause so the\n // caller can recover (clean up the duplicate) instead of a silent generic\n // failure that hides the partial completion.\n const baseProblem = Problem.fromUnknown(\n copyOrRemoveError,\n ErrorCode.UNKNOWN,\n originalSource,\n );\n throw new FsError(\n baseProblem.code,\n `Cross-device move of ${originalSource}: copy succeeded but source removal failed (destination holds a copy): ${baseProblem.message}`,\n originalSource,\n copyOrRemoveError,\n );\n }\n throw copyOrRemoveError;\n }\n }\n}\n\nexport const MOVE = defineTool<typeof MoveInputSchema, MoveOutput>({\n name: 'move',\n title: 'Move or Copy Files',\n description:\n 'Move, rename, or copy files and directories, like mv or cp -r. ' +\n 'Each destination is the full new path, not a folder to move into; missing parent directories are created.',\n input: MoveInputSchema,\n readOnlyHint: false,\n progress: (args) => {\n const label = args.copy ? 'Copy' : 'Move';\n if (args.moves.length === 1) {\n const move = args.moves[0];\n return {\n label,\n subject: `${basename(move?.source ?? '')} → ${basename(move?.destination ?? '')}`,\n };\n }\n return { label, subject: `${String(args.moves.length)} files` };\n },\n accessPaths: (args) => args.moves.flatMap((m) => [m.source, m.destination]),\n run: async (args, ctx) => {\n const op: PairOp = args.copy ? 'copy' : 'move';\n // `overwrite` is copy-only; move has no confirmation bypass.\n const outcome = await runTransfers(args.moves, ctx, op, args.copy && args.overwrite);\n // input_required is a return value, not a completed call: surface it\n // verbatim so the executor short-circuits before building a CallToolResult.\n if (isInputRequiredResult(outcome)) return outcome;\n const { results, skipped, failures } = outcome;\n return {\n structured: {\n moves: results,\n ...(failures.length > 0 ? { failures } : {}),\n ...(skipped.length > 0 ? { skipped } : {}),\n },\n text: buildSummary(op, results, failures, skipped),\n // Every requested pair failed: no move, no copy, no user-chosen skip - the\n // call did nothing. A skip is work the caller asked for, so it counts.\n isError: failures.length > 0 && results.length + skipped.length === 0,\n };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"move.js","sourceRoot":"","sources":["../../src/tools/move.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InputRequiredResult } from '@modelcontextprotocol/server';\nimport { isInputRequiredResult } from '@modelcontextprotocol/server';\n\nimport { stat } from 'node:fs/promises';\nimport { basename, dirname, relative, resolve } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { processInParallel } from '../core/concurrency.ts';\nimport {\n ErrorCode,\n FsError,\n isFsError,\n isNodeError,\n Problem,\n rethrowIfAborted,\n} from '../core/errors.ts';\nimport { joinRoster, pathLabel } from '../core/fmt.ts';\nimport { destExists } from '../core/fs.ts';\nimport type { GuardedFileSystem } from '../core/fs.ts';\nimport { globEntries } from '../core/glob.ts';\nimport {\n confirmKey,\n describeRefusal,\n pendingRoundTrip,\n readAcceptedChoice,\n} from '../core/input-required.ts';\nimport {\n isPathInsideDirectory,\n isSamePath,\n normalizeCaseForComparison,\n respellCaseOnlyTarget,\n} from '../core/path-utils.ts';\nimport { defaultFalseBoolean, RequiredPath } from '../core/schema.ts';\nimport { PARALLEL_CONCURRENCY } from '../core/util.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\nconst MoveItemSchema = z.strictObject({\n source: RequiredPath.describe('Path of the file or directory to move or copy'),\n destination: RequiredPath.describe('Destination path'),\n});\n\ninterface MoveItemResult {\n from: string;\n to: string;\n}\n\nconst MoveInputSchema = z.strictObject({\n moves: z.array(MoveItemSchema).min(1).max(100).describe('Operations to perform (max 100)'),\n copy: defaultFalseBoolean('Copy instead of move; sources are left in place'),\n overwrite: defaultFalseBoolean(\n 'Copy mode only: overwrite existing destinations without confirmation',\n ),\n});\n\ninterface MoveFailureItem {\n source: string;\n destination: string;\n error: Problem;\n}\n\ninterface MoveOutput {\n moves: MoveItemResult[];\n failures?: MoveFailureItem[];\n skipped?: string[];\n}\n\ntype PairOp = 'move' | 'copy';\n\nconst VERB: Readonly<Record<PairOp, string>> = { move: 'Move', copy: 'Copy' };\n\n/** A move or copy pre-checked up to the point a confirmation decision is needed. */\ninterface TransferPlan {\n pair: { source: string; destination: string };\n /**\n * The path the mutation runs on: the link itself for a move, the resolved\n * target for a copy. Every collision check uses the resolved source instead\n * — see {@link validateTransferSource}.\n */\n opSource: string;\n validDest: string;\n /**\n * A rename that only changes the destination's case. Move must perform it —\n * it is real work — so it is exempt from the destination-exists checks that\n * would otherwise read the source itself as an existing destination. Never\n * true for a copy, which treats a case-only target as a self-copy and skips.\n */\n isCaseOnlyRename: boolean;\n /** Whether the destination existed when planned (drives the TOCTOU guard). */\n destExistedOriginally: boolean;\n /** Destination exists and is not a self/case-only target → needs overwrite confirmation. */\n pending: boolean;\n}\n\n/**\n * Phase 1 (no mutation): validate source and destination, reject self-targets\n * and transfers into a subdirectory of the source, and stat the destination to\n * decide whether this pair needs an overwrite confirmation. No `mkdir` happens\n * here — the old flow created the destination's parent before asking, which\n * mutated the filesystem before a confirmation; that now waits for phase 2 (R14).\n *\n * `overwrite` is copy-only — move has no confirmation bypass — so a move always\n * passes false.\n */\nasync function planTransfer(\n op: PairOp,\n pair: { source: string; destination: string },\n fs: ToolCtx['fs'],\n overwrite: boolean,\n signal: AbortSignal | undefined,\n): Promise<TransferPlanResult> {\n let realSource: string;\n let opSource: string;\n let validDest: string;\n try {\n ({ realSource, opSource } = await validateTransferSource(op, pair.source, fs));\n validDest = await fs.pathGuard.validatePathForWrite(pair.destination);\n if (!(op === 'move' && opSource !== realSource) && (await stat(realSource)).isDirectory()) {\n await assertTreeHasNoProtectedEntries(op, realSource, pair.source, validDest, fs, signal);\n }\n } catch (error) {\n return { status: 'fail', failure: pairFailure(pair, error) };\n }\n\n // Comparisons run on the resolved source; only the fs call in phase 2 uses\n // opSource. validatePathForWrite resolves the destination through a symlink\n // too, so both sides of every check must be resolved to match.\n const resolvedSource = resolve(realSource);\n let resolvedDest = resolve(validDest);\n\n // validatePathForWrite realpaths an existing destination to its on-disk\n // spelling, so a case-only rename resolves to the source itself; re-spell\n // it with the requested basename before deciding self vs. rename.\n if (resolvedSource === resolvedDest) {\n validDest = respellCaseOnlyTarget(pair.destination, validDest);\n resolvedDest = resolve(validDest);\n }\n\n const isSelf = resolvedSource === resolvedDest;\n const isCaseOnlyRename = !isSelf && isSamePath(resolvedSource, resolvedDest);\n\n // A copy onto a case-only variant of its own source is the same file, so it\n // is a no-op; the same rename is real work for move and proceeds.\n if (isSelf || (isCaseOnlyRename && op === 'copy')) {\n return { status: 'noop' };\n }\n\n if (!isCaseOnlyRename && isPathInsideDirectory(resolvedSource, resolvedDest)) {\n return {\n status: 'fail',\n failure: pairFailure(\n pair,\n new FsError(\n ErrorCode.INVALID_INPUT,\n `Cannot ${op} a directory into its own subdirectory`,\n pair.source,\n ),\n ),\n };\n }\n\n const destExistedOriginally = !isCaseOnlyRename && (await destExists(fs, validDest, op));\n const pending = destExistedOriginally && !overwrite;\n\n return {\n status: 'plan',\n plan: { pair, opSource, validDest, isCaseOnlyRename, destExistedOriginally, pending },\n };\n}\n\n/**\n * Phase 2 (mutation): confirm an overwrite if needed, TOCTOU-check the\n * destination, create its parent, then rename (with cross-device fallback) or\n * copy. A declined/missing confirmation throws `CANCELLED`, collected as a\n * per-pair failure by the caller. A destination that appeared between plan and\n * mutation (created during the confirmation gap) also fails closed.\n */\nasync function executeTransfer(\n op: PairOp,\n plan: TransferPlan,\n ctx: Pick<ToolCtx, 'fs' | 'signal' | 'inputResponses' | 'droppedInputResponseKeys' | 'log'>,\n pendingSorted: readonly string[],\n): Promise<TransferExecResult> {\n if (plan.pending) {\n const key = confirmKey(pendingSorted.indexOf(plan.validDest));\n const choice = readAcceptedChoice(ctx.inputResponses, key);\n if (choice === 'skip') {\n return { skipped: plan.pair.destination };\n }\n if (choice !== 'overwrite') {\n throw new FsError(\n ErrorCode.CANCELLED,\n `${VERB[op]} cancelled: overwrite of \"${plan.pair.destination}\" was ${describeRefusal(ctx, key)}`,\n plan.pair.destination,\n );\n }\n }\n\n // TOCTOU check before any mutation: a destination that did not exist when\n // planned but exists now was created during the confirmation gap.\n if (\n !plan.isCaseOnlyRename &&\n !plan.destExistedOriginally &&\n (await destExists(ctx.fs, plan.validDest, op))\n ) {\n throw new FsError(\n ErrorCode.CANCELLED,\n `${VERB[op]} cancelled: destination \"${plan.pair.destination}\" was created during confirmation.`,\n plan.pair.destination,\n );\n }\n\n await ctx.fs.mkdir(dirname(plan.validDest), { recursive: true });\n\n if (op === 'move') {\n await performRenameWithFallback(plan.opSource, plan.validDest, ctx.fs, plan.pair.source);\n ctx.log('info', `move: ${plan.pair.source} -> ${plan.pair.destination}`, 'move');\n } else {\n await ctx.fs.cp(plan.opSource, plan.validDest, {\n recursive: true,\n verbatimSymlinks: true,\n preserveTimestamps: true,\n force: true,\n });\n }\n return { value: { from: plan.opSource, to: plan.validDest } };\n}\n\ntype TransferPlanResult =\n | { status: 'fail'; failure: MoveFailureItem }\n | { status: 'noop' }\n | { status: 'plan'; plan: TransferPlan };\n\n/** A discriminated union, so the fold below narrows without a generic cast. */\ntype TransferExecResult = { readonly skipped: string } | { readonly value: MoveItemResult };\n\nfunction pairFailure(\n pair: { source: string; destination: string },\n error: unknown,\n): MoveFailureItem {\n return {\n source: pair.source,\n destination: pair.destination,\n error: Problem.fromUnknown(error, ErrorCode.UNKNOWN, pair.source),\n };\n}\n\n/**\n * The source→destination sibling of `runOverPaths`: plan every pair, fail closed\n * on a duplicated destination, round-trip the overwrite confirmations as one\n * set, then execute what survived in parallel. `copy` and `move` differ only in\n * their `plan` and `execute` callbacks.\n */\nasync function runTransfers(\n items: readonly z.infer<typeof MoveItemSchema>[],\n ctx: ToolCtx,\n op: PairOp,\n overwrite: boolean,\n): Promise<\n | { results: MoveItemResult[]; skipped: string[]; failures: MoveFailureItem[] }\n | InputRequiredResult\n> {\n const { results: planned, errors: planErrors } = await processInParallel(\n items,\n (pair) => planTransfer(op, pair, ctx.fs, overwrite, ctx.signal),\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n // plan callbacks are fail-closed (they return { status: 'fail' }, never\n // throw), so planErrors should always be empty. Surface the first rather\n // than silently dropping the item if a future plan callback violates that.\n const firstPlanError = planErrors[0];\n if (firstPlanError) throw firstPlanError.error;\n\n const failures: MoveFailureItem[] = [];\n const candidates: TransferPlan[] = [];\n for (const { value } of planned) {\n if (value.status === 'fail') failures.push(value.failure);\n else if (value.status === 'plan') candidates.push(value.plan);\n // 'noop' (self-copy / self-move) is silently skipped.\n }\n\n // Two sources targeting the same destination in one batch would otherwise\n // collapse to a single shared overwrite confirmation and let the second\n // one silently clobber the first's freshly-written content. Fail closed:\n // only the first plan per destination proceeds; later ones targeting the\n // same destination are reported as a per-item failure.\n const seenDest = new Set<string>();\n const ready: TransferPlan[] = [];\n for (const candidate of candidates) {\n const destKey = normalizeCaseForComparison(candidate.validDest);\n if (seenDest.has(destKey)) {\n failures.push(\n pairFailure(\n candidate.pair,\n new FsError(\n ErrorCode.INVALID_INPUT,\n `${VERB[op]} cancelled: another entry in this batch already targets destination \"${candidate.pair.destination}\"`,\n candidate.pair.destination,\n ),\n ),\n );\n continue;\n }\n seenDest.add(destKey);\n ready.push(candidate);\n }\n\n const pendingSorted = ready\n .filter((p) => p.pending)\n .map((p) => p.validDest)\n .sort();\n if (pendingSorted.length > 0) {\n // Round 1 returns input_required; a retry whose verified state does not\n // bind this overwrite set throws (R9) via `pendingRoundTrip`.\n const round = await pendingRoundTrip(ctx, {\n op,\n pending: pendingSorted,\n buildInputs: (dests) =>\n dests.map((dest, i) => ({\n key: confirmKey(i),\n message:\n op === 'move'\n ? `\"${dest}\" already exists. Overwrite it?`\n : `Destination \"${dest}\" already exists. Overwrite it?`,\n choices: ['overwrite', 'skip'],\n })),\n });\n if (round !== undefined) return round;\n }\n\n const total = ready.length;\n let completed = 0;\n const tick = (): void => {\n completed += 1;\n ctx.onProgress({ current: completed, total });\n };\n const { results: execResults, errors: execErrors } = await processInParallel(\n ready,\n async (readyPlan) => {\n try {\n return await executeTransfer(op, readyPlan, ctx, pendingSorted);\n } finally {\n tick();\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n for (const { error, index } of execErrors) {\n rethrowIfAborted(error);\n const failed = ready[index];\n if (failed) failures.push(pairFailure(failed.pair, error));\n }\n\n const results: MoveItemResult[] = [];\n const skipped: string[] = [];\n for (const { value } of execResults) {\n if ('skipped' in value) skipped.push(value.skipped);\n else results.push(value.value);\n }\n\n return { results, skipped, failures };\n}\n\nfunction buildSummary(\n verb: 'move' | 'copy',\n results: readonly MoveItemResult[],\n failures: readonly MoveFailureItem[],\n skipped: readonly string[],\n): string {\n const failCount = failures.length;\n // Name each pair. \"move: 2 items\" left the caller to open structuredContent\n // to learn which two, and a partial failure was unreadable without it.\n // Skipped destinations are an outcome the user chose, not a failure — name\n // them, or an all-skipped call reads as \"copy: nothing\".\n const tokens = [\n ...results.map((r) => `${pathLabel(r.from)} → ${pathLabel(r.to)}`),\n ...skipped.map((dest) => `${pathLabel(dest)} SKIPPED`),\n ];\n const parts = [`${verb}: ${joinRoster(tokens) || 'nothing'}`];\n if (failCount > 0) parts.push(`${String(failCount)} failed`);\n return parts.join(' · ');\n}\n\ninterface TransferSource {\n /** Symlink resolved — the identity used for every same-target comparison. */\n realSource: string;\n /** The path the mutation runs on: symlink preserved for move, resolved for copy. */\n opSource: string;\n}\n\n/**\n * A move needs two views of its source. Renaming must operate on the link\n * itself, or moving a symlink would rename the file it points at and leave the\n * link dangling. Every collision check must instead compare the resolved\n * target, or a link moved onto itself (or onto its own target) reads as a real\n * move and renames the link over that target, destroying it. A copy reads\n * through the link, so both views are the resolved one.\n */\nasync function validateTransferSource(\n op: PairOp,\n source: string,\n fs: ToolCtx['fs'],\n): Promise<TransferSource> {\n try {\n const realSource = await fs.pathGuard.validateExistingPath(source);\n const opSource = op === 'move' ? await fs.pathGuard.validatePathForDelete(source) : realSource;\n return { realSource, opSource };\n } catch (error) {\n if (isFsError(error)) throw error;\n throw new FsError(ErrorCode.ACCESS_DENIED, `${VERB[op]} failed for ${source}`, source);\n }\n}\n\n/**\n * A directory transfer may proceed only when every entry keeps the same\n * sensitive-file status before and after relocation. Path-based rules\n * (`secrets/**`, `.aws/credentials`) follow the path, not the file, so refuse\n * any entry that would leave or enter the protected set. Walk the tree once\n * before any mutation and fail the pair closed if anything changes status.\n * Name-based rules need no help — they match after the move too.\n */\nasync function assertTreeHasNoProtectedEntries(\n op: PairOp,\n realSource: string,\n requestedSource: string,\n validDest: string,\n fs: ToolCtx['fs'],\n signal: AbortSignal | undefined,\n): Promise<void> {\n let protectedCount = 0;\n const entries = globEntries({\n cwd: realSource,\n pattern: '**/*',\n includeHidden: true,\n skipIgnored: false,\n onlyFiles: false,\n ...(signal ? { signal } : {}),\n });\n try {\n for await (const entry of entries) {\n signal?.throwIfAborted();\n const entryRelativePath = relative(realSource, entry.path);\n const requestedSourcePath = resolve(requestedSource, entryRelativePath);\n const destinationPath = resolve(validDest, entryRelativePath);\n const protectedBefore =\n fs.pathGuard.isSensitive(entry.path) || fs.pathGuard.isSensitive(requestedSourcePath);\n const protectedAfter = fs.pathGuard.isSensitive(destinationPath);\n if (protectedBefore !== protectedAfter) {\n protectedCount++;\n break;\n }\n }\n } catch (error) {\n rethrowIfAborted(error);\n throw new FsError(\n ErrorCode.ACCESS_DENIED,\n `${VERB[op]} refused: the directory could not be fully inspected for protected entries`,\n requestedSource,\n error,\n );\n }\n if (protectedCount > 0) {\n throw new FsError(\n ErrorCode.ACCESS_DENIED,\n `${VERB[op]} refused: the directory contains protected entries matching the sensitive-file policy; move or copy individual files instead`,\n requestedSource,\n );\n }\n}\n\nexport async function performRenameWithFallback(\n validSource: string,\n validDest: string,\n fsOps: Pick<GuardedFileSystem, 'rename' | 'cp' | 'rm'>,\n originalSource: string,\n): Promise<void> {\n try {\n await fsOps.rename(validSource, validDest);\n } catch (error: unknown) {\n rethrowIfAborted(error);\n\n if (!isNodeError(error) || error.code !== 'EXDEV') {\n throw error;\n }\n\n // EXDEV: cross-device rename. Copy then remove, preserving symlinks and\n // timestamps so link semantics survive the move.\n let copied = false;\n try {\n await fsOps.cp(validSource, validDest, {\n recursive: true,\n verbatimSymlinks: true,\n preserveTimestamps: true,\n });\n copied = true;\n await fsOps.rm(validSource, { recursive: true, force: true });\n } catch (copyOrRemoveError) {\n rethrowIfAborted(copyOrRemoveError);\n if (copied) {\n // cp succeeded but rm failed: the destination already holds a complete\n // copy and the source remains. Surface the rm error as the cause so the\n // caller can recover (clean up the duplicate) instead of a silent generic\n // failure that hides the partial completion.\n const baseProblem = Problem.fromUnknown(\n copyOrRemoveError,\n ErrorCode.UNKNOWN,\n originalSource,\n );\n throw new FsError(\n baseProblem.code,\n `Cross-device move of ${originalSource}: copy succeeded but source removal failed (destination holds a copy): ${baseProblem.message}`,\n originalSource,\n copyOrRemoveError,\n );\n }\n throw copyOrRemoveError;\n }\n }\n}\n\nexport const MOVE = defineTool<typeof MoveInputSchema, MoveOutput>({\n name: 'move',\n title: 'Move or Copy Files',\n description:\n 'Move, rename, or copy files and directories, like mv or cp -r. ' +\n 'Each destination is the full new path, not a folder to move into; missing parent directories are created.',\n input: MoveInputSchema,\n readOnlyHint: false,\n progress: (args) => {\n const label = args.copy ? 'Copy' : 'Move';\n if (args.moves.length === 1) {\n const move = args.moves[0];\n return {\n label,\n subject: `${basename(move?.source ?? '')} → ${basename(move?.destination ?? '')}`,\n };\n }\n return { label, subject: `${String(args.moves.length)} files` };\n },\n accessPaths: (args) => args.moves.flatMap((m) => [m.source, m.destination]),\n run: async (args, ctx) => {\n const op: PairOp = args.copy ? 'copy' : 'move';\n // `overwrite` is copy-only; move has no confirmation bypass.\n const outcome = await runTransfers(args.moves, ctx, op, args.copy && args.overwrite);\n // input_required is a return value, not a completed call: surface it\n // verbatim so the executor short-circuits before building a CallToolResult.\n if (isInputRequiredResult(outcome)) return outcome;\n const { results, skipped, failures } = outcome;\n return {\n structured: {\n moves: results,\n ...(failures.length > 0 ? { failures } : {}),\n ...(skipped.length > 0 ? { skipped } : {}),\n },\n text: buildSummary(op, results, failures, skipped),\n // Every requested pair failed: no move, no copy, no user-chosen skip - the\n // call did nothing. A skip is work the caller asked for, so it counts.\n isError: failures.length > 0 && results.length + skipped.length === 0,\n };\n },\n});\n"]}
|
package/dist/tools/read.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAsUA,eAAO,MAAM,IAAI,mCAkHf,CAAC"}
|
package/dist/tools/read.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
3
|
import * as z from 'zod/v4';
|
|
4
4
|
import { processInParallel } from "../core/concurrency.js";
|
|
5
|
-
import { ErrorCode } from "../core/errors.js";
|
|
5
|
+
import { ErrorCode, FsError } from "../core/errors.js";
|
|
6
6
|
import { buildFileResourceLinkFor, buildFileResourceUri } from "../core/file-uri.js";
|
|
7
7
|
import { detectMimeFromContent, detectMimeType } from "../core/mime.js";
|
|
8
8
|
import { readFileWithStats } from "../core/read.js";
|
|
@@ -110,49 +110,27 @@ async function collectFileBudget(filePaths, maxTotalSize, maxSize, ctx) {
|
|
|
110
110
|
}
|
|
111
111
|
}, PARALLEL_CONCURRENCY, ctx.signal);
|
|
112
112
|
const byIndex = new Map();
|
|
113
|
-
const known = new Map();
|
|
114
113
|
for (const { value: item } of results) {
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
byIndex.set(item.index, item.size);
|
|
118
|
-
// Keyed by the ORIGINAL requested path string (not validPath) — that's
|
|
119
|
-
// what readOnePath is called with downstream, and what filePaths[i]
|
|
120
|
-
// holds.
|
|
121
|
-
const requestedPath = filePaths[item.index];
|
|
122
|
-
if (requestedPath !== undefined) {
|
|
123
|
-
known.set(requestedPath, { validPath: item.validPath, stats: item.stats });
|
|
124
|
-
}
|
|
114
|
+
if (item)
|
|
115
|
+
byIndex.set(item.index, item);
|
|
125
116
|
}
|
|
126
117
|
let total = 0;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
const size = byIndex.get(i);
|
|
134
|
-
// A failed stat falls through to survivors so its read surfaces the real
|
|
135
|
-
// error, not a misleading TOO_LARGE.
|
|
136
|
-
if (size === undefined) {
|
|
137
|
-
survivors.push(path);
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
118
|
+
return filePaths.map((path, i) => {
|
|
119
|
+
const info = byIndex.get(i);
|
|
120
|
+
// A failed stat is neither known nor skipped, so its read surfaces the
|
|
121
|
+
// real error, not a misleading TOO_LARGE.
|
|
122
|
+
if (info === undefined)
|
|
123
|
+
return { path };
|
|
140
124
|
// Skip this file only; a later, smaller file that still fits is read.
|
|
141
|
-
if (total + size > maxTotalSize) {
|
|
142
|
-
|
|
125
|
+
if (total + info.size > maxTotalSize) {
|
|
126
|
+
return {
|
|
143
127
|
path,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
message: `Skipped: this file alone would push the batch past maxTotalSize (${String(maxTotalSize)} bytes). Read it on its own with path instead of paths.`,
|
|
147
|
-
path,
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
continue;
|
|
128
|
+
skip: new FsError(ErrorCode.TOO_LARGE, `Skipped: this file alone would push the batch past maxTotalSize (${String(maxTotalSize)} bytes). Read it on its own with path instead of paths.`, path),
|
|
129
|
+
};
|
|
151
130
|
}
|
|
152
|
-
total += size;
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
return { skippedResults, survivors, known };
|
|
131
|
+
total += info.size;
|
|
132
|
+
return { path, known: { validPath: info.validPath, stats: info.stats } };
|
|
133
|
+
});
|
|
156
134
|
}
|
|
157
135
|
function buildPerPathReadValue(result, options) {
|
|
158
136
|
const mimeInfo = detectMimeFromContent(result.path, result.content);
|
|
@@ -267,44 +245,14 @@ export const READ = defineTool({
|
|
|
267
245
|
},
|
|
268
246
|
accessPaths: singleOrBatchAccessPaths,
|
|
269
247
|
run: async (args, ctx) => {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
known = budget.known;
|
|
278
|
-
skippedResults = budget.skippedResults;
|
|
279
|
-
survivors = budget.survivors;
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
pathList = [args.path ?? ''];
|
|
283
|
-
survivors = [...pathList];
|
|
284
|
-
}
|
|
285
|
-
// Every path can be budget-skipped (a single file over maxTotalSize does
|
|
286
|
-
// it), and runOverPaths rejects an empty list. The per-path TOO_LARGE
|
|
287
|
-
// results are already built — return those rather than failing the call.
|
|
288
|
-
const batch = survivors.length === 0
|
|
289
|
-
? { results: [] }
|
|
290
|
-
: await runOverPaths(survivors, ctx, ErrorCode.NOT_FILE, (path) => readOnePath(path, args, ctx, known.get(path)));
|
|
291
|
-
const resultMap = new Map(batch.results.map((r) => [r.path, r]));
|
|
292
|
-
const ordered = pathList.map((path, idx) => {
|
|
293
|
-
const skipped = skippedResults.get(idx);
|
|
294
|
-
if (skipped)
|
|
295
|
-
return skipped;
|
|
296
|
-
const result = resultMap.get(path);
|
|
297
|
-
return (result ?? {
|
|
298
|
-
path,
|
|
299
|
-
error: { code: ErrorCode.UNKNOWN, message: 'Unknown read failure' },
|
|
300
|
-
});
|
|
248
|
+
const items = args.paths !== undefined
|
|
249
|
+
? await collectFileBudget(args.paths, READ_MANY_MAX_TOTAL_BYTES, getMaxTextFileSize(), ctx)
|
|
250
|
+
: [{ path: args.path ?? '' }];
|
|
251
|
+
const { results: ordered, summary } = await runOverPaths(items, ctx, ErrorCode.NOT_FILE, ({ path, known, skip }) => {
|
|
252
|
+
if (skip)
|
|
253
|
+
throw skip;
|
|
254
|
+
return readOnePath(path, args, ctx, known);
|
|
301
255
|
});
|
|
302
|
-
const failed = ordered.filter((r) => 'error' in r).length;
|
|
303
|
-
const summary = {
|
|
304
|
-
total: ordered.length,
|
|
305
|
-
succeeded: ordered.length - failed,
|
|
306
|
-
failed,
|
|
307
|
-
};
|
|
308
256
|
const resources = [];
|
|
309
257
|
for (const result of ordered) {
|
|
310
258
|
if ('error' in result)
|
package/dist/tools/read.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { createHash } from 'node:crypto';\nimport type { Stats } from 'node:fs';\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { processInParallel } from '../core/concurrency.ts';\nimport { ErrorCode } from '../core/errors.ts';\nimport { buildFileResourceLinkFor, buildFileResourceUri } from '../core/file-uri.ts';\nimport { detectMimeFromContent, detectMimeType, type FileKind } from '../core/mime.ts';\nimport type { ReadFileResult, ReadSpec } from '../core/read.ts';\nimport { readFileWithStats } from '../core/read.ts';\nimport {\n defaultFalseBoolean,\n singleOrBatchAccessPaths,\n singleOrBatchPathsInput,\n validateReadRange,\n} from '../core/schema.ts';\nimport {\n DEFAULT_CONTINUATION_CHUNK_SIZE,\n DEFAULT_SEARCH_TIMEOUT_MS,\n getMaxTextFileSize,\n PARALLEL_CONCURRENCY,\n READ_MANY_MAX_TOTAL_BYTES,\n} from '../core/util.ts';\nimport type { BatchResult, PerPathResult } from './batch.ts';\nimport { isTotalFailure, runOverPaths } from './batch.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\nconst rangeField = (description: string) =>\n z\n .int32()\n .min(1, { message: 'Min: 1' })\n .max(100000, { message: 'Max: 100,000' })\n .optional()\n .describe(description);\n\nconst readRangeFields = {\n head: rangeField('Return first N lines'),\n tail: rangeField('Return last N lines'),\n startLine: rangeField('Start line (1-indexed)'),\n endLine: rangeField('End line (1-indexed)'),\n};\n\nconst ReadFileInputSchema = singleOrBatchPathsInput({\n includeHash: defaultFalseBoolean('Include SHA-256 hash of the returned content in the response'),\n ...readRangeFields,\n})\n .superRefine((value, ctx) => {\n validateReadRange(\n {\n head: value.head,\n tail: value.tail,\n startLine: value.startLine,\n endLine: value.endLine,\n },\n ctx,\n );\n })\n // Mirror `validateReadRange` on the wire. Without this the four line params\n // published as four independent optional integers, so `{ path, head, tail }`\n // passed the advertised schema and was rejected only at call time.\n //\n // `oneOf` is restated because `.meta()` replaces the entry\n // `singleOrBatchPathsInput` set rather than merging into it — dropping it here\n // would silently un-publish the path/paths rule.\n .meta({\n // The line-param exclusivity that used to sit here as a five-branch\n // `not/anyOf` is one sentence in the description instead: validateReadRange\n // rejects every conflicting combination by name at runtime, so the wire copy\n // was paying for a second statement of a rule the model reads better in\n // prose.\n oneOf: [{ required: ['path'] }, { required: ['paths'] }],\n dependentRequired: { endLine: ['startLine'] },\n });\n\ninterface ReadContinuation {\n tool: 'read';\n args: { path: string; startLine: number; endLine: number };\n hint: string;\n}\n\n// File bytes ride content blocks, never the structured metadata.\ninterface ReadPerPathValue {\n mimeType?: string;\n kind?: FileKind;\n resourceUri?: string;\n /** ISO-8601 mtime at read time; also rides the resource_link. */\n modified?: string;\n continuation?: ReadContinuation;\n totalLines?: number;\n linesRead?: number;\n hasMoreLines?: boolean;\n head?: number;\n tail?: number;\n startLine?: number;\n endLine?: number;\n contentHash?: string;\n}\n\ntype ReadFileInput = z.infer<typeof ReadFileInputSchema>;\n\nconst READ_TOOL_LABEL = 'Read';\n\nfunction buildReadSpec(args: ReadFileInput, signal?: AbortSignal): ReadSpec {\n const signalPart = signal ? { signal } : {};\n const { head, tail, startLine, endLine } = args;\n\n if (head !== undefined) return { kind: 'head', lines: head, ...signalPart };\n if (tail !== undefined) return { kind: 'tail', lines: tail, ...signalPart };\n if (startLine !== undefined || endLine !== undefined) {\n return {\n kind: 'range',\n start: startLine ?? 1,\n ...(endLine !== undefined ? { end: endLine } : {}),\n ...signalPart,\n };\n }\n return { kind: 'full', ...signalPart };\n}\n\n// No `totalLines`: only `readFull` counts them and a full read never leaves\n// more behind, so a continuation cannot know the total without a second pass.\nfunction buildReadContinuation(\n result: ReadFileResult,\n requestedPath: string,\n): ReadContinuation | undefined {\n if (!result.hasMoreLines) return undefined;\n const linesRead = result.linesRead ?? 0;\n const nextStart = (result.startLine ?? 1) + linesRead;\n let chunkSize: number;\n if (result.head !== undefined) {\n chunkSize = result.head;\n } else if (result.startLine !== undefined && result.endLine !== undefined) {\n chunkSize = result.endLine - result.startLine + 1;\n } else {\n chunkSize = DEFAULT_CONTINUATION_CHUNK_SIZE;\n }\n const nextEnd = nextStart + chunkSize - 1;\n return {\n tool: 'read',\n args: { path: requestedPath, startLine: nextStart, endLine: nextEnd },\n hint: `More lines remain from ${String(nextStart)}. Read next chunk with these args.`,\n };\n}\n\n/**\n * The published metadata plus the bytes this call read. `content` and\n * `mediaData` exist only between `readOnePath` and the content blocks `run`\n * builds from them — they are stripped before the structured half is returned,\n * which is why they are not in `ReadPerPathValue`.\n */\ntype PerPathReadValue = ReadPerPathValue & {\n content?: string;\n mediaData?: string;\n};\n\ninterface BatchFileInfo {\n index: number;\n size: number;\n validPath: string;\n stats: Stats;\n}\n\nasync function collectFileBudget(\n filePaths: readonly string[],\n maxTotalSize: number,\n maxSize: number,\n ctx: Pick<ToolCtx, 'fs' | 'signal' | 'log'>,\n): Promise<{\n skippedResults: Map<number, PerPathResult<PerPathReadValue>>;\n survivors: string[];\n known: Map<string, { validPath: string; stats: Stats }>;\n}> {\n const indexed = filePaths.map((path, index) => ({ path, index }));\n const { results } = await processInParallel(\n indexed,\n async ({ path, index }): Promise<BatchFileInfo | undefined> => {\n try {\n const out = await ctx.fs.stat(path);\n return {\n index,\n size: Math.min(out.stats.size, maxSize),\n validPath: out.validPath,\n stats: out.stats,\n };\n } catch (err: unknown) {\n ctx.log('debug', `collectFileBudget: stat failed for \"${path}\": ${String(err)}`, 'read');\n return undefined;\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n const byIndex = new Map<number, number>();\n const known = new Map<string, { validPath: string; stats: Stats }>();\n for (const { value: item } of results) {\n if (!item) continue;\n byIndex.set(item.index, item.size);\n // Keyed by the ORIGINAL requested path string (not validPath) — that's\n // what readOnePath is called with downstream, and what filePaths[i]\n // holds.\n const requestedPath = filePaths[item.index];\n if (requestedPath !== undefined) {\n known.set(requestedPath, { validPath: item.validPath, stats: item.stats });\n }\n }\n\n let total = 0;\n const skippedResults = new Map<number, PerPathResult<PerPathReadValue>>();\n const survivors: string[] = [];\n for (let i = 0; i < filePaths.length; i += 1) {\n const path = filePaths[i];\n if (path === undefined) continue;\n const size = byIndex.get(i);\n // A failed stat falls through to survivors so its read surfaces the real\n // error, not a misleading TOO_LARGE.\n if (size === undefined) {\n survivors.push(path);\n continue;\n }\n // Skip this file only; a later, smaller file that still fits is read.\n if (total + size > maxTotalSize) {\n skippedResults.set(i, {\n path,\n error: {\n code: ErrorCode.TOO_LARGE,\n message: `Skipped: this file alone would push the batch past maxTotalSize (${String(maxTotalSize)} bytes). Read it on its own with path instead of paths.`,\n path,\n },\n });\n continue;\n }\n total += size;\n survivors.push(path);\n }\n\n return { skippedResults, survivors, known };\n}\n\nfunction buildPerPathReadValue(\n result: ReadFileResult,\n options: { includeHash?: boolean; requestedPath: string },\n): PerPathReadValue {\n const mimeInfo = detectMimeFromContent(result.path, result.content);\n const continuation =\n result.hasMoreLines && result.readMode !== 'tail'\n ? buildReadContinuation(result, options.requestedPath)\n : undefined;\n const contentHash = options.includeHash\n ? createHash('sha256').update(result.content, 'utf-8').digest('hex')\n : undefined;\n\n return {\n content: result.content,\n mimeType: mimeInfo.mimeType,\n kind: mimeInfo.kind,\n ...(continuation ? { continuation } : {}),\n ...(result.totalLines !== undefined ? { totalLines: result.totalLines } : {}),\n ...(result.linesRead !== undefined ? { linesRead: result.linesRead } : {}),\n ...(result.hasMoreLines ? { hasMoreLines: true } : {}),\n ...(result.head !== undefined ? { head: result.head } : {}),\n ...(result.tail !== undefined ? { tail: result.tail } : {}),\n ...(result.startLine !== undefined ? { startLine: result.startLine } : {}),\n ...(result.endLine !== undefined ? { endLine: result.endLine } : {}),\n ...(contentHash !== undefined ? { contentHash } : {}),\n resourceUri: buildFileResourceUri(result.path),\n modified: result.modified,\n };\n}\n\n/**\n * The two facts the model cannot act on without: that lines were dropped, and\n * the exact args to get the next chunk. Both used to live only in the structured\n * half, which no longer reaches the model. Each line is `//` prefixed and set\n * off by a blank line so it cannot be read as file bytes — do not drop either\n * guard.\n */\nfunction readTrailer(v: PerPathReadValue): string[] {\n const lines: string[] = [];\n if (v.continuation) {\n lines.push(\n `// truncated: ${v.continuation.hint} Continue: read ${JSON.stringify(v.continuation.args)}`,\n );\n } else if (v.hasMoreLines && v.linesRead !== undefined) {\n // A tail read gets no continuation — there are no args that read *backwards*\n // — so say what was shown rather than leaving the truncation silent.\n lines.push(`// truncated: showing last ${String(v.linesRead)} lines`);\n }\n if (v.contentHash !== undefined) lines.push(`// sha256: ${v.contentHash}`);\n return lines;\n}\n\nasync function readOnePath(\n filePath: string,\n args: ReadFileInput,\n ctx: ToolCtx,\n known?: { validPath: string; stats: Stats },\n): Promise<PerPathReadValue> {\n // Image/audio full read: return a media content block instead of throwing\n // INVALID_INPUT (\"Binary file detected.\"). Line-range reads are\n // text-oriented and stay rejected. `readRaw` enforces the same size cap as\n // the text path (getMaxTextFileSize), so a too-large image surfaces TOO_LARGE\n // rather than blowing memory. svg carries kind:'image' but is XML text —\n // readRaw.isBinary is false for it, so it falls through to the text path.\n const isRangeRead =\n args.head !== undefined ||\n args.tail !== undefined ||\n args.startLine !== undefined ||\n args.endLine !== undefined;\n if (!isRangeRead) {\n const mime = detectMimeType(filePath);\n if (mime.kind === 'image' || mime.kind === 'audio') {\n const raw = await ctx.fs.readRaw(filePath, { signal: ctx.signal });\n if (raw.isBinary) {\n return {\n content: `[binary ${mime.kind} content: ${String(raw.content.length)} bytes; returned as a ${mime.kind} content block]`,\n mimeType: raw.mimeType,\n kind: mime.kind,\n mediaData: raw.content.toString('base64'),\n };\n }\n }\n }\n\n const spec = buildReadSpec(args, ctx.signal);\n const result = known\n ? await readFileWithStats(filePath, known.validPath, known.stats, spec)\n : await ctx.fs.readFile(filePath, spec);\n\n return buildPerPathReadValue(result, {\n includeHash: args.includeHash,\n // The continuation is args the caller pastes back, so it echoes the path\n // they wrote. `result.path` is the resolved absolute one — on Windows that\n // is a backslash-doubling JSON string that also spells out the server root.\n requestedPath: filePath,\n });\n}\n\nexport const READ = defineTool<typeof ReadFileInputSchema, BatchResult<ReadPerPathValue>>({\n name: 'read',\n title: 'Read File',\n description:\n 'Read text files, like cat: whole, or one slice via head, tail, or startLine/endLine. ' +\n 'Images and audio return as media; other binary files are rejected.',\n input: ReadFileInputSchema,\n readOnlyHint: true,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n defaultErrorCode: ErrorCode.NOT_FILE,\n progress: (args) => {\n const isBatch = args.paths !== undefined;\n const name = isBatch ? `${String(args.paths?.length ?? 0)} files` : basename(args.path ?? '');\n if (isBatch) {\n return { label: READ_TOOL_LABEL, subject: name };\n }\n let scope: string | undefined;\n if (args.startLine !== undefined) {\n const end = args.endLine ?? '...';\n scope = `${args.startLine}-${String(end)}`;\n } else if (args.head !== undefined) {\n scope = `head ${args.head}`;\n } else if (args.tail !== undefined) {\n scope = `tail ${args.tail}`;\n }\n return { label: READ_TOOL_LABEL, subject: name, ...(scope ? { scope } : {}) };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n let pathList: string[];\n let skippedResults = new Map<number, PerPathResult<PerPathReadValue>>();\n let survivors: string[];\n let known = new Map<string, { validPath: string; stats: Stats }>();\n\n if (args.paths !== undefined) {\n pathList = args.paths;\n const budget = await collectFileBudget(\n pathList,\n READ_MANY_MAX_TOTAL_BYTES,\n getMaxTextFileSize(),\n ctx,\n );\n known = budget.known;\n skippedResults = budget.skippedResults;\n survivors = budget.survivors;\n } else {\n pathList = [args.path ?? ''];\n survivors = [...pathList];\n }\n\n // Every path can be budget-skipped (a single file over maxTotalSize does\n // it), and runOverPaths rejects an empty list. The per-path TOO_LARGE\n // results are already built — return those rather than failing the call.\n const batch =\n survivors.length === 0\n ? { results: [] as PerPathResult<PerPathReadValue>[] }\n : await runOverPaths(survivors, ctx, ErrorCode.NOT_FILE, (path) =>\n readOnePath(path, args, ctx, known.get(path)),\n );\n\n const resultMap = new Map(batch.results.map((r) => [r.path, r]));\n const ordered: PerPathResult<PerPathReadValue>[] = pathList.map((path, idx) => {\n const skipped = skippedResults.get(idx);\n if (skipped) return skipped;\n const result = resultMap.get(path);\n return (\n result ?? {\n path,\n error: { code: ErrorCode.UNKNOWN, message: 'Unknown read failure' },\n }\n );\n });\n\n const failed = ordered.filter((r) => 'error' in r).length;\n const summary = {\n total: ordered.length,\n succeeded: ordered.length - failed,\n failed,\n };\n\n const resources: ContentBlock[] = [];\n for (const result of ordered) {\n if ('error' in result) continue;\n const v = result.value;\n // Image/audio full read: emit the media content block alongside the\n // structured value. The base64 lives in v.mediaData (set in readOnePath).\n if (v.mediaData && v.mimeType && (v.kind === 'image' || v.kind === 'audio')) {\n resources.push(\n v.kind === 'image'\n ? { type: 'image', data: v.mediaData, mimeType: v.mimeType }\n : { type: 'audio', data: v.mediaData, mimeType: v.mimeType },\n );\n continue;\n }\n if (!v.resourceUri || !v.content) continue;\n // `result.path` is the path as *requested*; `v.resourceUri` was built from\n // the *validated* one. Rebuilding from the request would emit a second URI\n // for the same file whenever the two differ in case — subscribe by one and\n // unsubscribe by the other and the watcher never goes away.\n resources.push(\n buildFileResourceLinkFor(\n v.resourceUri,\n basename(result.path),\n v.mimeType ?? 'application/octet-stream',\n Buffer.byteLength(v.content, 'utf8'),\n v.modified,\n ),\n );\n }\n\n const [firstOrdered] = ordered;\n const body = (v: PerPathReadValue): string => {\n const content = v.content ?? 'read failed';\n const trailer = readTrailer(v);\n if (trailer.length === 0) return content;\n // Exactly one blank line between the bytes and the trailer, whether or not\n // the file ended in a newline.\n return `${content}${content.endsWith('\\n') ? '\\n' : '\\n\\n'}${trailer.join('\\n')}`;\n };\n const text =\n ordered.length === 1 && firstOrdered !== undefined\n ? 'error' in firstOrdered\n ? firstOrdered.error.message\n : body(firstOrdered.value)\n : ordered\n .map((r) => {\n const header = `// ${r.path}`;\n if ('value' in r) return `${header}\\n${body(r.value)}`;\n return `${header}\\n// Error: ${r.error.message}`;\n })\n .join('\\n\\n');\n\n // The bytes ship once. `text` above already carries every file's content\n // verbatim (and image/audio bytes ride the media content block), so\n // repeating them under `results[].value` doubled both the wire payload and\n // the model's token cost for every read. The structured half keeps the\n // metadata a client cannot recover from the text: paths, line counts,\n // hashes, continuations, resourceUri.\n const structuredResults = ordered.map((result) => {\n if ('error' in result) return result;\n const { content: _content, mediaData: _mediaData, ...value } = result.value;\n return { ...result, value };\n });\n\n return {\n structured: { results: structuredResults, summary },\n text,\n isError: isTotalFailure(summary),\n ...(resources.length > 0 ? { resources } : {}),\n };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { createHash } from 'node:crypto';\nimport type { Stats } from 'node:fs';\nimport { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\n\nimport { processInParallel } from '../core/concurrency.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { buildFileResourceLinkFor, buildFileResourceUri } from '../core/file-uri.ts';\nimport { detectMimeFromContent, detectMimeType, type FileKind } from '../core/mime.ts';\nimport type { ReadFileResult, ReadSpec } from '../core/read.ts';\nimport { readFileWithStats } from '../core/read.ts';\nimport {\n defaultFalseBoolean,\n singleOrBatchAccessPaths,\n singleOrBatchPathsInput,\n validateReadRange,\n} from '../core/schema.ts';\nimport {\n DEFAULT_CONTINUATION_CHUNK_SIZE,\n DEFAULT_SEARCH_TIMEOUT_MS,\n getMaxTextFileSize,\n PARALLEL_CONCURRENCY,\n READ_MANY_MAX_TOTAL_BYTES,\n} from '../core/util.ts';\nimport type { BatchResult } from './batch.ts';\nimport { isTotalFailure, runOverPaths } from './batch.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\nconst rangeField = (description: string) =>\n z\n .int32()\n .min(1, { message: 'Min: 1' })\n .max(100000, { message: 'Max: 100,000' })\n .optional()\n .describe(description);\n\nconst readRangeFields = {\n head: rangeField('Return first N lines'),\n tail: rangeField('Return last N lines'),\n startLine: rangeField('Start line (1-indexed)'),\n endLine: rangeField('End line (1-indexed)'),\n};\n\nconst ReadFileInputSchema = singleOrBatchPathsInput({\n includeHash: defaultFalseBoolean('Include SHA-256 hash of the returned content in the response'),\n ...readRangeFields,\n})\n .superRefine((value, ctx) => {\n validateReadRange(\n {\n head: value.head,\n tail: value.tail,\n startLine: value.startLine,\n endLine: value.endLine,\n },\n ctx,\n );\n })\n // Mirror `validateReadRange` on the wire. Without this the four line params\n // published as four independent optional integers, so `{ path, head, tail }`\n // passed the advertised schema and was rejected only at call time.\n //\n // `oneOf` is restated because `.meta()` replaces the entry\n // `singleOrBatchPathsInput` set rather than merging into it — dropping it here\n // would silently un-publish the path/paths rule.\n .meta({\n // The line-param exclusivity that used to sit here as a five-branch\n // `not/anyOf` is one sentence in the description instead: validateReadRange\n // rejects every conflicting combination by name at runtime, so the wire copy\n // was paying for a second statement of a rule the model reads better in\n // prose.\n oneOf: [{ required: ['path'] }, { required: ['paths'] }],\n dependentRequired: { endLine: ['startLine'] },\n });\n\ninterface ReadContinuation {\n tool: 'read';\n args: { path: string; startLine: number; endLine: number };\n hint: string;\n}\n\n// File bytes ride content blocks, never the structured metadata.\ninterface ReadPerPathValue {\n mimeType?: string;\n kind?: FileKind;\n resourceUri?: string;\n /** ISO-8601 mtime at read time; also rides the resource_link. */\n modified?: string;\n continuation?: ReadContinuation;\n totalLines?: number;\n linesRead?: number;\n hasMoreLines?: boolean;\n head?: number;\n tail?: number;\n startLine?: number;\n endLine?: number;\n contentHash?: string;\n}\n\ntype ReadFileInput = z.infer<typeof ReadFileInputSchema>;\n\nconst READ_TOOL_LABEL = 'Read';\n\nfunction buildReadSpec(args: ReadFileInput, signal?: AbortSignal): ReadSpec {\n const signalPart = signal ? { signal } : {};\n const { head, tail, startLine, endLine } = args;\n\n if (head !== undefined) return { kind: 'head', lines: head, ...signalPart };\n if (tail !== undefined) return { kind: 'tail', lines: tail, ...signalPart };\n if (startLine !== undefined || endLine !== undefined) {\n return {\n kind: 'range',\n start: startLine ?? 1,\n ...(endLine !== undefined ? { end: endLine } : {}),\n ...signalPart,\n };\n }\n return { kind: 'full', ...signalPart };\n}\n\n// No `totalLines`: only `readFull` counts them and a full read never leaves\n// more behind, so a continuation cannot know the total without a second pass.\nfunction buildReadContinuation(\n result: ReadFileResult,\n requestedPath: string,\n): ReadContinuation | undefined {\n if (!result.hasMoreLines) return undefined;\n const linesRead = result.linesRead ?? 0;\n const nextStart = (result.startLine ?? 1) + linesRead;\n let chunkSize: number;\n if (result.head !== undefined) {\n chunkSize = result.head;\n } else if (result.startLine !== undefined && result.endLine !== undefined) {\n chunkSize = result.endLine - result.startLine + 1;\n } else {\n chunkSize = DEFAULT_CONTINUATION_CHUNK_SIZE;\n }\n const nextEnd = nextStart + chunkSize - 1;\n return {\n tool: 'read',\n args: { path: requestedPath, startLine: nextStart, endLine: nextEnd },\n hint: `More lines remain from ${String(nextStart)}. Read next chunk with these args.`,\n };\n}\n\n/**\n * The published metadata plus the bytes this call read. `content` and\n * `mediaData` exist only between `readOnePath` and the content blocks `run`\n * builds from them — they are stripped before the structured half is returned,\n * which is why they are not in `ReadPerPathValue`.\n */\ntype PerPathReadValue = ReadPerPathValue & {\n content?: string;\n mediaData?: string;\n};\n\ninterface BatchFileInfo {\n index: number;\n size: number;\n validPath: string;\n stats: Stats;\n}\n\ninterface BudgetItem {\n path: string;\n known?: { validPath: string; stats: Stats };\n skip?: FsError;\n}\n\nasync function collectFileBudget(\n filePaths: readonly string[],\n maxTotalSize: number,\n maxSize: number,\n ctx: Pick<ToolCtx, 'fs' | 'signal' | 'log'>,\n): Promise<BudgetItem[]> {\n const indexed = filePaths.map((path, index) => ({ path, index }));\n const { results } = await processInParallel(\n indexed,\n async ({ path, index }): Promise<BatchFileInfo | undefined> => {\n try {\n const out = await ctx.fs.stat(path);\n return {\n index,\n size: Math.min(out.stats.size, maxSize),\n validPath: out.validPath,\n stats: out.stats,\n };\n } catch (err: unknown) {\n ctx.log('debug', `collectFileBudget: stat failed for \"${path}\": ${String(err)}`, 'read');\n return undefined;\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n const byIndex = new Map<number, BatchFileInfo>();\n for (const { value: item } of results) {\n if (item) byIndex.set(item.index, item);\n }\n\n let total = 0;\n return filePaths.map((path, i): BudgetItem => {\n const info = byIndex.get(i);\n // A failed stat is neither known nor skipped, so its read surfaces the\n // real error, not a misleading TOO_LARGE.\n if (info === undefined) return { path };\n // Skip this file only; a later, smaller file that still fits is read.\n if (total + info.size > maxTotalSize) {\n return {\n path,\n skip: new FsError(\n ErrorCode.TOO_LARGE,\n `Skipped: this file alone would push the batch past maxTotalSize (${String(maxTotalSize)} bytes). Read it on its own with path instead of paths.`,\n path,\n ),\n };\n }\n total += info.size;\n return { path, known: { validPath: info.validPath, stats: info.stats } };\n });\n}\n\nfunction buildPerPathReadValue(\n result: ReadFileResult,\n options: { includeHash?: boolean; requestedPath: string },\n): PerPathReadValue {\n const mimeInfo = detectMimeFromContent(result.path, result.content);\n const continuation =\n result.hasMoreLines && result.readMode !== 'tail'\n ? buildReadContinuation(result, options.requestedPath)\n : undefined;\n const contentHash = options.includeHash\n ? createHash('sha256').update(result.content, 'utf-8').digest('hex')\n : undefined;\n\n return {\n content: result.content,\n mimeType: mimeInfo.mimeType,\n kind: mimeInfo.kind,\n ...(continuation ? { continuation } : {}),\n ...(result.totalLines !== undefined ? { totalLines: result.totalLines } : {}),\n ...(result.linesRead !== undefined ? { linesRead: result.linesRead } : {}),\n ...(result.hasMoreLines ? { hasMoreLines: true } : {}),\n ...(result.head !== undefined ? { head: result.head } : {}),\n ...(result.tail !== undefined ? { tail: result.tail } : {}),\n ...(result.startLine !== undefined ? { startLine: result.startLine } : {}),\n ...(result.endLine !== undefined ? { endLine: result.endLine } : {}),\n ...(contentHash !== undefined ? { contentHash } : {}),\n resourceUri: buildFileResourceUri(result.path),\n modified: result.modified,\n };\n}\n\n/**\n * The two facts the model cannot act on without: that lines were dropped, and\n * the exact args to get the next chunk. Both used to live only in the structured\n * half, which no longer reaches the model. Each line is `//` prefixed and set\n * off by a blank line so it cannot be read as file bytes — do not drop either\n * guard.\n */\nfunction readTrailer(v: PerPathReadValue): string[] {\n const lines: string[] = [];\n if (v.continuation) {\n lines.push(\n `// truncated: ${v.continuation.hint} Continue: read ${JSON.stringify(v.continuation.args)}`,\n );\n } else if (v.hasMoreLines && v.linesRead !== undefined) {\n // A tail read gets no continuation — there are no args that read *backwards*\n // — so say what was shown rather than leaving the truncation silent.\n lines.push(`// truncated: showing last ${String(v.linesRead)} lines`);\n }\n if (v.contentHash !== undefined) lines.push(`// sha256: ${v.contentHash}`);\n return lines;\n}\n\nasync function readOnePath(\n filePath: string,\n args: ReadFileInput,\n ctx: ToolCtx,\n known?: { validPath: string; stats: Stats },\n): Promise<PerPathReadValue> {\n // Image/audio full read: return a media content block instead of throwing\n // INVALID_INPUT (\"Binary file detected.\"). Line-range reads are\n // text-oriented and stay rejected. `readRaw` enforces the same size cap as\n // the text path (getMaxTextFileSize), so a too-large image surfaces TOO_LARGE\n // rather than blowing memory. svg carries kind:'image' but is XML text —\n // readRaw.isBinary is false for it, so it falls through to the text path.\n const isRangeRead =\n args.head !== undefined ||\n args.tail !== undefined ||\n args.startLine !== undefined ||\n args.endLine !== undefined;\n if (!isRangeRead) {\n const mime = detectMimeType(filePath);\n if (mime.kind === 'image' || mime.kind === 'audio') {\n const raw = await ctx.fs.readRaw(filePath, { signal: ctx.signal });\n if (raw.isBinary) {\n return {\n content: `[binary ${mime.kind} content: ${String(raw.content.length)} bytes; returned as a ${mime.kind} content block]`,\n mimeType: raw.mimeType,\n kind: mime.kind,\n mediaData: raw.content.toString('base64'),\n };\n }\n }\n }\n\n const spec = buildReadSpec(args, ctx.signal);\n const result = known\n ? await readFileWithStats(filePath, known.validPath, known.stats, spec)\n : await ctx.fs.readFile(filePath, spec);\n\n return buildPerPathReadValue(result, {\n includeHash: args.includeHash,\n // The continuation is args the caller pastes back, so it echoes the path\n // they wrote. `result.path` is the resolved absolute one — on Windows that\n // is a backslash-doubling JSON string that also spells out the server root.\n requestedPath: filePath,\n });\n}\n\nexport const READ = defineTool<typeof ReadFileInputSchema, BatchResult<ReadPerPathValue>>({\n name: 'read',\n title: 'Read File',\n description:\n 'Read text files, like cat: whole, or one slice via head, tail, or startLine/endLine. ' +\n 'Images and audio return as media; other binary files are rejected.',\n input: ReadFileInputSchema,\n readOnlyHint: true,\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n defaultErrorCode: ErrorCode.NOT_FILE,\n progress: (args) => {\n const isBatch = args.paths !== undefined;\n const name = isBatch ? `${String(args.paths?.length ?? 0)} files` : basename(args.path ?? '');\n if (isBatch) {\n return { label: READ_TOOL_LABEL, subject: name };\n }\n let scope: string | undefined;\n if (args.startLine !== undefined) {\n const end = args.endLine ?? '...';\n scope = `${args.startLine}-${String(end)}`;\n } else if (args.head !== undefined) {\n scope = `head ${args.head}`;\n } else if (args.tail !== undefined) {\n scope = `tail ${args.tail}`;\n }\n return { label: READ_TOOL_LABEL, subject: name, ...(scope ? { scope } : {}) };\n },\n accessPaths: singleOrBatchAccessPaths,\n run: async (args, ctx) => {\n const items: BudgetItem[] =\n args.paths !== undefined\n ? await collectFileBudget(args.paths, READ_MANY_MAX_TOTAL_BYTES, getMaxTextFileSize(), ctx)\n : [{ path: args.path ?? '' }];\n const { results: ordered, summary } = await runOverPaths(\n items,\n ctx,\n ErrorCode.NOT_FILE,\n ({ path, known, skip }) => {\n if (skip) throw skip;\n return readOnePath(path, args, ctx, known);\n },\n );\n\n const resources: ContentBlock[] = [];\n for (const result of ordered) {\n if ('error' in result) continue;\n const v = result.value;\n // Image/audio full read: emit the media content block alongside the\n // structured value. The base64 lives in v.mediaData (set in readOnePath).\n if (v.mediaData && v.mimeType && (v.kind === 'image' || v.kind === 'audio')) {\n resources.push(\n v.kind === 'image'\n ? { type: 'image', data: v.mediaData, mimeType: v.mimeType }\n : { type: 'audio', data: v.mediaData, mimeType: v.mimeType },\n );\n continue;\n }\n if (!v.resourceUri || !v.content) continue;\n // `result.path` is the path as *requested*; `v.resourceUri` was built from\n // the *validated* one. Rebuilding from the request would emit a second URI\n // for the same file whenever the two differ in case — subscribe by one and\n // unsubscribe by the other and the watcher never goes away.\n resources.push(\n buildFileResourceLinkFor(\n v.resourceUri,\n basename(result.path),\n v.mimeType ?? 'application/octet-stream',\n Buffer.byteLength(v.content, 'utf8'),\n v.modified,\n ),\n );\n }\n\n const [firstOrdered] = ordered;\n const body = (v: PerPathReadValue): string => {\n const content = v.content ?? 'read failed';\n const trailer = readTrailer(v);\n if (trailer.length === 0) return content;\n // Exactly one blank line between the bytes and the trailer, whether or not\n // the file ended in a newline.\n return `${content}${content.endsWith('\\n') ? '\\n' : '\\n\\n'}${trailer.join('\\n')}`;\n };\n const text =\n ordered.length === 1 && firstOrdered !== undefined\n ? 'error' in firstOrdered\n ? firstOrdered.error.message\n : body(firstOrdered.value)\n : ordered\n .map((r) => {\n const header = `// ${r.path}`;\n if ('value' in r) return `${header}\\n${body(r.value)}`;\n return `${header}\\n// Error: ${r.error.message}`;\n })\n .join('\\n\\n');\n\n // The bytes ship once. `text` above already carries every file's content\n // verbatim (and image/audio bytes ride the media content block), so\n // repeating them under `results[].value` doubled both the wire payload and\n // the model's token cost for every read. The structured half keeps the\n // metadata a client cannot recover from the text: paths, line counts,\n // hashes, continuations, resourceUri.\n const structuredResults = ordered.map((result) => {\n if ('error' in result) return result;\n const { content: _content, mediaData: _mediaData, ...value } = result.value;\n return { ...result, value };\n });\n\n return {\n structured: { results: structuredResults, summary },\n text,\n isError: isTotalFailure(summary),\n ...(resources.length > 0 ? { resources } : {}),\n };\n },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAUxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAUxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAmBrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmNjD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,CA4HjB"}
|
package/dist/transport/http.js
CHANGED
|
@@ -11,7 +11,7 @@ import { parseTrueEnvFlag } from "../core/path-utils.js";
|
|
|
11
11
|
import { PathGuard } from "../core/path.js";
|
|
12
12
|
import { PageSnapshotStore, ResourceStore } from "../core/store.js";
|
|
13
13
|
import { getMaxInboundMessageBytes, parseEnvInt } from "../core/util.js";
|
|
14
|
-
import { createWatcherRegistry
|
|
14
|
+
import { createWatcherRegistry } from "../core/watcher-registry.js";
|
|
15
15
|
import { createServer } from "../server.js";
|
|
16
16
|
import { assertHttpBindingPolicy, assertHttpHostPolicy, bearerAuthMiddleware, computeAllowedOriginHostnames, corsMiddleware, createRateLimiter, isLoopbackHttpHost, JSONRPC_SERVER_ERROR, protectedResourceUrl, resolveAllowedHosts, resolveTrustProxySetting, sendJsonRpcError, } from "./http-policy.js";
|
|
17
17
|
import { jsonRpcRequestId, listenSubscriptionUris, prepareListenWatchers } from "./shared.js";
|
|
@@ -126,18 +126,7 @@ function setupExpressApp(httpHost, apiKey, allowedHosts, modernNodeHandler, shar
|
|
|
126
126
|
await modernNodeHandler(req, res, parsedBody);
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
|
-
//
|
|
130
|
-
// every requested URI is watched when the watcher budget is exhausted.
|
|
131
|
-
// The per-URI `capped` failure below would also reject, but only after
|
|
132
|
-
// creating and tearing down every watcher up to the cap.
|
|
133
|
-
// Only URIs without a live watcher consume a slot; a re-listen to an
|
|
134
|
-
// already-watched URI just retains another lease.
|
|
135
|
-
const newUris = requestedUris.filter((uri) => !sharedRegistry.hasWatcher(uri));
|
|
136
|
-
const available = MAX_WATCHERS - sharedRegistry.size();
|
|
137
|
-
if (newUris.length > available) {
|
|
138
|
-
sendJsonRpcError(res, 400, ProtocolErrorCode.InvalidParams, `subscriptions/listen names ${newUris.length} not-yet-watched URIs but only ${available} watcher slots remain (cap ${MAX_WATCHERS}). Reduce the resourceSubscriptions list.`, jsonRpcRequestId(parsedBody));
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
129
|
+
// Over-cap listens are rejected inside prepareListenWatchers, before the ack.
|
|
141
130
|
const prepared = await prepareListenWatchers(requestedUris, sharedPathGuard, sharedRegistry, resourceUpdateSink);
|
|
142
131
|
if (!prepared.ok) {
|
|
143
132
|
sendJsonRpcError(res, 400, ProtocolErrorCode.InvalidParams, prepared.message, jsonRpcRequestId(parsedBody));
|
|
@@ -221,11 +210,6 @@ export async function startHttpServer(port, options, config = {}) {
|
|
|
221
210
|
era,
|
|
222
211
|
...(apiKey !== undefined ? { apiKey } : {}),
|
|
223
212
|
});
|
|
224
|
-
const previousOnClose = c.mcp.server.onclose;
|
|
225
|
-
c.mcp.server.onclose = () => {
|
|
226
|
-
previousOnClose?.();
|
|
227
|
-
c.disposeRuntimeState();
|
|
228
|
-
};
|
|
229
213
|
return c.mcp;
|
|
230
214
|
}, {
|
|
231
215
|
// The SDK's default: a 2025-era request is answered by a fresh instance
|