@j0hanz/filesystem-mcp 2.8.0 → 2.9.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.
Files changed (134) hide show
  1. package/README.md +32 -26
  2. package/dist/cli-help.d.ts.map +1 -1
  3. package/dist/cli-help.js +10 -1
  4. package/dist/cli-help.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +10 -3
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/concurrency.d.ts +4 -4
  9. package/dist/core/concurrency.d.ts.map +1 -1
  10. package/dist/core/concurrency.js +1 -1
  11. package/dist/core/concurrency.js.map +1 -1
  12. package/dist/core/config.d.ts +2 -0
  13. package/dist/core/config.d.ts.map +1 -1
  14. package/dist/core/config.js.map +1 -1
  15. package/dist/core/cursor.d.ts +8 -0
  16. package/dist/core/cursor.d.ts.map +1 -1
  17. package/dist/core/cursor.js +14 -0
  18. package/dist/core/cursor.js.map +1 -1
  19. package/dist/core/file-uri.d.ts +12 -3
  20. package/dist/core/file-uri.d.ts.map +1 -1
  21. package/dist/core/file-uri.js +35 -7
  22. package/dist/core/file-uri.js.map +1 -1
  23. package/dist/core/fmt.d.ts +2 -0
  24. package/dist/core/fmt.d.ts.map +1 -1
  25. package/dist/core/fmt.js +16 -0
  26. package/dist/core/fmt.js.map +1 -1
  27. package/dist/core/fs.d.ts +16 -1
  28. package/dist/core/fs.d.ts.map +1 -1
  29. package/dist/core/fs.js +191 -72
  30. package/dist/core/fs.js.map +1 -1
  31. package/dist/core/glob.d.ts +8 -0
  32. package/dist/core/glob.d.ts.map +1 -1
  33. package/dist/core/glob.js +84 -11
  34. package/dist/core/glob.js.map +1 -1
  35. package/dist/core/input-required.d.ts +7 -0
  36. package/dist/core/input-required.d.ts.map +1 -1
  37. package/dist/core/input-required.js +13 -0
  38. package/dist/core/input-required.js.map +1 -1
  39. package/dist/core/path-completer.d.ts.map +1 -1
  40. package/dist/core/path-completer.js +5 -3
  41. package/dist/core/path-completer.js.map +1 -1
  42. package/dist/core/path-utils.d.ts +51 -12
  43. package/dist/core/path-utils.d.ts.map +1 -1
  44. package/dist/core/path-utils.js +69 -29
  45. package/dist/core/path-utils.js.map +1 -1
  46. package/dist/core/path.d.ts +108 -21
  47. package/dist/core/path.d.ts.map +1 -1
  48. package/dist/core/path.js +436 -83
  49. package/dist/core/path.js.map +1 -1
  50. package/dist/core/read.d.ts +13 -3
  51. package/dist/core/read.d.ts.map +1 -1
  52. package/dist/core/read.js +46 -40
  53. package/dist/core/read.js.map +1 -1
  54. package/dist/core/schema.d.ts +9 -6
  55. package/dist/core/schema.d.ts.map +1 -1
  56. package/dist/core/schema.js +22 -19
  57. package/dist/core/schema.js.map +1 -1
  58. package/dist/core/search.d.ts +6 -0
  59. package/dist/core/search.d.ts.map +1 -1
  60. package/dist/core/search.js +159 -33
  61. package/dist/core/search.js.map +1 -1
  62. package/dist/core/sensitive.d.ts.map +1 -1
  63. package/dist/core/sensitive.js +71 -29
  64. package/dist/core/sensitive.js.map +1 -1
  65. package/dist/core/store.d.ts +1 -0
  66. package/dist/core/store.d.ts.map +1 -1
  67. package/dist/core/store.js +3 -0
  68. package/dist/core/store.js.map +1 -1
  69. package/dist/core/util.d.ts +12 -1
  70. package/dist/core/util.d.ts.map +1 -1
  71. package/dist/core/util.js +24 -1
  72. package/dist/core/util.js.map +1 -1
  73. package/dist/prompts.d.ts +1 -1
  74. package/dist/prompts.d.ts.map +1 -1
  75. package/dist/prompts.js +1 -1
  76. package/dist/prompts.js.map +1 -1
  77. package/dist/resources.d.ts +1 -2
  78. package/dist/resources.d.ts.map +1 -1
  79. package/dist/resources.js +20 -13
  80. package/dist/resources.js.map +1 -1
  81. package/dist/server.js +2 -2
  82. package/dist/server.js.map +1 -1
  83. package/dist/tools/create.d.ts.map +1 -1
  84. package/dist/tools/create.js +122 -45
  85. package/dist/tools/create.js.map +1 -1
  86. package/dist/tools/define.d.ts +8 -4
  87. package/dist/tools/define.d.ts.map +1 -1
  88. package/dist/tools/define.js +36 -9
  89. package/dist/tools/define.js.map +1 -1
  90. package/dist/tools/delete.d.ts.map +1 -1
  91. package/dist/tools/delete.js +57 -17
  92. package/dist/tools/delete.js.map +1 -1
  93. package/dist/tools/diff.js +1 -1
  94. package/dist/tools/diff.js.map +1 -1
  95. package/dist/tools/edit.d.ts.map +1 -1
  96. package/dist/tools/edit.js +14 -12
  97. package/dist/tools/edit.js.map +1 -1
  98. package/dist/tools/find-files.d.ts.map +1 -1
  99. package/dist/tools/find-files.js +20 -20
  100. package/dist/tools/find-files.js.map +1 -1
  101. package/dist/tools/index.d.ts +1 -1
  102. package/dist/tools/index.d.ts.map +1 -1
  103. package/dist/tools/index.js +1 -1
  104. package/dist/tools/index.js.map +1 -1
  105. package/dist/tools/list.d.ts.map +1 -1
  106. package/dist/tools/list.js +142 -73
  107. package/dist/tools/list.js.map +1 -1
  108. package/dist/tools/move.d.ts.map +1 -1
  109. package/dist/tools/move.js +81 -36
  110. package/dist/tools/move.js.map +1 -1
  111. package/dist/tools/patch.js +13 -6
  112. package/dist/tools/patch.js.map +1 -1
  113. package/dist/tools/read.d.ts.map +1 -1
  114. package/dist/tools/read.js +114 -45
  115. package/dist/tools/read.js.map +1 -1
  116. package/dist/tools/replace-text.d.ts.map +1 -1
  117. package/dist/tools/replace-text.js +49 -35
  118. package/dist/tools/replace-text.js.map +1 -1
  119. package/dist/tools/search-text.d.ts.map +1 -1
  120. package/dist/tools/search-text.js +20 -49
  121. package/dist/tools/search-text.js.map +1 -1
  122. package/dist/tools/stat.d.ts.map +1 -1
  123. package/dist/tools/stat.js +26 -8
  124. package/dist/tools/stat.js.map +1 -1
  125. package/dist/transport/http-policy.d.ts +3 -2
  126. package/dist/transport/http-policy.d.ts.map +1 -1
  127. package/dist/transport/http-policy.js +3 -2
  128. package/dist/transport/http-policy.js.map +1 -1
  129. package/dist/transport/http.d.ts.map +1 -1
  130. package/dist/transport/http.js +2 -2
  131. package/dist/transport/http.js.map +1 -1
  132. package/dist/transport/stdio.js +1 -1
  133. package/dist/transport/stdio.js.map +1 -1
  134. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/tools/define.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CallToolResult,\n ClientCapabilities,\n ContentBlock,\n InputRequiredResult,\n McpServer,\n Notification,\n RegisteredTool,\n RequestId,\n RequestStateAccessor,\n ServerContext,\n StandardSchemaWithJSON,\n ToolAnnotations,\n} from '@modelcontextprotocol/server';\nimport {\n CLIENT_CAPABILITIES_META_KEY,\n isInputRequiredResult,\n TRACEPARENT_META_KEY,\n} from '@modelcontextprotocol/server';\n\nimport type * as z from 'zod/v4';\n\nimport { ErrorCode, formatUnknownErrorMessage, FsError, Problem } from '../core/errors.ts';\nimport type { ProgressCtx } from '../core/fmt.ts';\nimport { plainMessage } from '../core/fmt.ts';\nimport { GuardedFileSystem } from '../core/fs.ts';\nimport {\n confirmKey,\n pendingRoundTrip,\n readAcceptedConfirm,\n readAcceptedMultiChoice,\n} from '../core/input-required.ts';\nimport { Logger, sanitizeLogField } from '../core/observability.ts';\nimport type { LoggingLevel } from '../core/observability.ts';\nimport { isSamePath } from '../core/path-utils.ts';\nimport type { PathGuard } from '../core/path.ts';\nimport { withSplitArgsRecovery } from '../core/schema.ts';\nimport type { PageSnapshotStore, ResourceStore } from '../core/store.ts';\nimport { jsonBytesOver, MAX_OUTBOUND_RESULT_BYTES } from '../core/util.ts';\nimport { ProgressSession } from './progress.ts';\n\nexport interface ToolCtx {\n readonly signal: AbortSignal;\n /** The JSON-RPC id of the `tools/call` this context serves; prefixes every log line. */\n readonly requestId: RequestId;\n readonly fs: GuardedFileSystem;\n readonly pageStore: PageSnapshotStore;\n readonly resourceStore: ResourceStore;\n /** Emits a log line to stderr via `Logger.emit`, gated by `FS_LOG_LEVEL`. */\n readonly log: (level: LoggingLevel, data: unknown, logger?: string) => void;\n readonly onProgress: (params: { current: number; total?: number }) => void;\n /**\n * Multi-round-trip `inputResponses` carried by a retried `tools/call`\n * (protocol revision 2026-07-28); `undefined` on the first round. Bare,\n * unvalidated client values — handlers read them through\n * `readAcceptedConfirm`.\n */\n readonly inputResponses?: Record<string, unknown> | undefined;\n /**\n * Keys of `inputResponses` entries the SDK dropped on this round because\n * they were not bare results (the `{ method, result }` wrapper some hosts\n * send). `pendingRoundTrip` re-issues a confirmation whose key is listed\n * here once; `describeRefusal` names the cause after that.\n */\n readonly droppedInputResponseKeys?: readonly string[] | undefined;\n /**\n * Reads the verified multi-round-trip `requestState` for the current round:\n * the decoded `PendingState` the `requestStateCodec` verified, or `undefined`\n * when the round carried no state (the first round). `undefined` when no\n * live request context is available.\n */\n readonly requestState?: RequestStateAccessor | undefined;\n /**\n * What the connected client declared it can do, or `undefined` when this\n * connection cannot say. Read by the `input_required` flows: an embedded\n * elicitation sent to a client that never declared `elicitation` is rejected\n * by the SDK with `-32021` before it reaches the wire, so the handlers check\n * first and answer with an actionable tool error instead.\n *\n * Two sources, because the eras differ: a legacy connection negotiated them\n * at `initialize` (`Server.getClientCapabilities()`), a modern one carries\n * them per request in the `_meta` envelope and never runs `initialize` at\n * all. `undefined` means \"cannot tell\" — never \"no capabilities\".\n */\n readonly clientCapabilities?: ClientCapabilities | undefined;\n /** The SDK request context this call runs under; `pendingRoundTrip` binds minted state to it. */\n readonly serverCtx: ServerContext;\n /** `stdio` alone has a 10 MiB frame limit; `http` on HTTP, unset on the in-memory test pair. */\n readonly transport?: 'stdio' | 'http' | undefined;\n}\n\nexport interface ToolDeps {\n readonly server: McpServer;\n readonly pathGuard: PathGuard;\n readonly pageStore: PageSnapshotStore;\n readonly resourceStore: ResourceStore;\n readonly era?: 'legacy' | 'modern';\n readonly transport?: 'stdio' | 'http';\n}\n\ninterface RunResult<T> {\n readonly structured: T;\n readonly text?: string;\n readonly resources?: ContentBlock[];\n /**\n * The call as a whole failed. Batch tools set it from `isTotalFailure` in\n * `batch.ts` — every requested item failed — so the executor never has to\n * know a tool's output shape. Absent or `false` means the call did work.\n */\n readonly isError?: boolean;\n}\n\nexport interface ToolDef<I extends z.ZodType, O extends object> {\n readonly name: string;\n readonly title: string;\n readonly description: string;\n readonly input: I;\n /** Required: drives both the --read-only gate and published annotations. */\n readonly readOnlyHint: boolean;\n readonly timeoutMs?: number;\n readonly progress?: (args: z.infer<I>) => ProgressCtx;\n readonly progressDone?: (args: z.infer<I>, result: O) => Partial<ProgressCtx>;\n readonly defaultErrorCode?: ErrorCode;\n /**\n * The filesystem paths this tool will operate on, extracted from its parsed\n * args. The executor runs an access-grant pre-check over these BEFORE `run`\n * (R7): any path outside the granted roots yields an `input_required`\n * round-trip requesting a grant, and nothing is touched until the client\n * retries with an accepted grant (R8). Omit for tools that do not operate on\n * caller-supplied filesystem paths.\n */\n readonly accessPaths?: (args: z.infer<I>) => readonly string[];\n readonly run: (args: z.infer<I>, ctx: ToolCtx) => Promise<RunResult<O> | InputRequiredResult>;\n /**\n * What the stdio size refusal tells the caller to do instead, for a tool\n * that knows better than the generic advice (see `refuseOversized`).\n */\n readonly oversizeRemedy?: (result: RunResult<O>) => string;\n}\n\nexport interface DefinedTool {\n readonly name: string;\n readonly readOnlyHint: boolean;\n\n register(deps: ToolDeps): RegisteredTool;\n}\n\nfunction toToolCtx(ctx: ServerContext, deps: ToolDeps): Omit<ToolCtx, 'log' | 'onProgress'> {\n // Envelope first, accessor second — the two eras carry this differently.\n // A modern request states the capabilities in its own `_meta` envelope; a\n // legacy connection fixed them at `initialize` and has no envelope at all.\n // The deprecated accessor still answers for both today (the SDK backfills it\n // per request from the validated envelope on modern instances), but reading\n // the envelope directly is the supported path, so it leads: when the accessor\n // goes, legacy degrades to \"cannot tell\", which fails open to the behavior\n // that predates this check.\n //\n // The cast is the SDK's shipped `RequestMetaEnvelope` declaration collapsing\n // to `{}` — the reserved keys survive at runtime but not in the .d.ts, so the\n // key constant cannot index the declared type.\n const envelope = ctx.mcpReq.envelope as Record<string, unknown> | undefined;\n const clientCapabilities =\n (envelope?.[CLIENT_CAPABILITIES_META_KEY] as ClientCapabilities | undefined) ??\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- the only source of client capabilities on a legacy connection, where no envelope exists.\n deps.server.server.getClientCapabilities() ??\n // A legacy instance that never saw `initialize` is the HTTP leg's\n // per-request serving (`createMcpHandler` with `legacy: 'stateless'`):\n // there is no return path for a server-to-client request, so read the\n // client as having declared nothing. The `input_required` flows then\n // answer with their named workaround instead of the SDK's generic refusal.\n // sunset(SEP-2577): removal trigger in docs/adr/002-legacy-protocol-paths-sunset.md.\n (deps.era === 'legacy' ? {} : undefined);\n\n return {\n signal: ctx.mcpReq.signal,\n requestId: ctx.mcpReq.id,\n fs: new GuardedFileSystem(deps.pathGuard),\n pageStore: deps.pageStore,\n resourceStore: deps.resourceStore,\n inputResponses: ctx.mcpReq.inputResponses,\n droppedInputResponseKeys: ctx.mcpReq.droppedInputResponseKeys,\n requestState: ctx.mcpReq.requestState,\n serverCtx: ctx,\n ...(clientCapabilities ? { clientCapabilities } : {}),\n ...(deps.transport ? { transport: deps.transport } : {}),\n };\n}\n\n/**\n * Claude Code — and any client that treats `structuredContent` as the canonical\n * model view — discards the `text` blocks when `structuredContent` is present,\n * showing the model `JSON.stringify(structuredContent)` instead. A tool that\n * authored a text result (list's ASCII tree, read's file) meant that text for\n * the model, so it ships its metadata under `_meta`, which no client renders in\n * place of the content. Tools with no `text` keep `structuredContent`: the JSON\n * *is* their model-facing view.\n */\nfunction buildSuccessResponse<O extends object>(result: RunResult<O>): CallToolResult {\n const hasText = result.text !== undefined;\n const text = result.text ?? JSON.stringify(result.structured);\n const content: ContentBlock[] = [{ type: 'text' as const, text }, ...(result.resources ?? [])];\n return {\n content,\n ...(hasText // Result interfaces have named fields; the SDK metadata requires an index signature.\n ? { _meta: result.structured as Record<string, unknown> }\n : { structuredContent: result.structured }),\n ...(result.isError ? { isError: true } : {}),\n };\n}\n\nclass ToolExecutor<I extends z.ZodType, O extends object> {\n readonly signal: AbortSignal;\n private readonly def: ToolDef<I, O>;\n private readonly parsedArgs: z.infer<I>;\n private readonly toolCtx: ToolCtx;\n\n readonly #progressCtx: ProgressCtx;\n readonly #progressSession: ProgressSession;\n\n constructor(\n toolName: string,\n ctx: Omit<ToolCtx, 'log' | 'onProgress'>,\n def: ToolDef<I, O>,\n parsedArgs: z.infer<I>,\n ) {\n this.def = def;\n this.parsedArgs = parsedArgs;\n this.signal = def.timeoutMs\n ? AbortSignal.any([ctx.signal, AbortSignal.timeout(def.timeoutMs)])\n : ctx.signal;\n this.#progressCtx = def.progress ? def.progress(parsedArgs) : { label: def.title };\n const { mcpReq } = ctx.serverCtx;\n const token = mcpReq._meta?.progressToken;\n const notify = async (notification: Notification): Promise<void> => mcpReq.notify(notification);\n this.#progressSession = new ProgressSession({\n label: this.#progressCtx.label,\n ...(token !== undefined ? { sink: { toolName, token, notify } } : {}),\n });\n const traceparent = mcpReq._meta?.[TRACEPARENT_META_KEY];\n this.toolCtx = {\n ...ctx,\n signal: this.signal,\n // Per-call views, so a response refused after `run` can take back the\n // cached result and page snapshot behind a link or cursor it never sent.\n pageStore: ctx.pageStore.forCall(),\n resourceStore: ctx.resourceStore.forCall(),\n log: (level: LoggingLevel, data: unknown, logger?: string) => {\n const msg = typeof data === 'string' ? data : String(data);\n // `[req <id>]` first so one grep finds every line of one call; the\n // traceparent rides along only when the client sent one. Both are\n // client-supplied, so they pass through `sanitizeLogField`: a control\n // character in a JSON-RPC id or a traceparent would forge log lines.\n // The message is flattened too (uncapped): it can carry a resolved\n // path or OS error text, and input schemas reject CR/LF but not the\n // Unicode line separators.\n const trace = typeof traceparent === 'string' ? ` ${sanitizeLogField(traceparent)}` : '';\n const prefix = logger ? `[${logger}] ` : '';\n const text = sanitizeLogField(msg, Infinity);\n Logger.emit(\n level,\n `[req ${sanitizeLogField(String(ctx.requestId))}${trace}] ${prefix}${text}`,\n );\n },\n onProgress: (p) => {\n this.#tick(p);\n },\n };\n }\n\n #tick(p: { current: number; total?: number }): void {\n const tickCtx: ProgressCtx = {\n ...this.#progressCtx,\n current: p.current,\n ...(p.total !== undefined ? { total: p.total } : {}),\n };\n this.#progressSession.set({ ...p, message: plainMessage('tick', tickCtx) });\n }\n\n private completeProgress(result: O): void {\n const doneCtx: ProgressCtx = this.def.progressDone\n ? { ...this.#progressCtx, ...this.def.progressDone(this.parsedArgs, result) }\n : this.#progressCtx;\n this.#progressSession.complete(plainMessage('done', doneCtx));\n }\n\n private failProgress(error: unknown): { isError: true; content: ContentBlock[] } {\n const errMsg = formatUnknownErrorMessage(error);\n this.#progressSession.fail(plainMessage('fail', { ...this.#progressCtx, error: errMsg }));\n const errorText = Problem.toText(error, this.def.defaultErrorCode ?? ErrorCode.UNKNOWN);\n return {\n content: [{ type: 'text' as const, text: errorText }],\n isError: true,\n };\n }\n\n /**\n * Access-grant pre-check (R7/R8/R9). Before `run` touches the filesystem,\n * ask PathGuard which of the tool's declared paths are out-of-root and\n * grantable. If any are and this round carries no verified `requestState`,\n * return `input_required` (nothing is read or written — R7). On retry, the\n * verified state must bind this grant set (R9); apply each accepted grant for\n * the session (R8) and proceed. A declined or ungrantable path is left for\n * `validateAccess` to fail closed during the operation. Returns `undefined`\n * when no round-trip is needed and any applicable grants have been applied.\n */\n private async precheckGrant(): Promise<InputRequiredResult | undefined> {\n const extract = this.def.accessPaths;\n if (!extract) return undefined;\n const paths = extract(this.parsedArgs);\n if (paths.length === 0) return undefined;\n const grantDirs = await this.toolCtx.fs.pathGuard.precheckAccess(paths);\n if (grantDirs.length === 0) return undefined;\n\n // One grant dir: a single boolean confirm. Multiple: one multi-select\n // elicitation so the client picks the subset to allow in one round-trip\n // (N dirs → 1 round-trip, not N). `pendingRoundTrip` still binds\n // `paths: grantDirs` sorted, so R9 path-binding is unaffected.\n const multi = grantDirs.length > 1;\n const round = await pendingRoundTrip(this.toolCtx, {\n op: 'grant',\n pending: grantDirs,\n buildInputs: (dirs) =>\n multi\n ? [\n {\n key: 'grant',\n message: 'Grant filesystem access to these directories? Select the ones to allow.',\n choices: dirs,\n multi: true,\n },\n ]\n : dirs.map((dir, i) => ({\n key: confirmKey(i),\n message: `Grant filesystem access to \"${dir}\"?`,\n })),\n });\n if (round !== undefined) return round;\n // Apply accepted grants for the session (R8). Declined/missing dirs are\n // skipped here; their paths fail with ACCESS_DENIED during the operation.\n //\n // No list-changed notification follows: a grant widens the allowed roots,\n // and no resource list reads them. The instructions resource has a fixed\n // URI, the result template lists the ResourceStore, and the file template\n // lists nothing at all (see resources.ts). Notifying here only bought the\n // client a round trip to re-fetch a list that could not have changed.\n //\n // `readAcceptedMultiChoice` does NOT validate against the offered choices\n // (attacker-controlled inputResponses on re-entry). Only grant dirs that\n // were actually offered by precheckAccess — a value outside grantDirs is\n // ignored and fails closed in validateAccess. The single-select path reads\n // `confirmKey(i)` for `grantDirs[i]`, so the isSamePath filter is a no-op\n // there; it only bites for the multi-select array.\n const accepted = multi\n ? (readAcceptedMultiChoice(this.toolCtx.inputResponses, 'grant') ?? [])\n : grantDirs.filter((_dir, i) =>\n readAcceptedConfirm(this.toolCtx.inputResponses, confirmKey(i)),\n );\n for (const dir of accepted) {\n if (!grantDirs.some((g) => isSamePath(g, dir))) continue;\n await this.toolCtx.fs.pathGuard.applyGrant(dir);\n }\n return undefined;\n }\n\n /**\n * stdio's SDK reader drops the connection on a message past 10 MiB, so a\n * response that would overflow it becomes TOO_LARGE instead. Only a call\n * that changed nothing can be refused after `run` — a read-only tool, or a\n * dry run (every tool with `dryRun` writes nothing under it); a mutation may\n * already have committed. The whole encoded response counts, duplicated\n * metadata and escaping included; the ceiling leaves room for the envelope.\n */\n private refuseOversized(result: RunResult<O>, response: CallToolResult): void {\n if (this.toolCtx.transport !== 'stdio') return;\n const dryRun = (this.parsedArgs as { dryRun?: unknown }).dryRun === true;\n if (!this.def.readOnlyHint && !dryRun) return;\n const encodedBytes = jsonBytesOver(response, MAX_OUTBOUND_RESULT_BYTES);\n if (encodedBytes === undefined) return;\n // The client never receives the link or cursor these back, so they would\n // only push live entries out of the stores' caps.\n this.toolCtx.resourceStore.discard();\n this.toolCtx.pageStore.discard();\n const remedy =\n this.def.oversizeRemedy?.(result) ??\n (dryRun\n ? 'Nothing was written. Preview fewer files or a smaller file per call, or connect over HTTP.'\n : 'Reduce the requested output or connect over HTTP.');\n // The remedy stands in for TOO_LARGE's default head/tail advice, which\n // fits neither media nor a dry run.\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `${this.def.name} result too large to return (${String(encodedBytes)} bytes once JSON-encoded, over the ${String(MAX_OUTBOUND_RESULT_BYTES)}-byte stdio message limit).`,\n undefined,\n undefined,\n remedy,\n );\n }\n\n async execute(): Promise<CallToolResult | InputRequiredResult> {\n try {\n // Access-grant pre-check before any filesystem touch (R7/R8/R9). A\n // grant input_required short-circuits here (progress paused, not\n // finished); an R9 mismatch throws, which this catch surfaces as an\n // isError tool result like every other handler failure — not a raw\n // JSON-RPC error (GRANT-1 impact #2).\n const grantRequired = await this.precheckGrant();\n if (grantRequired !== undefined) return grantRequired;\n const result = await this.def.run(this.parsedArgs, this.toolCtx);\n // input_required is a return value, not a completed call: the client\n // retries the same tools/call carrying inputResponses, and this\n // handler re-enters from the top. Skip the progress \"done\" close and\n // return it verbatim — progress is paused, not finished.\n if (isInputRequiredResult(result)) {\n return result;\n }\n const response = buildSuccessResponse(result);\n this.refuseOversized(result, response);\n this.completeProgress(result.structured);\n return response;\n } catch (error) {\n return this.failProgress(error);\n } finally {\n await this.#progressSession.flush();\n }\n }\n}\n\nexport function defineTool<I extends z.ZodType, O extends object>(def: ToolDef<I, O>): DefinedTool {\n // Nothing here depends on `deps`, so it is built once per tool definition\n // rather than once per `register` — the HTTP leg registers every tool afresh\n // on each request.\n // Filesystem tools are closed-world; only mutating tools are destructive.\n const publishedAnnotations: ToolAnnotations = {\n readOnlyHint: def.readOnlyHint,\n openWorldHint: false,\n ...(def.readOnlyHint ? {} : { destructiveHint: true }),\n };\n\n const toolDefShape = {\n title: def.title,\n description: def.description,\n // The Zod schema goes in behind `withSplitArgsRecovery` only: the SDK\n // validates with it and publishes its own draft-2020-12 conversion in\n // `tools/list`, which the preprocess step leaves unchanged. The cast only\n // names the in/out types a generic `ZodType` cannot surface through\n // `~standard`.\n inputSchema: withSplitArgsRecovery(def.input) as unknown as StandardSchemaWithJSON<\n z.input<I>,\n z.output<I>\n >,\n // No `outputSchema`, ever. Publishing one obliges the result to carry\n // `structuredContent` (clients enforce it), and every tool that authors its\n // own text ships its metadata under `_meta` instead — see\n // `buildSuccessResponse`. The two cannot both hold, and the text is what\n // the model reads. `TOOL-SURFACE-001` pins this for the whole surface.\n // Result shapes are checked by TypeScript, not unused runtime schemas.\n annotations: publishedAnnotations,\n };\n\n return {\n name: def.name,\n readOnlyHint: def.readOnlyHint,\n\n register(deps: ToolDeps): RegisteredTool {\n return deps.server.registerTool(def.name, toolDefShape, async (args, ctx) =>\n new ToolExecutor<I, O>(def.name, toToolCtx(ctx, deps), def, args).execute(),\n );\n },\n };\n}\n"]}
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/tools/define.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CallToolResult,\n ClientCapabilities,\n ContentBlock,\n InputRequiredResult,\n McpServer,\n Notification,\n RegisteredTool,\n RequestId,\n RequestStateAccessor,\n ServerContext,\n StandardSchemaWithJSON,\n ToolAnnotations,\n} from '@modelcontextprotocol/server';\nimport {\n CLIENT_CAPABILITIES_META_KEY,\n isInputRequiredResult,\n TRACEPARENT_META_KEY,\n} from '@modelcontextprotocol/server';\n\nimport type * as z from 'zod/v4';\n\nimport { ErrorCode, formatUnknownErrorMessage, FsError, Problem } from '../core/errors.ts';\nimport type { ProgressCtx } from '../core/fmt.ts';\nimport { plainMessage } from '../core/fmt.ts';\nimport { GuardedFileSystem } from '../core/fs.ts';\nimport {\n confirmKey,\n pendingRoundTrip,\n readAcceptedConfirm,\n readAcceptedMultiChoice,\n} from '../core/input-required.ts';\nimport { Logger, sanitizeLogField } from '../core/observability.ts';\nimport type { LoggingLevel } from '../core/observability.ts';\nimport { isSamePath } from '../core/path-utils.ts';\nimport type { PathGuard } from '../core/path.ts';\nimport { withSplitArgsRecovery } from '../core/schema.ts';\nimport type { PageSnapshotStore, ResourceStore } from '../core/store.ts';\nimport { getToolTimeoutMs, jsonBytesOver, MAX_OUTBOUND_RESULT_BYTES } from '../core/util.ts';\nimport { ProgressSession } from './progress.ts';\n\nexport interface ToolCtx {\n readonly signal: AbortSignal;\n /** The JSON-RPC id of the `tools/call` this context serves; prefixes every log line. */\n readonly requestId: RequestId;\n readonly fs: GuardedFileSystem;\n readonly pageStore: PageSnapshotStore;\n readonly resourceStore: ResourceStore;\n /** Emits a log line to stderr via `Logger.emit`, gated by `FS_LOG_LEVEL`. */\n readonly log: (level: LoggingLevel, data: unknown, logger?: string) => void;\n readonly onProgress: (params: { current: number; total?: number }) => void;\n /**\n * Multi-round-trip `inputResponses` carried by a retried `tools/call`\n * (protocol revision 2026-07-28); `undefined` on the first round. Bare,\n * unvalidated client values — handlers read them through\n * `readAcceptedConfirm`.\n */\n readonly inputResponses?: Record<string, unknown> | undefined;\n /**\n * Keys of `inputResponses` entries the SDK dropped on this round because\n * they were not bare results (the `{ method, result }` wrapper some hosts\n * send). `pendingRoundTrip` re-issues a confirmation whose key is listed\n * here once; `describeRefusal` names the cause after that.\n */\n readonly droppedInputResponseKeys?: readonly string[] | undefined;\n /**\n * Reads the verified multi-round-trip `requestState` for the current round:\n * the decoded `PendingState` the `requestStateCodec` verified, or `undefined`\n * when the round carried no state (the first round). `undefined` when no\n * live request context is available.\n */\n readonly requestState?: RequestStateAccessor | undefined;\n /**\n * What the connected client declared it can do, or `undefined` when this\n * connection cannot say. Read by the `input_required` flows: an embedded\n * elicitation sent to a client that never declared `elicitation` is rejected\n * by the SDK with `-32021` before it reaches the wire, so the handlers check\n * first and answer with an actionable tool error instead.\n *\n * Two sources, because the eras differ: a legacy connection negotiated them\n * at `initialize` (`Server.getClientCapabilities()`), a modern one carries\n * them per request in the `_meta` envelope and never runs `initialize` at\n * all. `undefined` means \"cannot tell\" — never \"no capabilities\".\n */\n readonly clientCapabilities?: ClientCapabilities | undefined;\n /** The SDK request context this call runs under; `pendingRoundTrip` binds minted state to it. */\n readonly serverCtx: ServerContext;\n /** `stdio` alone has a 10 MiB frame limit; `http` on HTTP, unset on the in-memory test pair. */\n readonly transport?: 'stdio' | 'http' | undefined;\n}\n\nexport interface ToolDeps {\n readonly server: McpServer;\n readonly pathGuard: PathGuard;\n readonly pageStore: PageSnapshotStore;\n readonly resourceStore: ResourceStore;\n readonly era?: 'legacy' | 'modern';\n readonly transport?: 'stdio' | 'http';\n}\n\ninterface RunResult<T> {\n readonly structured: T;\n readonly text?: string;\n readonly resources?: ContentBlock[];\n /**\n * The call as a whole failed. Batch tools set it from `isTotalFailure` in\n * `batch.ts` — every requested item failed — so the executor never has to\n * know a tool's output shape. Absent or `false` means the call did work.\n */\n readonly isError?: boolean;\n}\n\nexport interface ToolDef<I extends z.ZodType, O extends object> {\n readonly name: string;\n readonly title: string;\n readonly description: string;\n readonly input: I;\n /** Required: drives both the --read-only gate and published annotations. */\n readonly readOnlyHint: boolean;\n /** Abort the call after getToolTimeoutMs() (`--tool-timeout`, FS_TOOL_TIMEOUT_MS). */\n readonly deadline?: boolean;\n readonly progress?: (args: z.infer<I>) => ProgressCtx;\n readonly progressDone?: (args: z.infer<I>, result: O) => Partial<ProgressCtx>;\n readonly defaultErrorCode?: ErrorCode;\n /**\n * The parsed args with every caller-supplied filesystem path passed through\n * `fn`. Before `run`, the executor reads the paths through it to resolve\n * relative ones (`PathGuard.resolveRelativePaths`) and writes the results\n * back, so every check `run` makes — duplicates and overlaps included — sees\n * one spelling. It then runs the access-grant pre-check over the same paths\n * (R7): any path outside the granted roots yields an `input_required`\n * round-trip requesting a grant, and nothing is touched until the client\n * retries with an accepted grant (R8). Omit for tools that do not operate on\n * caller-supplied filesystem paths.\n */\n readonly mapPaths?: (args: z.infer<I>, fn: (path: string) => string) => z.infer<I>;\n readonly run: (args: z.infer<I>, ctx: ToolCtx) => Promise<RunResult<O> | InputRequiredResult>;\n /**\n * What the stdio size refusal tells the caller to do instead, for a tool\n * that knows better than the generic advice (see `refuseOversized`).\n */\n readonly oversizeRemedy?: (result: RunResult<O>) => string;\n}\n\nexport interface DefinedTool {\n readonly name: string;\n readonly readOnlyHint: boolean;\n\n register(deps: ToolDeps): RegisteredTool;\n}\n\nfunction toToolCtx(ctx: ServerContext, deps: ToolDeps): Omit<ToolCtx, 'log' | 'onProgress'> {\n // Envelope first, accessor second — the two eras carry this differently.\n // A modern request states the capabilities in its own `_meta` envelope; a\n // legacy connection fixed them at `initialize` and has no envelope at all.\n // The deprecated accessor still answers for both today (the SDK backfills it\n // per request from the validated envelope on modern instances), but reading\n // the envelope directly is the supported path, so it leads: when the accessor\n // goes, legacy degrades to \"cannot tell\", which fails open to the behavior\n // that predates this check.\n //\n // The cast is the SDK's shipped `RequestMetaEnvelope` declaration collapsing\n // to `{}` — the reserved keys survive at runtime but not in the .d.ts, so the\n // key constant cannot index the declared type.\n const envelope = ctx.mcpReq.envelope as Record<string, unknown> | undefined;\n const clientCapabilities =\n (envelope?.[CLIENT_CAPABILITIES_META_KEY] as ClientCapabilities | undefined) ??\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- the only source of client capabilities on a legacy connection, where no envelope exists.\n deps.server.server.getClientCapabilities() ??\n // A legacy instance that never saw `initialize` is the HTTP leg's\n // per-request serving (`createMcpHandler` with `legacy: 'stateless'`):\n // there is no return path for a server-to-client request, so read the\n // client as having declared nothing. The `input_required` flows then\n // answer with their named workaround instead of the SDK's generic refusal.\n // sunset(SEP-2577): removal trigger in docs/adr/002-legacy-protocol-paths-sunset.md.\n (deps.era === 'legacy' ? {} : undefined);\n\n return {\n signal: ctx.mcpReq.signal,\n requestId: ctx.mcpReq.id,\n fs: new GuardedFileSystem(deps.pathGuard),\n pageStore: deps.pageStore,\n resourceStore: deps.resourceStore,\n inputResponses: ctx.mcpReq.inputResponses,\n droppedInputResponseKeys: ctx.mcpReq.droppedInputResponseKeys,\n requestState: ctx.mcpReq.requestState,\n serverCtx: ctx,\n ...(clientCapabilities ? { clientCapabilities } : {}),\n ...(deps.transport ? { transport: deps.transport } : {}),\n };\n}\n\n/**\n * Claude Code — and any client that treats `structuredContent` as the canonical\n * model view — discards the `text` blocks when `structuredContent` is present,\n * showing the model `JSON.stringify(structuredContent)` instead. A tool that\n * authored a text result (list's ASCII tree, read's file) meant that text for\n * the model, so it ships its metadata under `_meta`, which no client renders in\n * place of the content. Tools with no `text` keep `structuredContent`: the JSON\n * *is* their model-facing view.\n */\nfunction buildSuccessResponse<O extends object>(result: RunResult<O>): CallToolResult {\n const hasText = result.text !== undefined;\n const text = result.text ?? JSON.stringify(result.structured);\n const content: ContentBlock[] = [{ type: 'text' as const, text }, ...(result.resources ?? [])];\n return {\n content,\n ...(hasText // Result interfaces have named fields; the SDK metadata requires an index signature.\n ? { _meta: result.structured as Record<string, unknown> }\n : { structuredContent: result.structured }),\n ...(result.isError ? { isError: true } : {}),\n };\n}\n\nclass ToolExecutor<I extends z.ZodType, O extends object> {\n readonly signal: AbortSignal;\n private readonly def: ToolDef<I, O>;\n /** Rewritten once, by `resolveRelativePaths`, before anything reads a path. */\n private parsedArgs: z.infer<I>;\n private readonly toolCtx: ToolCtx;\n\n readonly #progressCtx: ProgressCtx;\n readonly #progressSession: ProgressSession;\n\n constructor(\n toolName: string,\n ctx: Omit<ToolCtx, 'log' | 'onProgress'>,\n def: ToolDef<I, O>,\n parsedArgs: z.infer<I>,\n ) {\n this.def = def;\n this.parsedArgs = parsedArgs;\n this.signal = def.deadline\n ? AbortSignal.any([ctx.signal, AbortSignal.timeout(getToolTimeoutMs())])\n : ctx.signal;\n this.#progressCtx = def.progress ? def.progress(parsedArgs) : { label: def.title };\n const { mcpReq } = ctx.serverCtx;\n const token = mcpReq._meta?.progressToken;\n const notify = async (notification: Notification): Promise<void> => mcpReq.notify(notification);\n this.#progressSession = new ProgressSession({\n label: this.#progressCtx.label,\n ...(token !== undefined ? { sink: { toolName, token, notify } } : {}),\n });\n const traceparent = mcpReq._meta?.[TRACEPARENT_META_KEY];\n this.toolCtx = {\n ...ctx,\n signal: this.signal,\n // Per-call views, so a response refused after `run` can take back the\n // cached result and page snapshot behind a link or cursor it never sent.\n pageStore: ctx.pageStore.forCall(),\n resourceStore: ctx.resourceStore.forCall(),\n log: (level: LoggingLevel, data: unknown, logger?: string) => {\n const msg = typeof data === 'string' ? data : String(data);\n // `[req <id>]` first so one grep finds every line of one call; the\n // traceparent rides along only when the client sent one. Both are\n // client-supplied, so they pass through `sanitizeLogField`: a control\n // character in a JSON-RPC id or a traceparent would forge log lines.\n // The message is flattened too (uncapped): it can carry a resolved\n // path or OS error text, and input schemas reject CR/LF but not the\n // Unicode line separators.\n const trace = typeof traceparent === 'string' ? ` ${sanitizeLogField(traceparent)}` : '';\n const prefix = logger ? `[${logger}] ` : '';\n const text = sanitizeLogField(msg, Infinity);\n Logger.emit(\n level,\n `[req ${sanitizeLogField(String(ctx.requestId))}${trace}] ${prefix}${text}`,\n );\n },\n onProgress: (p) => {\n this.#tick(p);\n },\n };\n }\n\n #tick(p: { current: number; total?: number }): void {\n const tickCtx: ProgressCtx = {\n ...this.#progressCtx,\n current: p.current,\n ...(p.total !== undefined ? { total: p.total } : {}),\n };\n this.#progressSession.set({ ...p, message: plainMessage('tick', tickCtx) });\n }\n\n private completeProgress(result: O): void {\n const doneCtx: ProgressCtx = this.def.progressDone\n ? { ...this.#progressCtx, ...this.def.progressDone(this.parsedArgs, result) }\n : this.#progressCtx;\n this.#progressSession.complete(plainMessage('done', doneCtx));\n }\n\n private failProgress(error: unknown): { isError: true; content: ContentBlock[] } {\n const errMsg = formatUnknownErrorMessage(error);\n this.#progressSession.fail(plainMessage('fail', { ...this.#progressCtx, error: errMsg }));\n const errorText = Problem.toText(error, this.def.defaultErrorCode ?? ErrorCode.UNKNOWN);\n return {\n content: [{ type: 'text' as const, text: errorText }],\n isError: true,\n };\n }\n\n private collectPaths(): string[] {\n const paths: string[] = [];\n this.def.mapPaths?.(this.parsedArgs, (path) => {\n paths.push(path);\n return path;\n });\n return paths;\n }\n\n private async resolveRelativePaths(): Promise<void> {\n const { mapPaths } = this.def;\n if (!mapPaths) return;\n const resolved = await this.toolCtx.fs.pathGuard.resolveRelativePaths(this.collectPaths());\n if (resolved.size === 0) return;\n const rewritten = mapPaths(this.parsedArgs, (path) => resolved.get(path) ?? path);\n // The schema compared the spellings the caller sent, so `a.txt` and\n // `<root>/a.txt` passed create's and edit's one-entry-per-file rule as two\n // files. Its checks judge the resolved paths too.\n const check = this.def.input.safeParse(rewritten);\n if (!check.success) {\n const issues = check.error.issues.map(\n (issue) => `${issue.path.map(String).join('.')}: ${issue.message}`,\n );\n throw new FsError(ErrorCode.INVALID_INPUT, issues.join('; '));\n }\n this.parsedArgs = rewritten;\n }\n\n /**\n * Access-grant pre-check (R7/R8/R9). Before `run` touches the filesystem,\n * ask PathGuard which of the tool's declared paths are out-of-root and\n * grantable. If any are and this round carries no verified `requestState`,\n * return `input_required` (nothing is read or written — R7). On retry, the\n * verified state must bind this grant set (R9); apply each accepted grant for\n * the session (R8) and proceed. A declined or ungrantable path is left for\n * `validateAccess` to fail closed during the operation. Returns `undefined`\n * when no round-trip is needed and any applicable grants have been applied.\n */\n private async precheckGrant(): Promise<InputRequiredResult | undefined> {\n const paths = this.collectPaths();\n if (paths.length === 0) return undefined;\n const grantDirs = await this.toolCtx.fs.pathGuard.precheckAccess(paths);\n if (grantDirs.length === 0) return undefined;\n\n // One grant dir: a single boolean confirm. Multiple: one multi-select\n // elicitation so the client picks the subset to allow in one round-trip\n // (N dirs → 1 round-trip, not N). `pendingRoundTrip` still binds\n // `paths: grantDirs` sorted, so R9 path-binding is unaffected.\n const multi = grantDirs.length > 1;\n const round = await pendingRoundTrip(this.toolCtx, {\n op: 'grant',\n pending: grantDirs,\n buildInputs: (dirs) =>\n multi\n ? [\n {\n key: 'grant',\n message: 'Grant filesystem access to these directories? Select the ones to allow.',\n choices: dirs,\n multi: true,\n },\n ]\n : dirs.map((dir, i) => ({\n key: confirmKey(i),\n message: `Grant filesystem access to \"${dir}\"?`,\n })),\n });\n if (round !== undefined) return round;\n // Apply accepted grants for the session (R8). Declined/missing dirs are\n // skipped here; their paths fail with ACCESS_DENIED during the operation.\n //\n // No list-changed notification follows: a grant widens the allowed roots,\n // and no resource list reads them. The instructions resource has a fixed\n // URI, the result template lists the ResourceStore, and the file template\n // lists nothing at all (see resources.ts). Notifying here only bought the\n // client a round trip to re-fetch a list that could not have changed.\n //\n // `readAcceptedMultiChoice` does NOT validate against the offered choices\n // (attacker-controlled inputResponses on re-entry). Only grant dirs that\n // were actually offered by precheckAccess — a value outside grantDirs is\n // ignored and fails closed in validateAccess. The single-select path reads\n // `confirmKey(i)` for `grantDirs[i]`, so the isSamePath filter is a no-op\n // there; it only bites for the multi-select array.\n const accepted = multi\n ? (readAcceptedMultiChoice(this.toolCtx.inputResponses, 'grant') ?? [])\n : grantDirs.filter((_dir, i) =>\n readAcceptedConfirm(this.toolCtx.inputResponses, confirmKey(i)),\n );\n for (const dir of accepted) {\n if (!grantDirs.some((g) => isSamePath(g, dir))) continue;\n await this.toolCtx.fs.pathGuard.applyGrant(dir, 'access');\n }\n return undefined;\n }\n\n /**\n * stdio's SDK reader drops the connection on a message past 10 MiB, so a\n * response that would overflow it becomes TOO_LARGE instead. Only a call\n * that changed nothing can be refused after `run` — a read-only tool, or a\n * dry run (every tool with `dryRun` writes nothing under it); a mutation may\n * already have committed. The whole encoded response counts, duplicated\n * metadata and escaping included; the ceiling leaves room for the envelope.\n */\n private refuseOversized(result: RunResult<O>, response: CallToolResult): void {\n if (this.toolCtx.transport !== 'stdio') return;\n const dryRun = (this.parsedArgs as { dryRun?: unknown }).dryRun === true;\n if (!this.def.readOnlyHint && !dryRun) return;\n const encodedBytes = jsonBytesOver(response, MAX_OUTBOUND_RESULT_BYTES);\n if (encodedBytes === undefined) return;\n // The client never receives the link or cursor these back, so they would\n // only push live entries out of the stores' caps.\n this.toolCtx.resourceStore.discard();\n this.toolCtx.pageStore.discard();\n const remedy =\n this.def.oversizeRemedy?.(result) ??\n (dryRun\n ? 'Nothing was written. Preview fewer files or a smaller file per call, or connect over HTTP.'\n : 'Reduce the requested output or connect over HTTP.');\n // The remedy stands in for TOO_LARGE's default head/tail advice, which\n // fits neither media nor a dry run.\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `${this.def.name} result too large to return (${String(encodedBytes)} bytes once JSON-encoded, over the ${String(MAX_OUTBOUND_RESULT_BYTES)}-byte stdio message limit).`,\n undefined,\n undefined,\n remedy,\n );\n }\n\n async execute(): Promise<CallToolResult | InputRequiredResult> {\n try {\n // Access-grant pre-check before any filesystem touch (R7/R8/R9). A\n // grant input_required short-circuits here (progress paused, not\n // finished); an R9 mismatch throws, which this catch surfaces as an\n // isError tool result like every other handler failure — not a raw\n // JSON-RPC error (GRANT-1 impact #2). Relative paths resolve first, so\n // the pre-check judges the path the call will use; with several roots\n // that probes each candidate through validation, and reads nothing.\n await this.resolveRelativePaths();\n const grantRequired = await this.precheckGrant();\n if (grantRequired !== undefined) return grantRequired;\n const result = await this.def.run(this.parsedArgs, this.toolCtx);\n // input_required is a return value, not a completed call: the client\n // retries the same tools/call carrying inputResponses, and this\n // handler re-enters from the top. Skip the progress \"done\" close and\n // return it verbatim — progress is paused, not finished.\n if (isInputRequiredResult(result)) {\n return result;\n }\n const response = buildSuccessResponse(result);\n this.refuseOversized(result, response);\n this.completeProgress(result.structured);\n return response;\n } catch (error) {\n return this.failProgress(error);\n } finally {\n await this.#progressSession.flush();\n }\n }\n}\n\nexport function defineTool<I extends z.ZodType, O extends object>(def: ToolDef<I, O>): DefinedTool {\n // Nothing here depends on `deps`, so it is built once per tool definition\n // rather than once per `register` — the HTTP leg registers every tool afresh\n // on each request.\n // Filesystem tools are closed-world; only mutating tools are destructive.\n const publishedAnnotations: ToolAnnotations = {\n readOnlyHint: def.readOnlyHint,\n openWorldHint: false,\n ...(def.readOnlyHint ? {} : { destructiveHint: true }),\n };\n\n const toolDefShape = {\n title: def.title,\n description: def.description,\n // The Zod schema goes in behind `withSplitArgsRecovery` only: the SDK\n // validates with it and publishes its own draft-2020-12 conversion in\n // `tools/list`, which the preprocess step leaves unchanged. The cast only\n // names the in/out types a generic `ZodType` cannot surface through\n // `~standard`.\n inputSchema: withSplitArgsRecovery(def.input) as unknown as StandardSchemaWithJSON<\n z.input<I>,\n z.output<I>\n >,\n // No `outputSchema`, ever. Publishing one obliges the result to carry\n // `structuredContent` (clients enforce it), and every tool that authors its\n // own text ships its metadata under `_meta` instead — see\n // `buildSuccessResponse`. The two cannot both hold, and the text is what\n // the model reads. `TOOL-SURFACE-001` pins this for the whole surface.\n // Result shapes are checked by TypeScript, not unused runtime schemas.\n annotations: publishedAnnotations,\n };\n\n return {\n name: def.name,\n readOnlyHint: def.readOnlyHint,\n\n register(deps: ToolDeps): RegisteredTool {\n return deps.server.registerTool(def.name, toolDefShape, async (args, ctx) =>\n new ToolExecutor<I, O>(def.name, toToolCtx(ctx, deps), def, args).execute(),\n );\n },\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/tools/delete.ts"],"names":[],"mappings":"AAoYA,eAAO,MAAM,MAAM,mCA4CjB,CAAC"}
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/tools/delete.ts"],"names":[],"mappings":"AA2aA,eAAO,MAAM,MAAM,mCA4CjB,CAAC"}
@@ -4,8 +4,8 @@ import * as z from 'zod/v4';
4
4
  import { processInParallel } from "../core/concurrency.js";
5
5
  import { ErrorCode, FsError, isFsError, isNodeError, isNotFoundErrno, Problem, } from "../core/errors.js";
6
6
  import { joinRoster, pathLabel } from "../core/fmt.js";
7
- import { confirmKey, describeRefusal, pendingRoundTrip, readAcceptedChoice, } from "../core/input-required.js";
8
- import { resolveEntryType } from "../core/path-utils.js";
7
+ import { confirmKey, pendingRoundTrip, readPendingVerdict, } from "../core/input-required.js";
8
+ import { isPathInsideDirectory, resolveEntryType } from "../core/path-utils.js";
9
9
  import { defaultFalseBoolean, RequiredPath } from "../core/schema.js";
10
10
  import { PARALLEL_CONCURRENCY } from "../core/util.js";
11
11
  import { isTotalFailure, summarize } from "./batch.js";
@@ -149,16 +149,17 @@ async function finalizeDeletion(plan, args, ctx) {
149
149
  */
150
150
  async function executePlan(plan, args, ctx, pendingSorted, confirmationState) {
151
151
  if (plan.pending) {
152
- const key = confirmKey(pendingSorted.indexOf(plan.validPath));
153
- const choice = readAcceptedChoice(ctx.inputResponses, key);
154
- if (choice === 'skip') {
152
+ const verdict = readPendingVerdict(ctx, pendingSorted, plan.validPath, 'delete');
153
+ if (verdict === 'skipped') {
155
154
  return { skipped: true, path: plan.validPath };
156
155
  }
157
- if (choice !== 'delete') {
156
+ if (verdict !== 'accepted') {
158
157
  return {
159
158
  failure: {
160
159
  path: plan.validPath,
161
- error: Problem.cancelled(`Delete cancelled: confirmation was ${describeRefusal(ctx, key)}`, { path: plan.validPath }),
160
+ error: Problem.cancelled(`Delete cancelled: confirmation was ${verdict.refused}`, {
161
+ path: plan.validPath,
162
+ }),
162
163
  },
163
164
  };
164
165
  }
@@ -176,18 +177,30 @@ async function executePlan(plan, args, ctx, pendingSorted, confirmationState) {
176
177
  }
177
178
  async function handleDelete(args, ctx) {
178
179
  // Duplicate paths collapse: results are keyed by path, so a repeated entry
179
- // would emit two rows for one deletion and inflate `summary.total`.
180
+ // would emit two rows for one deletion and inflate `summary.total`. Exact
181
+ // repeats go here; other spellings of one entry collapse after planning,
182
+ // by validated path, so two on-disk names that fold alike both stay.
180
183
  const paths = [...new Set(args.paths)];
181
184
  // Phase 1 (no mutation): plan every path.
182
185
  const planned = await processInParallel(paths, (inputPath) => planPath(inputPath, args, ctx.fs), PARALLEL_CONCURRENCY, ctx.signal);
183
186
  const out = new Array(paths.length).fill(undefined);
184
- const plans = [];
187
+ let plans = [];
185
188
  const confirmationState = ctx.requestState?.();
186
189
  const previouslyPendingPaths = new Set(confirmationState?.op === 'delete' ? confirmationState.paths : []);
190
+ const seenTargets = new Set();
191
+ const duplicates = new Set();
187
192
  for (const { index, value: r } of planned.results) {
188
- if (r.status === 'fail')
193
+ if (r.status === 'fail') {
189
194
  out[index] = { path: r.failure.path, error: r.failure.error };
190
- else if (r.status === 'noop')
195
+ continue;
196
+ }
197
+ const target = r.status === 'noop' ? r.deleted : r.plan.validPath;
198
+ if (seenTargets.has(target)) {
199
+ duplicates.add(index);
200
+ continue;
201
+ }
202
+ seenTargets.add(target);
203
+ if (r.status === 'noop')
191
204
  out[index] = { path: r.deleted, value: { deleted: true } };
192
205
  else {
193
206
  // Emptying a directory while its prompt is open must not discard the
@@ -202,6 +215,29 @@ async function handleDelete(args, ctx) {
202
215
  error: { code: ErrorCode.UNKNOWN, message: error.message },
203
216
  };
204
217
  }
218
+ // One entry inside another would race the other's recursive delete, and
219
+ // accepting the parent would remove a child whose own prompt was skipped.
220
+ // Refuse both sides before any prompt or mutation.
221
+ const nested = new Set();
222
+ for (const [i, a] of plans.entries()) {
223
+ for (const b of plans.slice(i + 1)) {
224
+ if (isPathInsideDirectory(a.plan.validPath, b.plan.validPath) ||
225
+ isPathInsideDirectory(b.plan.validPath, a.plan.validPath)) {
226
+ nested.add(a.index).add(b.index);
227
+ }
228
+ }
229
+ }
230
+ if (nested.size > 0) {
231
+ for (const { plan, index } of plans) {
232
+ if (!nested.has(index))
233
+ continue;
234
+ out[index] = {
235
+ path: plan.validPath,
236
+ error: Problem.invalidInput('Delete refused: this path contains, or is inside, another path in the batch. Delete the outer one alone.', { path: plan.validPath }),
237
+ };
238
+ }
239
+ plans = plans.filter(({ index }) => !nested.has(index));
240
+ }
205
241
  // Pending set: recursive + non-empty directories, sorted and de-duplicated.
206
242
  // `buildInputRequired` seals exactly this set into the requestState, and the
207
243
  // retried round recomputes it from the same args so a swapped retry (accept
@@ -262,12 +298,16 @@ async function handleDelete(args, ctx) {
262
298
  }
263
299
  // Emit in the caller's input order so `results[i]` lines up with `paths[i]`
264
300
  // the way read/stat guarantee.
265
- const results = paths.map((requested, i) => {
301
+ const results = paths.flatMap((requested, i) => {
302
+ if (duplicates.has(i))
303
+ return [];
266
304
  const entry = out[i];
267
- return (entry ?? {
268
- path: requested,
269
- error: { code: ErrorCode.UNKNOWN, message: 'Unknown delete failure' },
270
- });
305
+ return [
306
+ entry ?? {
307
+ path: requested,
308
+ error: { code: ErrorCode.UNKNOWN, message: 'Unknown delete failure' },
309
+ },
310
+ ];
271
311
  });
272
312
  return { results, summary: summarize(results) };
273
313
  }
@@ -283,7 +323,7 @@ export const DELETE = defineTool({
283
323
  ? basename(args.paths[0] ?? '')
284
324
  : `${String(args.paths.length)} paths`,
285
325
  }),
286
- accessPaths: (args) => [...args.paths],
326
+ mapPaths: (args, fn) => ({ ...args, paths: args.paths.map(fn) }),
287
327
  run: async (args, ctx) => {
288
328
  const structured = await handleDelete(args, ctx);
289
329
  // input_required is a return value, not a completed call: surface it
@@ -1 +1 @@
1
- {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/tools/delete.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InputRequiredResult } from '@modelcontextprotocol/server';\nimport { isInputRequiredResult } from '@modelcontextprotocol/server';\n\nimport { basename } 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 isNotFoundErrno,\n Problem,\n} from '../core/errors.ts';\nimport { joinRoster, pathLabel } from '../core/fmt.ts';\nimport type { FileType, GuardedFileSystem } from '../core/fs.ts';\nimport {\n confirmKey,\n describeRefusal,\n type PendingDeleteIdentity,\n pendingRoundTrip,\n type PendingState,\n readAcceptedChoice,\n} from '../core/input-required.ts';\nimport { resolveEntryType } from '../core/path-utils.ts';\nimport { defaultFalseBoolean, RequiredPath } from '../core/schema.ts';\nimport { PARALLEL_CONCURRENCY } from '../core/util.ts';\nimport { type BatchResult, isTotalFailure, type PerPathResult, summarize } from './batch.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\nconst DeleteInputSchema = z.strictObject({\n paths: z\n .array(RequiredPath)\n .min(1)\n .max(1000)\n .describe('Paths to delete (max 1000); accepts files, directories, or symlinks'),\n recursive: defaultFalseBoolean(\n 'Delete directory contents recursively (required for non-empty directories)',\n ),\n ignoreIfNotExists: defaultFalseBoolean(\n 'Silently succeed if a path does not exist instead of returning an error',\n ),\n});\n\ntype DeleteInput = z.infer<typeof DeleteInputSchema>;\ntype DeleteOutput = BatchResult<{ deleted: boolean }>;\ntype DeletePerPathResult = PerPathResult<{ deleted: boolean }>;\n\n// Internal types for error handling\ninterface DeleteFailure {\n path: string;\n error: Problem;\n}\n\nconst ERR_NOT_EMPTY = new Error('Directory not empty. Set recursive: true.');\n\nfunction toDeleteFailure(path: string, error: unknown): DeleteFailure {\n // A missing path reached here as the raw errno text (\"ENOENT: no such file or\n // directory, lstat 'c:\\...'\"), while `stat` reported the same condition as\n // \"Path not found\". One condition, one message — and the syscall name stays\n // off the wire.\n if (isNotFoundErrno(error)) {\n return {\n path,\n error: Problem.fromUnknown(\n new FsError(ErrorCode.NOT_FOUND, 'Path not found', path),\n ErrorCode.NOT_FOUND,\n path,\n ),\n };\n }\n if (\n isNodeError(error) &&\n (error.code === 'ENOTEMPTY' || error.code === 'EISDIR' || error.code === 'EEXIST')\n ) {\n return {\n path,\n error: Problem.fromUnknown(ERR_NOT_EMPTY, ErrorCode.INVALID_INPUT, path),\n };\n }\n return { path, error: Problem.fromUnknown(error, ErrorCode.UNKNOWN, path) };\n}\n\ntype LstatResult = Awaited<ReturnType<GuardedFileSystem['lstat']>>;\n\n/** A path's pre-checked plan: validated, statted, and flagged if it needs confirmation. */\ninterface DeletePlan {\n inputPath: string;\n validPath: string;\n itemType: FileType;\n firstStats: LstatResult;\n /** Recursive + non-empty directory: needs a round-trip confirmation. */\n pending: boolean;\n}\n\ntype PlanResult =\n | { status: 'fail'; failure: DeleteFailure }\n | { status: 'noop'; deleted: string }\n | { status: 'plan'; plan: DeletePlan };\n\n/**\n * Phase 1 (no mutation): validate, stat, and decide whether a path needs a\n * confirmation before anything is deleted. A pending path is a recursive\n * non-empty directory; everything else is ready to delete directly.\n */\nasync function planPath(\n inputPath: string,\n args: Pick<DeleteInput, 'recursive' | 'ignoreIfNotExists'>,\n fs: Pick<GuardedFileSystem, 'pathGuard' | 'lstat' | 'hasChildrenUnchecked'>,\n): Promise<PlanResult> {\n let validPath: string;\n try {\n validPath = await fs.pathGuard.validatePathForDelete(inputPath);\n } catch (error) {\n if (\n args.ignoreIfNotExists &&\n ((isFsError(error) && error.code === ErrorCode.NOT_FOUND) || isNotFoundErrno(error))\n ) {\n return { status: 'noop', deleted: inputPath };\n }\n return { status: 'fail', failure: toDeleteFailure(inputPath, error) };\n }\n\n if (fs.pathGuard.isAllowedRoot(validPath)) {\n return {\n status: 'fail',\n // Keyed by the REQUESTED path, like every other failure here: handleDelete\n // orders results by input path, and a resolved key would not be found for\n // a relative request.\n failure: {\n path: inputPath,\n error: Problem.accessDenied('Deleting a workspace root directory is not allowed', {\n path: validPath,\n }),\n },\n };\n }\n\n let firstStats: LstatResult;\n try {\n firstStats = await fs.lstat(validPath);\n } catch (error) {\n if (isNotFoundErrno(error) && args.ignoreIfNotExists) {\n return { status: 'noop', deleted: inputPath };\n }\n return { status: 'fail', failure: toDeleteFailure(inputPath, error) };\n }\n\n const itemType = resolveEntryType(firstStats.stats);\n let hasChildren = false;\n if (args.recursive && itemType === 'directory') {\n try {\n hasChildren = await fs.hasChildrenUnchecked(validPath);\n } catch (error) {\n return { status: 'fail', failure: toDeleteFailure(inputPath, error) };\n }\n }\n return {\n status: 'plan',\n plan: { inputPath, validPath, itemType, firstStats, pending: hasChildren },\n };\n}\n\ntype Identity = Pick<LstatResult['stats'], 'dev' | 'ino' | 'birthtimeMs'>;\n\n/** Same filesystem object. birthtimeMs joins dev/ino, which read 0 on some non-POSIX drivers. */\nconst sameIdentity = (a: Identity, b: Identity): boolean =>\n a.dev === b.dev && a.ino === b.ino && a.birthtimeMs === b.birthtimeMs;\n\n/**\n * Phase 2 (mutation): TOCTOU re-stat against the plan's first stat, then\n * delete. A type or identity change across the confirmation gap fails closed\n * rather than deleting a replacement object the user never confirmed.\n */\nasync function finalizeDeletion(\n plan: DeletePlan,\n args: Pick<DeleteInput, 'recursive' | 'ignoreIfNotExists'>,\n ctx: Pick<ToolCtx, 'fs' | 'log'>,\n): Promise<{ deleted: string } | { failure: DeleteFailure }> {\n let currentStats: LstatResult;\n try {\n currentStats = await ctx.fs.lstat(plan.validPath);\n } catch (error) {\n if (isNotFoundErrno(error) && args.ignoreIfNotExists) {\n return { deleted: plan.validPath };\n }\n return { failure: toDeleteFailure(plan.inputPath, error) };\n }\n\n const currentItemType = resolveEntryType(currentStats.stats);\n // Identity comparison, not just the coarse category: a swap during the\n // confirmation gap (delete original, create a same-named replacement) keeps\n // the type but changes dev/ino/birthtimeMs. birthtimeMs is the primary\n // cross-platform signal — dev/ino can read 0 on some non-POSIX drivers — so\n // combine all three rather than trusting dev/ino alone.\n const identityChanged = !sameIdentity(plan.firstStats.stats, currentStats.stats);\n if (plan.itemType !== 'other' && (currentItemType !== plan.itemType || identityChanged)) {\n return {\n failure: {\n path: plan.validPath,\n error: Problem.invalidInput(\n `Delete failed: item type changed from ${plan.itemType} to ${currentItemType} during confirmation.`,\n { path: plan.validPath },\n ),\n },\n };\n }\n\n try {\n if (currentStats.stats.isDirectory() && !args.recursive) await ctx.fs.rmdir(plan.validPath);\n else\n await ctx.fs.rm(plan.validPath, { recursive: args.recursive, force: args.ignoreIfNotExists });\n } catch (error) {\n return { failure: toDeleteFailure(plan.inputPath, error) };\n }\n\n ctx.log('info', `rm: ${plan.inputPath}`, 'delete');\n return { deleted: plan.validPath };\n}\n\n/**\n * Execute one planned path on the retry round. A pending path deletes only on\n * an accepted `confirm: true`; decline, cancel, or a missing key report\n * `CANCELLED` for that path (R3 proceed, R4/R5 cancelled). A non-pending path\n * deletes directly (R14: non-pending items proceed alongside accepted ones).\n */\nasync function executePlan(\n plan: DeletePlan,\n args: Pick<DeleteInput, 'recursive' | 'ignoreIfNotExists'>,\n ctx: Pick<ToolCtx, 'fs' | 'inputResponses' | 'droppedInputResponseKeys' | 'log'>,\n pendingSorted: readonly string[],\n confirmationState: PendingState | undefined,\n): Promise<{ deleted: string } | { failure: DeleteFailure } | { skipped: true; path: string }> {\n if (plan.pending) {\n const key = confirmKey(pendingSorted.indexOf(plan.validPath));\n const choice = readAcceptedChoice(ctx.inputResponses, key);\n if (choice === 'skip') {\n return { skipped: true as const, path: plan.validPath };\n }\n if (choice !== 'delete') {\n return {\n failure: {\n path: plan.validPath,\n error: Problem.cancelled(\n `Delete cancelled: confirmation was ${describeRefusal(ctx, key)}`,\n { path: plan.validPath },\n ),\n },\n };\n }\n const identity = confirmationState?.deleteIdentities?.find(\n (entry) => entry.path === plan.validPath,\n );\n if (identity?.itemType !== plan.itemType || !sameIdentity(identity, plan.firstStats.stats)) {\n return {\n failure: {\n path: plan.validPath,\n error: Problem.invalidInput(\n 'Delete failed: item identity changed or is missing from the confirmation.',\n { path: plan.validPath },\n ),\n },\n };\n }\n }\n return finalizeDeletion(plan, args, ctx);\n}\n\nasync function handleDelete(\n args: DeleteInput,\n ctx: ToolCtx,\n): Promise<DeleteOutput | InputRequiredResult> {\n // Duplicate paths collapse: results are keyed by path, so a repeated entry\n // would emit two rows for one deletion and inflate `summary.total`.\n const paths = [...new Set(args.paths)];\n\n // Phase 1 (no mutation): plan every path.\n const planned = await processInParallel(\n paths,\n (inputPath) => planPath(inputPath, args, ctx.fs),\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n const out = new Array<DeletePerPathResult | undefined>(paths.length).fill(undefined);\n const plans: { plan: DeletePlan; index: number }[] = [];\n const confirmationState = ctx.requestState?.<PendingState>();\n const previouslyPendingPaths = new Set(\n confirmationState?.op === 'delete' ? confirmationState.paths : [],\n );\n for (const { index, value: r } of planned.results) {\n if (r.status === 'fail') out[index] = { path: r.failure.path, error: r.failure.error };\n else if (r.status === 'noop') out[index] = { path: r.deleted, value: { deleted: true } };\n else {\n // Emptying a directory while its prompt is open must not discard the\n // answer. Keep that path pending so the verified retry still honors skip.\n r.plan.pending ||= previouslyPendingPaths.has(r.plan.validPath);\n plans.push({ plan: r.plan, index });\n }\n }\n for (const { index, error } of planned.errors) {\n out[index] = {\n path: paths[index] ?? '(unknown)',\n error: { code: ErrorCode.UNKNOWN, message: error.message },\n };\n }\n\n // Pending set: recursive + non-empty directories, sorted and de-duplicated.\n // `buildInputRequired` seals exactly this set into the requestState, and the\n // retried round recomputes it from the same args so a swapped retry (accept\n // for X, retry with Y) is rejected — the codec only proves the state was not\n // tampered, not that it matches the current request (R9).\n const pendingSorted = [\n ...new Set(plans.filter((p) => p.plan.pending).map((p) => p.plan.validPath)),\n ].sort();\n\n // With no actionable plans, preserve per-path NOT_FOUND / ignoreIfNotExists\n // results. Otherwise even an empty pending set must be checked before an\n // unrelated non-pending batch entry can mutate.\n if (pendingSorted.length > 0 || (confirmationState?.op === 'delete' && plans.length > 0)) {\n // Round 1 returns input_required (atomic — R14: nothing deleted yet, not\n // even the non-pending items in the same call); a retry whose verified\n // state does not bind this pending set throws (R9) via `pendingRoundTrip`.\n const round = await pendingRoundTrip(ctx, {\n op: 'delete',\n pending: pendingSorted,\n deleteIdentities: plans\n .filter(({ plan }) => plan.pending)\n .map(({ plan }): PendingDeleteIdentity => {\n const { dev, ino, birthtimeMs } = plan.firstStats.stats;\n return { path: plan.validPath, itemType: plan.itemType, dev, ino, birthtimeMs };\n }),\n buildInputs: (ps) =>\n ps.map((p, i) => ({\n key: confirmKey(i),\n message: `Permanently delete \"${p}\" and all its contents? This cannot be undone.`,\n choices: ['delete', 'skip'],\n })),\n });\n if (round !== undefined) return round;\n }\n\n // Phase 2 (mutation): execute deletions for every planned path.\n const executed = await processInParallel(\n plans,\n ({ plan }) => executePlan(plan, args, ctx, pendingSorted, confirmationState),\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n for (const { index, value: r } of executed.results) {\n const slot = plans[index]?.index;\n if (slot === undefined) continue;\n if ('skipped' in r) {\n out[slot] = { path: r.path, value: { deleted: false } };\n } else if ('failure' in r) {\n out[slot] = { path: r.failure.path, error: r.failure.error };\n } else {\n out[slot] = { path: r.deleted, value: { deleted: true } };\n }\n }\n for (const { index, error } of executed.errors) {\n const slot = plans[index]?.index;\n if (slot === undefined) continue;\n out[slot] = {\n path: paths[slot] ?? '(unknown)',\n error: { code: ErrorCode.UNKNOWN, message: error.message },\n };\n }\n\n // Emit in the caller's input order so `results[i]` lines up with `paths[i]`\n // the way read/stat guarantee.\n const results: DeletePerPathResult[] = paths.map((requested, i) => {\n const entry = out[i];\n return (\n entry ?? {\n path: requested,\n error: { code: ErrorCode.UNKNOWN, message: 'Unknown delete failure' },\n }\n );\n });\n\n return { results, summary: summarize(results) };\n}\n\nexport const DELETE = defineTool<typeof DeleteInputSchema, DeleteOutput>({\n name: 'delete',\n title: 'Delete File',\n description:\n 'Permanently delete files, directories, or symlinks, like rm or rm -r. Paths are exact; globs are not expanded.',\n input: DeleteInputSchema,\n readOnlyHint: false,\n progress: (args) => ({\n label: 'Delete',\n subject:\n args.paths.length === 1\n ? basename(args.paths[0] ?? '')\n : `${String(args.paths.length)} paths`,\n }),\n accessPaths: (args) => [...args.paths],\n run: async (args, ctx) => {\n const structured = await handleDelete(args, ctx);\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(structured)) return structured;\n // Name every path and its outcome. The old text said \"deleted 2 paths\"\n // without saying which two, so a partial failure was unreadable without\n // parsing the structured half.\n const { failed, total } = structured.summary;\n const isError = isTotalFailure(structured.summary);\n // A lone failure carries its reason in the text. \"delete: . FAILED (0/1 ok)\"\n // made the model re-read structuredContent to learn it was ACCESS_DENIED;\n // with one path there is no ambiguity about which message applies.\n if (total === 1 && failed === 1) {\n const only = structured.results[0];\n return {\n structured,\n text: `delete: ${only?.path ?? ''} FAILED — ${only && 'error' in only ? only.error.message : 'unknown error'}`,\n isError,\n };\n }\n const tokens = structured.results.map((r) => {\n const label = pathLabel(r.path);\n if ('error' in r) return `${label} FAILED`;\n return r.value.deleted ? label : `${label} SKIPPED`;\n });\n const ratio = failed > 0 ? ` (${String(total - failed)}/${String(total)} ok)` : '';\n return { structured, text: `delete: ${joinRoster(tokens)}${ratio}`, isError };\n },\n});\n"]}
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/tools/delete.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InputRequiredResult } from '@modelcontextprotocol/server';\nimport { isInputRequiredResult } from '@modelcontextprotocol/server';\n\nimport { basename } 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 isNotFoundErrno,\n Problem,\n} from '../core/errors.ts';\nimport { joinRoster, pathLabel } from '../core/fmt.ts';\nimport type { FileType, GuardedFileSystem } from '../core/fs.ts';\nimport {\n confirmKey,\n type PendingDeleteIdentity,\n pendingRoundTrip,\n type PendingState,\n readPendingVerdict,\n} from '../core/input-required.ts';\nimport { isPathInsideDirectory, resolveEntryType } from '../core/path-utils.ts';\nimport { defaultFalseBoolean, RequiredPath } from '../core/schema.ts';\nimport { PARALLEL_CONCURRENCY } from '../core/util.ts';\nimport { type BatchResult, isTotalFailure, type PerPathResult, summarize } from './batch.ts';\nimport type { ToolCtx } from './define.ts';\nimport { defineTool } from './define.ts';\n\nconst DeleteInputSchema = z.strictObject({\n paths: z\n .array(RequiredPath)\n .min(1)\n .max(1000)\n .describe('Paths to delete (max 1000); accepts files, directories, or symlinks'),\n recursive: defaultFalseBoolean(\n 'Delete directory contents recursively (required for non-empty directories)',\n ),\n ignoreIfNotExists: defaultFalseBoolean(\n 'Silently succeed if a path does not exist instead of returning an error',\n ),\n});\n\ntype DeleteInput = z.infer<typeof DeleteInputSchema>;\ntype DeleteOutput = BatchResult<{ deleted: boolean }>;\ntype DeletePerPathResult = PerPathResult<{ deleted: boolean }>;\n\n// Internal types for error handling\ninterface DeleteFailure {\n path: string;\n error: Problem;\n}\n\nconst ERR_NOT_EMPTY = new Error('Directory not empty. Set recursive: true.');\n\nfunction toDeleteFailure(path: string, error: unknown): DeleteFailure {\n // A missing path reached here as the raw errno text (\"ENOENT: no such file or\n // directory, lstat 'c:\\...'\"), while `stat` reported the same condition as\n // \"Path not found\". One condition, one message — and the syscall name stays\n // off the wire.\n if (isNotFoundErrno(error)) {\n return {\n path,\n error: Problem.fromUnknown(\n new FsError(ErrorCode.NOT_FOUND, 'Path not found', path),\n ErrorCode.NOT_FOUND,\n path,\n ),\n };\n }\n if (\n isNodeError(error) &&\n (error.code === 'ENOTEMPTY' || error.code === 'EISDIR' || error.code === 'EEXIST')\n ) {\n return {\n path,\n error: Problem.fromUnknown(ERR_NOT_EMPTY, ErrorCode.INVALID_INPUT, path),\n };\n }\n return { path, error: Problem.fromUnknown(error, ErrorCode.UNKNOWN, path) };\n}\n\ntype LstatResult = Awaited<ReturnType<GuardedFileSystem['lstat']>>;\n\n/** A path's pre-checked plan: validated, statted, and flagged if it needs confirmation. */\ninterface DeletePlan {\n inputPath: string;\n validPath: string;\n itemType: FileType;\n firstStats: LstatResult;\n /** Recursive + non-empty directory: needs a round-trip confirmation. */\n pending: boolean;\n}\n\ntype PlanResult =\n | { status: 'fail'; failure: DeleteFailure }\n | { status: 'noop'; deleted: string }\n | { status: 'plan'; plan: DeletePlan };\n\n/**\n * Phase 1 (no mutation): validate, stat, and decide whether a path needs a\n * confirmation before anything is deleted. A pending path is a recursive\n * non-empty directory; everything else is ready to delete directly.\n */\nasync function planPath(\n inputPath: string,\n args: Pick<DeleteInput, 'recursive' | 'ignoreIfNotExists'>,\n fs: Pick<GuardedFileSystem, 'pathGuard' | 'lstat' | 'hasChildrenUnchecked'>,\n): Promise<PlanResult> {\n let validPath: string;\n try {\n validPath = await fs.pathGuard.validatePathForDelete(inputPath);\n } catch (error) {\n if (\n args.ignoreIfNotExists &&\n ((isFsError(error) && error.code === ErrorCode.NOT_FOUND) || isNotFoundErrno(error))\n ) {\n return { status: 'noop', deleted: inputPath };\n }\n return { status: 'fail', failure: toDeleteFailure(inputPath, error) };\n }\n\n if (fs.pathGuard.isAllowedRoot(validPath)) {\n return {\n status: 'fail',\n // Keyed by the REQUESTED path, like every other failure here: handleDelete\n // orders results by input path, and a resolved key would not be found for\n // a relative request.\n failure: {\n path: inputPath,\n error: Problem.accessDenied('Deleting a workspace root directory is not allowed', {\n path: validPath,\n }),\n },\n };\n }\n\n let firstStats: LstatResult;\n try {\n firstStats = await fs.lstat(validPath);\n } catch (error) {\n if (isNotFoundErrno(error) && args.ignoreIfNotExists) {\n return { status: 'noop', deleted: inputPath };\n }\n return { status: 'fail', failure: toDeleteFailure(inputPath, error) };\n }\n\n const itemType = resolveEntryType(firstStats.stats);\n let hasChildren = false;\n if (args.recursive && itemType === 'directory') {\n try {\n hasChildren = await fs.hasChildrenUnchecked(validPath);\n } catch (error) {\n return { status: 'fail', failure: toDeleteFailure(inputPath, error) };\n }\n }\n return {\n status: 'plan',\n plan: { inputPath, validPath, itemType, firstStats, pending: hasChildren },\n };\n}\n\ntype Identity = Pick<LstatResult['stats'], 'dev' | 'ino' | 'birthtimeMs'>;\n\n/** Same filesystem object. birthtimeMs joins dev/ino, which read 0 on some non-POSIX drivers. */\nconst sameIdentity = (a: Identity, b: Identity): boolean =>\n a.dev === b.dev && a.ino === b.ino && a.birthtimeMs === b.birthtimeMs;\n\n/**\n * Phase 2 (mutation): TOCTOU re-stat against the plan's first stat, then\n * delete. A type or identity change across the confirmation gap fails closed\n * rather than deleting a replacement object the user never confirmed.\n */\nasync function finalizeDeletion(\n plan: DeletePlan,\n args: Pick<DeleteInput, 'recursive' | 'ignoreIfNotExists'>,\n ctx: Pick<ToolCtx, 'fs' | 'log'>,\n): Promise<{ deleted: string } | { failure: DeleteFailure }> {\n let currentStats: LstatResult;\n try {\n currentStats = await ctx.fs.lstat(plan.validPath);\n } catch (error) {\n if (isNotFoundErrno(error) && args.ignoreIfNotExists) {\n return { deleted: plan.validPath };\n }\n return { failure: toDeleteFailure(plan.inputPath, error) };\n }\n\n const currentItemType = resolveEntryType(currentStats.stats);\n // Identity comparison, not just the coarse category: a swap during the\n // confirmation gap (delete original, create a same-named replacement) keeps\n // the type but changes dev/ino/birthtimeMs. birthtimeMs is the primary\n // cross-platform signal — dev/ino can read 0 on some non-POSIX drivers — so\n // combine all three rather than trusting dev/ino alone.\n const identityChanged = !sameIdentity(plan.firstStats.stats, currentStats.stats);\n if (plan.itemType !== 'other' && (currentItemType !== plan.itemType || identityChanged)) {\n return {\n failure: {\n path: plan.validPath,\n error: Problem.invalidInput(\n `Delete failed: item type changed from ${plan.itemType} to ${currentItemType} during confirmation.`,\n { path: plan.validPath },\n ),\n },\n };\n }\n\n try {\n if (currentStats.stats.isDirectory() && !args.recursive) await ctx.fs.rmdir(plan.validPath);\n else\n await ctx.fs.rm(plan.validPath, { recursive: args.recursive, force: args.ignoreIfNotExists });\n } catch (error) {\n return { failure: toDeleteFailure(plan.inputPath, error) };\n }\n\n ctx.log('info', `rm: ${plan.inputPath}`, 'delete');\n return { deleted: plan.validPath };\n}\n\n/**\n * Execute one planned path on the retry round. A pending path deletes only on\n * an accepted `confirm: true`; decline, cancel, or a missing key report\n * `CANCELLED` for that path (R3 proceed, R4/R5 cancelled). A non-pending path\n * deletes directly (R14: non-pending items proceed alongside accepted ones).\n */\nasync function executePlan(\n plan: DeletePlan,\n args: Pick<DeleteInput, 'recursive' | 'ignoreIfNotExists'>,\n ctx: Pick<ToolCtx, 'fs' | 'inputResponses' | 'droppedInputResponseKeys' | 'log'>,\n pendingSorted: readonly string[],\n confirmationState: PendingState | undefined,\n): Promise<{ deleted: string } | { failure: DeleteFailure } | { skipped: true; path: string }> {\n if (plan.pending) {\n const verdict = readPendingVerdict(ctx, pendingSorted, plan.validPath, 'delete');\n if (verdict === 'skipped') {\n return { skipped: true as const, path: plan.validPath };\n }\n if (verdict !== 'accepted') {\n return {\n failure: {\n path: plan.validPath,\n error: Problem.cancelled(`Delete cancelled: confirmation was ${verdict.refused}`, {\n path: plan.validPath,\n }),\n },\n };\n }\n const identity = confirmationState?.deleteIdentities?.find(\n (entry) => entry.path === plan.validPath,\n );\n if (identity?.itemType !== plan.itemType || !sameIdentity(identity, plan.firstStats.stats)) {\n return {\n failure: {\n path: plan.validPath,\n error: Problem.invalidInput(\n 'Delete failed: item identity changed or is missing from the confirmation.',\n { path: plan.validPath },\n ),\n },\n };\n }\n }\n return finalizeDeletion(plan, args, ctx);\n}\n\nasync function handleDelete(\n args: DeleteInput,\n ctx: ToolCtx,\n): Promise<DeleteOutput | InputRequiredResult> {\n // Duplicate paths collapse: results are keyed by path, so a repeated entry\n // would emit two rows for one deletion and inflate `summary.total`. Exact\n // repeats go here; other spellings of one entry collapse after planning,\n // by validated path, so two on-disk names that fold alike both stay.\n const paths = [...new Set(args.paths)];\n\n // Phase 1 (no mutation): plan every path.\n const planned = await processInParallel(\n paths,\n (inputPath) => planPath(inputPath, args, ctx.fs),\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n const out = new Array<DeletePerPathResult | undefined>(paths.length).fill(undefined);\n let plans: { plan: DeletePlan; index: number }[] = [];\n const confirmationState = ctx.requestState?.<PendingState>();\n const previouslyPendingPaths = new Set(\n confirmationState?.op === 'delete' ? confirmationState.paths : [],\n );\n const seenTargets = new Set<string>();\n const duplicates = new Set<number>();\n for (const { index, value: r } of planned.results) {\n if (r.status === 'fail') {\n out[index] = { path: r.failure.path, error: r.failure.error };\n continue;\n }\n const target = r.status === 'noop' ? r.deleted : r.plan.validPath;\n if (seenTargets.has(target)) {\n duplicates.add(index);\n continue;\n }\n seenTargets.add(target);\n if (r.status === 'noop') out[index] = { path: r.deleted, value: { deleted: true } };\n else {\n // Emptying a directory while its prompt is open must not discard the\n // answer. Keep that path pending so the verified retry still honors skip.\n r.plan.pending ||= previouslyPendingPaths.has(r.plan.validPath);\n plans.push({ plan: r.plan, index });\n }\n }\n for (const { index, error } of planned.errors) {\n out[index] = {\n path: paths[index] ?? '(unknown)',\n error: { code: ErrorCode.UNKNOWN, message: error.message },\n };\n }\n\n // One entry inside another would race the other's recursive delete, and\n // accepting the parent would remove a child whose own prompt was skipped.\n // Refuse both sides before any prompt or mutation.\n const nested = new Set<number>();\n for (const [i, a] of plans.entries()) {\n for (const b of plans.slice(i + 1)) {\n if (\n isPathInsideDirectory(a.plan.validPath, b.plan.validPath) ||\n isPathInsideDirectory(b.plan.validPath, a.plan.validPath)\n ) {\n nested.add(a.index).add(b.index);\n }\n }\n }\n if (nested.size > 0) {\n for (const { plan, index } of plans) {\n if (!nested.has(index)) continue;\n out[index] = {\n path: plan.validPath,\n error: Problem.invalidInput(\n 'Delete refused: this path contains, or is inside, another path in the batch. Delete the outer one alone.',\n { path: plan.validPath },\n ),\n };\n }\n plans = plans.filter(({ index }) => !nested.has(index));\n }\n\n // Pending set: recursive + non-empty directories, sorted and de-duplicated.\n // `buildInputRequired` seals exactly this set into the requestState, and the\n // retried round recomputes it from the same args so a swapped retry (accept\n // for X, retry with Y) is rejected — the codec only proves the state was not\n // tampered, not that it matches the current request (R9).\n const pendingSorted = [\n ...new Set(plans.filter((p) => p.plan.pending).map((p) => p.plan.validPath)),\n ].sort();\n\n // With no actionable plans, preserve per-path NOT_FOUND / ignoreIfNotExists\n // results. Otherwise even an empty pending set must be checked before an\n // unrelated non-pending batch entry can mutate.\n if (pendingSorted.length > 0 || (confirmationState?.op === 'delete' && plans.length > 0)) {\n // Round 1 returns input_required (atomic — R14: nothing deleted yet, not\n // even the non-pending items in the same call); a retry whose verified\n // state does not bind this pending set throws (R9) via `pendingRoundTrip`.\n const round = await pendingRoundTrip(ctx, {\n op: 'delete',\n pending: pendingSorted,\n deleteIdentities: plans\n .filter(({ plan }) => plan.pending)\n .map(({ plan }): PendingDeleteIdentity => {\n const { dev, ino, birthtimeMs } = plan.firstStats.stats;\n return { path: plan.validPath, itemType: plan.itemType, dev, ino, birthtimeMs };\n }),\n buildInputs: (ps) =>\n ps.map((p, i) => ({\n key: confirmKey(i),\n message: `Permanently delete \"${p}\" and all its contents? This cannot be undone.`,\n choices: ['delete', 'skip'],\n })),\n });\n if (round !== undefined) return round;\n }\n\n // Phase 2 (mutation): execute deletions for every planned path.\n const executed = await processInParallel(\n plans,\n ({ plan }) => executePlan(plan, args, ctx, pendingSorted, confirmationState),\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n for (const { index, value: r } of executed.results) {\n const slot = plans[index]?.index;\n if (slot === undefined) continue;\n if ('skipped' in r) {\n out[slot] = { path: r.path, value: { deleted: false } };\n } else if ('failure' in r) {\n out[slot] = { path: r.failure.path, error: r.failure.error };\n } else {\n out[slot] = { path: r.deleted, value: { deleted: true } };\n }\n }\n for (const { index, error } of executed.errors) {\n const slot = plans[index]?.index;\n if (slot === undefined) continue;\n out[slot] = {\n path: paths[slot] ?? '(unknown)',\n error: { code: ErrorCode.UNKNOWN, message: error.message },\n };\n }\n\n // Emit in the caller's input order so `results[i]` lines up with `paths[i]`\n // the way read/stat guarantee.\n const results: DeletePerPathResult[] = paths.flatMap((requested, i) => {\n if (duplicates.has(i)) return [];\n const entry = out[i];\n return [\n entry ?? {\n path: requested,\n error: { code: ErrorCode.UNKNOWN, message: 'Unknown delete failure' },\n },\n ];\n });\n\n return { results, summary: summarize(results) };\n}\n\nexport const DELETE = defineTool<typeof DeleteInputSchema, DeleteOutput>({\n name: 'delete',\n title: 'Delete File',\n description:\n 'Permanently delete files, directories, or symlinks, like rm or rm -r. Paths are exact; globs are not expanded.',\n input: DeleteInputSchema,\n readOnlyHint: false,\n progress: (args) => ({\n label: 'Delete',\n subject:\n args.paths.length === 1\n ? basename(args.paths[0] ?? '')\n : `${String(args.paths.length)} paths`,\n }),\n mapPaths: (args, fn) => ({ ...args, paths: args.paths.map(fn) }),\n run: async (args, ctx) => {\n const structured = await handleDelete(args, ctx);\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(structured)) return structured;\n // Name every path and its outcome. The old text said \"deleted 2 paths\"\n // without saying which two, so a partial failure was unreadable without\n // parsing the structured half.\n const { failed, total } = structured.summary;\n const isError = isTotalFailure(structured.summary);\n // A lone failure carries its reason in the text. \"delete: . FAILED (0/1 ok)\"\n // made the model re-read structuredContent to learn it was ACCESS_DENIED;\n // with one path there is no ambiguity about which message applies.\n if (total === 1 && failed === 1) {\n const only = structured.results[0];\n return {\n structured,\n text: `delete: ${only?.path ?? ''} FAILED — ${only && 'error' in only ? only.error.message : 'unknown error'}`,\n isError,\n };\n }\n const tokens = structured.results.map((r) => {\n const label = pathLabel(r.path);\n if ('error' in r) return `${label} FAILED`;\n return r.value.deleted ? label : `${label} SKIPPED`;\n });\n const ratio = failed > 0 ? ` (${String(total - failed)}/${String(total)} ok)` : '';\n return { structured, text: `delete: ${joinRoster(tokens)}${ratio}`, isError };\n },\n});\n"]}
@@ -22,7 +22,7 @@ export const DIFF = defineTool({
22
22
  label: 'Diff',
23
23
  subject: basename(args.a),
24
24
  }),
25
- accessPaths: (args) => [args.a, args.b],
25
+ mapPaths: (args, fn) => ({ ...args, a: fn(args.a), b: fn(args.b) }),
26
26
  run: async (args, ctx) => {
27
27
  const [{ validPath: validA, content: contentA }, { validPath: validB, content: contentB }] = await Promise.all([
28
28
  ctx.fs.readEditableText(args.a, { signal: ctx.signal, tool: 'diff' }),
@@ -1 +1 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/tools/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,eAAe,GAAG,CAAC,CAAC,YAAY,CAAC;IACrC,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,uBAAuB,CAAC;IACjD,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAClD,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;SACzB,OAAO,CAAC,CAAC,CAAC;SACV,QAAQ,CAAC,8DAA8D,CAAC;CAC5E,CAAC,CAAC;AASH,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAqC;IACjE,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IACb,WAAW,EAAE,6EAA6E;IAC1F,KAAK,EAAE,eAAe;IACtB,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnB,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;KAC1B,CAAC;IACF,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACvC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,GACxF,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACrE,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;SACtE,CAAC,CAAC;QAEL,wEAAwE;QACxE,MAAM,QAAQ,GAAG,mBAAmB,CAClC,QAAQ,CAAC,MAAM,CAAC,EAChB,QAAQ,CAAC,MAAM,CAAC,EAChB,QAAQ,EACR,QAAQ,EACR,GAAG,EACH,GAAG,EACH,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CACpD,CAAC;QACF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,OAAO,CACf,SAAS,CAAC,SAAS,EACnB,wEAAwE,MAAM,CAAC,eAAe,CAAC,8DAA8D,EAC7J,IAAI,CAAC,CAAC,CACP,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAElE,wEAAwE;QACxE,8EAA8E;QAC9E,OAAO;YACL,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE;YAC9D,IAAI,EAAE,QAAQ;SACf,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\nimport { createTwoFilesPatch } from 'diff';\n\nimport { DIFF_TIMEOUT_MS, diffStatsFromPatch } from '../core/diff.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { PositiveInt, RequiredPath } from '../core/schema.ts';\nimport { defineTool } from './define.ts';\n\nconst DiffInputSchema = z.strictObject({\n a: RequiredPath.describe('First file to compare'),\n b: RequiredPath.describe('Second file to compare'),\n context: PositiveInt.max(50)\n .default(3)\n .describe('Number of context lines surrounding each change (default: 3)'),\n});\n\ninterface DiffOutput {\n a: string;\n b: string;\n linesAdded: number;\n linesRemoved: number;\n}\n\nexport const DIFF = defineTool<typeof DiffInputSchema, DiffOutput>({\n name: 'diff',\n title: 'Diff',\n description: 'Compare two text files and return a unified diff from a to b, like diff -u.',\n input: DiffInputSchema,\n readOnlyHint: true,\n progress: (args) => ({\n label: 'Diff',\n subject: basename(args.a),\n }),\n accessPaths: (args) => [args.a, args.b],\n run: async (args, ctx) => {\n const [{ validPath: validA, content: contentA }, { validPath: validB, content: contentB }] =\n await Promise.all([\n ctx.fs.readEditableText(args.a, { signal: ctx.signal, tool: 'diff' }),\n ctx.fs.readEditableText(args.b, { signal: ctx.signal, tool: 'diff' }),\n ]);\n\n // Synchronous Myers diff; `timeout` is the only thing that can stop it.\n const diffText = createTwoFilesPatch(\n basename(validA),\n basename(validB),\n contentA,\n contentB,\n 'a',\n 'b',\n { context: args.context, timeout: DIFF_TIMEOUT_MS },\n );\n if (diffText === undefined) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `Diff not computed: the files differ in too many lines to diff within ${String(DIFF_TIMEOUT_MS)} ms. Compare smaller sections with read + startLine/endLine.`,\n args.a,\n );\n }\n\n const { linesAdded, linesRemoved } = diffStatsFromPatch(diffText);\n\n // The text block is the one copy of the diff; a model reads that, and a\n // structured duplicate or a store entry would only ship the same bytes again.\n return {\n structured: { a: validA, b: validB, linesAdded, linesRemoved },\n text: diffText,\n };\n },\n});\n"]}
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/tools/diff.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename } from 'node:path';\n\nimport * as z from 'zod/v4';\nimport { createTwoFilesPatch } from 'diff';\n\nimport { DIFF_TIMEOUT_MS, diffStatsFromPatch } from '../core/diff.ts';\nimport { ErrorCode, FsError } from '../core/errors.ts';\nimport { PositiveInt, RequiredPath } from '../core/schema.ts';\nimport { defineTool } from './define.ts';\n\nconst DiffInputSchema = z.strictObject({\n a: RequiredPath.describe('First file to compare'),\n b: RequiredPath.describe('Second file to compare'),\n context: PositiveInt.max(50)\n .default(3)\n .describe('Number of context lines surrounding each change (default: 3)'),\n});\n\ninterface DiffOutput {\n a: string;\n b: string;\n linesAdded: number;\n linesRemoved: number;\n}\n\nexport const DIFF = defineTool<typeof DiffInputSchema, DiffOutput>({\n name: 'diff',\n title: 'Diff',\n description: 'Compare two text files and return a unified diff from a to b, like diff -u.',\n input: DiffInputSchema,\n readOnlyHint: true,\n progress: (args) => ({\n label: 'Diff',\n subject: basename(args.a),\n }),\n mapPaths: (args, fn) => ({ ...args, a: fn(args.a), b: fn(args.b) }),\n run: async (args, ctx) => {\n const [{ validPath: validA, content: contentA }, { validPath: validB, content: contentB }] =\n await Promise.all([\n ctx.fs.readEditableText(args.a, { signal: ctx.signal, tool: 'diff' }),\n ctx.fs.readEditableText(args.b, { signal: ctx.signal, tool: 'diff' }),\n ]);\n\n // Synchronous Myers diff; `timeout` is the only thing that can stop it.\n const diffText = createTwoFilesPatch(\n basename(validA),\n basename(validB),\n contentA,\n contentB,\n 'a',\n 'b',\n { context: args.context, timeout: DIFF_TIMEOUT_MS },\n );\n if (diffText === undefined) {\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `Diff not computed: the files differ in too many lines to diff within ${String(DIFF_TIMEOUT_MS)} ms. Compare smaller sections with read + startLine/endLine.`,\n args.a,\n );\n }\n\n const { linesAdded, linesRemoved } = diffStatsFromPatch(diffText);\n\n // The text block is the one copy of the diff; a model reads that, and a\n // structured duplicate or a store entry would only ship the same bytes again.\n return {\n structured: { a: validA, b: validB, linesAdded, linesRemoved },\n text: diffText,\n };\n },\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAucA,eAAO,MAAM,IAAI,mCAwDf,CAAC"}
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAwcA,eAAO,MAAM,IAAI,mCAwDf,CAAC"}
@@ -5,7 +5,7 @@ import { ErrorCode, FsError } from "../core/errors.js";
5
5
  import { buildWrittenFileMeta } from "../core/file-uri.js";
6
6
  import { joinRoster, truncateProgressPattern } from "../core/fmt.js";
7
7
  import { isSamePath } from "../core/path-utils.js";
8
- import { defaultFalseBoolean, nonBlankString, RequiredPath, singleOrBatchAccessPaths, } from "../core/schema.js";
8
+ import { defaultFalseBoolean, mapSingleOrBatchPaths, nonBlankString, RequiredPath, } from "../core/schema.js";
9
9
  import { compileRegex, execMatches, freeRegex } from "../core/search.js";
10
10
  import { escapeRegExp } from "../core/util.js";
11
11
  import { isTotalFailure, runOverPaths } from "./batch.js";
@@ -33,7 +33,7 @@ const EditFileInputSchema = z
33
33
  .min(1)
34
34
  .max(MAX_EDITS_PER_FILE)
35
35
  .optional()
36
- .describe('Replacements applied to path; not allowed when using files'),
36
+ .describe('Replacements applied to path (required with path); not allowed with files'),
37
37
  files: z
38
38
  .array(z.strictObject({
39
39
  path: RequiredPath,
@@ -92,12 +92,7 @@ const EditFileInputSchema = z
92
92
  });
93
93
  }
94
94
  }
95
- })
96
- // Mirror the superRefine on the wire: exactly one input mode, and single-file
97
- // mode carries its own `edits`. Without `edits` in the first branch, `{ path }`
98
- // alone validated against the published schema and was then rejected at
99
- // runtime — the model had no way to see that coming.
100
- .meta({ oneOf: [{ required: ['path', 'edits'] }, { required: ['files'] }] });
95
+ });
101
96
  const MAX_REPORTED_MATCH_LINES = 5;
102
97
  /**
103
98
  * Pattern for a whitespace run of oldText that contains a newline. Between two
@@ -295,14 +290,21 @@ async function editOnce(filePath, edits, options, ctx) {
295
290
  // writer it may reflect that writer's mtime while `size`/content below come from
296
291
  // this edit's atomic write. The file content itself is always consistent. A dry
297
292
  // run wrote nothing, so it reports the time of the preview.
298
- const modified = options.dryRun
299
- ? new Date().toISOString()
300
- : (await ctx.fs.stat(filePath, { signal: ctx.signal })).stats.mtime.toISOString();
293
+ let modified = new Date().toISOString();
294
+ if (!options.dryRun) {
295
+ try {
296
+ modified = (await ctx.fs.stat(validPath)).stats.mtime.toISOString();
297
+ }
298
+ catch {
299
+ /* post-commit metadata only */
300
+ }
301
+ }
301
302
  const meta = buildWrittenFileMeta({
302
303
  validPath,
303
304
  content: editResult.content,
304
305
  dryRun: options.dryRun,
305
306
  lastModified: modified,
307
+ transport: ctx.transport,
306
308
  });
307
309
  const { resourceLink, ...fileMeta } = meta;
308
310
  return {
@@ -380,7 +382,7 @@ export const EDIT = defineTool({
380
382
  }
381
383
  return { label: `Edit${dryLabel}`, subject };
382
384
  },
383
- accessPaths: singleOrBatchAccessPaths,
385
+ mapPaths: mapSingleOrBatchPaths,
384
386
  run: async (args, ctx) => {
385
387
  const items = args.path !== undefined ? [{ path: args.path, edits: args.edits ?? [] }] : (args.files ?? []);
386
388
  const batch = await runOverPaths(items, ctx, ErrorCode.UNKNOWN, ({ path, edits }) =>