@j0hanz/filesystem-mcp 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -8
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +14 -41
- package/dist/cli-help.js.map +1 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -41
- package/dist/cli.js.map +1 -1
- package/dist/core/concurrency.d.ts +5 -17
- package/dist/core/concurrency.d.ts.map +1 -1
- package/dist/core/concurrency.js +11 -34
- package/dist/core/concurrency.js.map +1 -1
- package/dist/core/cursor.d.ts +1 -12
- package/dist/core/cursor.d.ts.map +1 -1
- package/dist/core/cursor.js +2 -12
- package/dist/core/cursor.js.map +1 -1
- package/dist/core/errors.d.ts +0 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +6 -17
- package/dist/core/errors.js.map +1 -1
- package/dist/core/file-uri.d.ts +2 -2
- package/dist/core/file-uri.js +3 -3
- package/dist/core/file-uri.js.map +1 -1
- package/dist/core/fmt.d.ts +0 -10
- package/dist/core/fmt.d.ts.map +1 -1
- package/dist/core/fmt.js +1 -18
- package/dist/core/fmt.js.map +1 -1
- package/dist/core/fs.d.ts +3 -3
- package/dist/core/fs.d.ts.map +1 -1
- package/dist/core/fs.js +9 -10
- package/dist/core/fs.js.map +1 -1
- package/dist/core/glob.d.ts +1 -2
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/glob.js +9 -20
- package/dist/core/glob.js.map +1 -1
- package/dist/core/input-required.d.ts +15 -16
- package/dist/core/input-required.d.ts.map +1 -1
- package/dist/core/input-required.js +34 -34
- package/dist/core/input-required.js.map +1 -1
- package/dist/core/observability.js +2 -2
- package/dist/core/observability.js.map +1 -1
- package/dist/core/path-completer.d.ts +6 -9
- package/dist/core/path-completer.d.ts.map +1 -1
- package/dist/core/path-completer.js +28 -55
- package/dist/core/path-completer.js.map +1 -1
- package/dist/core/path-discovery.d.ts.map +1 -1
- package/dist/core/path-discovery.js +3 -4
- package/dist/core/path-discovery.js.map +1 -1
- package/dist/core/path-utils.d.ts +28 -0
- package/dist/core/path-utils.d.ts.map +1 -1
- package/dist/core/path-utils.js +57 -2
- package/dist/core/path-utils.js.map +1 -1
- package/dist/core/path.d.ts +3 -8
- package/dist/core/path.d.ts.map +1 -1
- package/dist/core/path.js +8 -9
- package/dist/core/path.js.map +1 -1
- package/dist/core/read.d.ts +3 -22
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +46 -96
- package/dist/core/read.js.map +1 -1
- package/dist/core/schema.d.ts +8 -9
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +11 -14
- package/dist/core/schema.js.map +1 -1
- package/dist/core/search.d.ts +1 -1
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +3 -4
- package/dist/core/search.js.map +1 -1
- package/dist/core/sensitive.d.ts.map +1 -1
- package/dist/core/sensitive.js +4 -5
- package/dist/core/sensitive.js.map +1 -1
- package/dist/core/store.d.ts +41 -16
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +147 -82
- package/dist/core/store.js.map +1 -1
- package/dist/core/util.d.ts +3 -2
- package/dist/core/util.d.ts.map +1 -1
- package/dist/core/util.js +5 -6
- package/dist/core/util.js.map +1 -1
- package/dist/core/watcher-registry.d.ts +1 -1
- package/dist/core/watcher-registry.js +4 -4
- package/dist/core/watcher-registry.js.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/instructions.js +2 -2
- package/dist/instructions.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +11 -19
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +39 -59
- package/dist/resources.js.map +1 -1
- package/dist/server.d.ts +4 -5
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -9
- package/dist/server.js.map +1 -1
- package/dist/tools/batch.d.ts +2 -2
- package/dist/tools/batch.js +3 -3
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/create.d.ts +1 -1
- package/dist/tools/create.js +17 -15
- package/dist/tools/create.js.map +1 -1
- package/dist/tools/define.d.ts +10 -9
- package/dist/tools/define.d.ts.map +1 -1
- package/dist/tools/define.js +26 -92
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/delete.d.ts +1 -1
- package/dist/tools/delete.js +16 -13
- package/dist/tools/delete.js.map +1 -1
- package/dist/tools/diff.d.ts +1 -1
- package/dist/tools/diff.d.ts.map +1 -1
- package/dist/tools/diff.js +7 -37
- package/dist/tools/diff.js.map +1 -1
- package/dist/tools/edit.d.ts +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +27 -26
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/find-files.d.ts +1 -1
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +18 -37
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/index.d.ts +9 -10
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +13 -13
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-roots.d.ts +1 -1
- package/dist/tools/list-roots.js +3 -3
- package/dist/tools/list-roots.js.map +1 -1
- package/dist/tools/list.d.ts +1 -1
- package/dist/tools/list.d.ts.map +1 -1
- package/dist/tools/list.js +23 -29
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/move.d.ts +1 -1
- package/dist/tools/move.js +18 -13
- package/dist/tools/move.js.map +1 -1
- package/dist/tools/patch.d.ts +1 -1
- package/dist/tools/patch.js +4 -4
- package/dist/tools/patch.js.map +1 -1
- package/dist/tools/progress.d.ts +17 -28
- package/dist/tools/progress.d.ts.map +1 -1
- package/dist/tools/progress.js +42 -94
- package/dist/tools/progress.js.map +1 -1
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +10 -12
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/replace-text.d.ts +1 -1
- package/dist/tools/replace-text.d.ts.map +1 -1
- package/dist/tools/replace-text.js +32 -49
- package/dist/tools/replace-text.js.map +1 -1
- package/dist/tools/search-text.d.ts +1 -1
- package/dist/tools/search-text.d.ts.map +1 -1
- package/dist/tools/search-text.js +19 -45
- package/dist/tools/search-text.js.map +1 -1
- package/dist/tools/stat.d.ts +1 -1
- package/dist/tools/stat.d.ts.map +1 -1
- package/dist/tools/stat.js +9 -29
- package/dist/tools/stat.js.map +1 -1
- package/dist/transport/http-policy.js +4 -4
- package/dist/transport/http-policy.js.map +1 -1
- package/dist/transport/http.d.ts +2 -2
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +16 -17
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/shared.d.ts +2 -2
- package/dist/transport/shared.js +2 -2
- package/dist/transport/shared.js.map +1 -1
- package/dist/transport/stdio.d.ts +3 -3
- package/dist/transport/stdio.js +6 -6
- package/dist/transport/stdio.js.map +1 -1
- package/dist/transport.d.ts +2 -2
- package/dist/transport.js +2 -2
- package/dist/transport.js.map +1 -1
- package/package.json +3 -7
- package/dist/core/page-store.d.ts +0 -42
- package/dist/core/page-store.d.ts.map +0 -1
- package/dist/core/page-store.js +0 -75
- package/dist/core/page-store.js.map +0 -1
- package/dist/core/primitives.d.ts +0 -34
- package/dist/core/primitives.d.ts.map +0 -1
- package/dist/core/primitives.js +0 -63
- package/dist/core/primitives.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/core/concurrency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAIjD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAE5F;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAEtF;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IAC5B,OAAO,CAAiB;IAExB,aAAa;QACX,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC;IAC9B,CAAC;IAED,WAAW;QACT,IAAI,IAAI,CAAC,OAAO,KAAK,YAAY;YAAE,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;IAC/D,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC;IAC7B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC;IACpC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF;AAOD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAmB,EACnB,SAAkC,EAClC,cAAsB,oBAAoB,EAC1C,MAAoB;IAEpB,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;IAC/B,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAExD,MAAM,OAAO,GAAkC,EAAE,CAAC;IAClD,MAAM,MAAM,GAAsC,EAAE,CAAC;IAErD,MAAM,EAAE,cAAc,EAAE,CAAC;IAEzB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,sEAAsE;IACtE,mEAAmE;IACnE,wEAAwE;IACxE,8DAA8D;IAC9D,IAAI,SAAS,GAAG,KAAgB,CAAC;IAEjC,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;QACrC,OAAO,SAAS,GAAG,SAAS,EAAE,CAAC;YAC7B,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBACpB,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM,CAAC,cAAc,EAAE,CAAC;YAC1B,CAAC;YAED,MAAM,KAAK,GAAG,SAAS,CAAC;YACxB,SAAS,IAAI,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,gEAAgE;gBAChE,gEAAgE;gBAChE,6DAA6D;gBAC7D,iDAAiD;gBACjD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;gBACpC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK;oBACL,KAAK,EAAE,qBAAqB,CAAC,KAAK,CAAC;iBACpC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACrD,MAAM,OAAO,GAAoB,IAAI,KAAK,CAAgB,WAAW,CAAC,CAAC;IACvE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,WAAW,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAClC,uEAAuE;IACvE,sEAAsE;IACtE,uEAAuE;IACvE,iEAAiE;IACjE,uEAAuE;IACvE,qEAAqE;IACrE,2BAA2B;IAC3B,IAAI,SAAS;QAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAExC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACxD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAqE,EACrE,OAQC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IACzC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC5F,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAC;IACxC,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,MAAM,WAAW,GAAG,KAAK,IAAmB,EAAE;QAC5C,IAAI,OAAO,CAAC,IAAI,GAAG,WAAW;YAAE,OAAO;QACvC,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC,CAAC;IAEF,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAClC,2EAA2E;QAC3E,2EAA2E;QAC3E,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM;QACR,CAAC;QACD,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,IAAI,UAAU,EAAE,CAAC;YACzD,OAAO,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM;QACR,CAAC;QACD,2EAA2E;QAC3E,kEAAkE;QAClE,IAAI,UAAU,EAAE,EAAE,EAAE,CAAC;YACnB,OAAO,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM;QACR,CAAC;QACD,MAAM,WAAW,EAAE,CAAC;QACpB,0EAA0E;QAC1E,4EAA4E;QAC5E,8EAA8E;QAC9E,IAAI,UAAU,EAAE,EAAE,EAAE,CAAC;YACnB,OAAO,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM;QACR,CAAC;QACD,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,CAAC;QAEb,8EAA8E;QAC9E,6EAA6E;QAC7E,oEAAoE;QACpE,2EAA2E;QAC3E,2DAA2D;QAC3D,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YAC1D,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE;YACxB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,OAAmB,EAAE,MAAoB;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,CAAC,cAAc,EAAE,CAAC;IACxB,IAAI,OAAiC,CAAC;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC;QAClB,OAAO;QACP,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YAC/B,OAAO,GAAG,GAAG,EAAE;gBACb,MAAM,CAAC,MAAM,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAC1F,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC,CAAC;KACH,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACd,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import * as z from 'zod/v4';\n\nimport { normalizeUnknownError } from './errors.js';\nimport { PARALLEL_CONCURRENCY } from './util.js';\n\nexport type StoppedReason = 'maxResults' | 'maxFiles' | 'timeout';\n\nexport const StoppedReasonSchema = z.enum(['maxResults', 'maxFiles', 'timeout']).optional();\n\n/**\n * The subset `search_text` and `find_files` can actually emit. Their scans call\n * only `hitMaxResults` and `hitAbort` (search.ts), never `hitMaxFiles`, so the\n * three-value enum published a value no response can carry and disagreed with\n * both tools' own descriptions.\n */\nexport const SearchStoppedReasonSchema = z.enum(['maxResults', 'timeout']).optional();\n\n/**\n * Accumulates why an enumeration stopped early. maxResults wins over maxFiles\n * wins over timeout (the most specific cap is the definite cause even if the\n * abort also fired on the same iteration). Call `resolve()` once at the end.\n */\nexport class StopReasonTracker {\n #reason?: StoppedReason;\n\n hitMaxResults(): void {\n this.#reason = 'maxResults';\n }\n\n hitMaxFiles(): void {\n if (this.#reason !== 'maxResults') this.#reason = 'maxFiles';\n }\n\n hitAbort(): void {\n this.#reason ??= 'timeout';\n }\n\n get truncated(): boolean {\n return this.#reason !== undefined;\n }\n\n resolve(): StoppedReason | undefined {\n return this.#reason;\n }\n}\n\ninterface ParallelResult<R> {\n results: { index: number; value: R }[];\n errors: { index: number; error: Error }[];\n}\n\nexport async function processInParallel<T, R>(\n items: readonly T[],\n processor: (item: T) => Promise<R>,\n concurrency: number = PARALLEL_CONCURRENCY,\n signal?: AbortSignal,\n): Promise<ParallelResult<R>> {\n const itemCount = items.length;\n if (itemCount === 0) return { results: [], errors: [] };\n\n const results: { index: number; value: R }[] = [];\n const errors: { index: number; error: Error }[] = [];\n\n signal?.throwIfAborted();\n\n let nextIndex = 0;\n // Set when a worker saw the signal fire before an item ran — the only\n // shape in which the batch is genuinely incomplete. The annotation\n // matters: without it control-flow analysis keeps the `false` narrowing\n // from the initializer and cannot see the closure assignment.\n let truncated = false as boolean;\n\n const next = async (): Promise<void> => {\n while (nextIndex < itemCount) {\n if (signal?.aborted) {\n truncated = true;\n signal.throwIfAborted();\n }\n\n const index = nextIndex;\n nextIndex += 1;\n const item = items[index];\n if (item === undefined) {\n continue;\n }\n\n try {\n // No abort check after the processor: once an item has run, its\n // result is real work that a write caller may have committed to\n // disk. Discarding it here would report a finished append as\n // failed, and a client retry would append twice.\n const value = await processor(item);\n results.push({ index, value });\n } catch (error) {\n errors.push({\n index,\n error: normalizeUnknownError(error),\n });\n }\n }\n };\n\n const workerCount = Math.min(itemCount, concurrency);\n const workers: Promise<void>[] = new Array<Promise<void>>(workerCount);\n for (let index = 0; index < workerCount; index += 1) {\n workers[index] = next();\n }\n\n await Promise.allSettled(workers);\n // A deadline (AbortSignal.timeout) hit during the run surfaces here as\n // signal.reason — a TimeoutError — rather than a fresh AbortError, so\n // callers see TIMEOUT, not CANCELLED. Only a run that actually skipped\n // items reports the abort: a deadline firing after the last item\n // finished leaves a complete batch, and returning it beats telling the\n // caller that committed writes failed. The per-item throws above are\n // swallowed by allSettled.\n if (truncated) signal?.throwIfAborted();\n\n results.sort((left, right) => left.index - right.index);\n return { results, errors };\n}\n\n/**\n * The streaming sibling of {@link processInParallel}: bounded-concurrency\n * dispatch over an AsyncIterable that may be far larger than the caller wants\n * to walk, so it stops early and reports why.\n *\n * `maxEntries` caps how many entries are dispatched (maxFiles); `shouldStop`\n * lets the caller stop on its own accumulating result count (maxResults). Both\n * are checked before dispatch, so the returned tracker names exactly one\n * reason — the loop breaks on the first that fires.\n */\nexport async function processEntriesConcurrently(\n entries: AsyncIterable<{ path: string }> | Iterable<{ path: string }>,\n options: {\n signal: AbortSignal | undefined;\n concurrency: number;\n maxEntries?: number;\n shouldStop?: () => boolean;\n onEntry: () => void;\n onError?: (entryPath: string, err: unknown) => void;\n runEntry: (entryPath: string) => Promise<void>;\n },\n): Promise<StopReasonTracker> {\n const pending = new Set<Promise<void>>();\n const { signal, concurrency, maxEntries, shouldStop, onEntry, onError, runEntry } = options;\n const tracker = new StopReasonTracker();\n let dispatched = 0;\n\n const waitForSlot = async (): Promise<void> => {\n if (pending.size < concurrency) return;\n await Promise.race(pending);\n };\n\n for await (const entry of entries) {\n // The signal is cancellation OR the caller's timeout: stop dispatching and\n // let the caller report the run as incomplete rather than as a full sweep.\n if (signal?.aborted) {\n tracker.hitAbort();\n break;\n }\n if (maxEntries !== undefined && dispatched >= maxEntries) {\n tracker.hitMaxFiles();\n break;\n }\n // Check the result cap before waiting for a slot so an in-flight task that\n // already crossed the cap stops dispatch without an extra wait...\n if (shouldStop?.()) {\n tracker.hitMaxResults();\n break;\n }\n await waitForSlot();\n // ...and again after the slot frees, since tasks settle concurrently. The\n // cap can still be exceeded by at most `concurrency - 1` already-dispatched\n // tasks that are mid-flight; that overrun is inherent to concurrent dispatch.\n if (shouldStop?.()) {\n tracker.hitMaxResults();\n break;\n }\n onEntry();\n dispatched++;\n\n // Track a non-rejecting wrapper so a rejected task can never propagate out of\n // Promise.race(pending) in waitForSlot() and abort the loop before the final\n // drain below (which would silently abandon other in-flight tasks).\n // runEntry is expected to catch its own errors; if it unexpectedly throws,\n // record it as a failure rather than silently dropping it.\n const tracked = runEntry(entry.path).catch((err: unknown) => {\n onError?.(entry.path, err);\n });\n pending.add(tracked);\n void tracked.finally(() => {\n pending.delete(tracked);\n });\n }\n\n if (pending.size > 0) {\n await Promise.allSettled([...pending]);\n }\n\n return tracker;\n}\n\nexport function withAbort<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) {\n return promise;\n }\n signal.throwIfAborted();\n let onAbort: (() => void) | undefined;\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n onAbort = () => {\n reject(signal.reason instanceof Error ? signal.reason : new Error('Operation aborted'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n ]).finally(() => {\n if (onAbort) {\n signal.removeEventListener('abort', onAbort);\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/core/concurrency.ts"],"names":[],"mappings":"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","sourcesContent":["import * as z from 'zod/v4';\n\nimport { normalizeUnknownError } from './errors.ts';\nimport { PARALLEL_CONCURRENCY } from './util.ts';\n\nexport type StoppedReason = 'maxResults' | 'maxFiles' | 'timeout';\n\nexport const StoppedReasonSchema = z.enum(['maxResults', 'maxFiles', 'timeout']).optional();\n\n/**\n * The subset `search_text` and `find_files` can actually emit. Their scans call\n * only `hitMaxResults` and `hitAbort` (search.ts), never `hitMaxFiles`, so the\n * three-value enum published a value no response can carry and disagreed with\n * both tools' own descriptions.\n */\nexport const SearchStoppedReasonSchema = z.enum(['maxResults', 'timeout']).optional();\n\ninterface ParallelResult<R> {\n results: { index: number; value: R }[];\n errors: { index: number; error: Error }[];\n}\n\nexport async function processInParallel<T, R>(\n items: readonly T[],\n processor: (item: T) => Promise<R>,\n concurrency: number = PARALLEL_CONCURRENCY,\n signal?: AbortSignal,\n): Promise<ParallelResult<R>> {\n const itemCount = items.length;\n if (itemCount === 0) return { results: [], errors: [] };\n\n const results: { index: number; value: R }[] = [];\n const errors: { index: number; error: Error }[] = [];\n\n signal?.throwIfAborted();\n\n let nextIndex = 0;\n // Set when a worker saw the signal fire before an item ran — the only\n // shape in which the batch is genuinely incomplete. The annotation\n // matters: without it control-flow analysis keeps the `false` narrowing\n // from the initializer and cannot see the closure assignment.\n let truncated = false as boolean;\n\n const next = async (): Promise<void> => {\n while (nextIndex < itemCount) {\n if (signal?.aborted) {\n truncated = true;\n signal.throwIfAborted();\n }\n\n const index = nextIndex;\n nextIndex += 1;\n const item = items[index];\n if (item === undefined) {\n continue;\n }\n\n try {\n // No abort check after the processor: once an item has run, its\n // result is real work that a write caller may have committed to\n // disk. Discarding it here would report a finished append as\n // failed, and a client retry would append twice.\n const value = await processor(item);\n results.push({ index, value });\n } catch (error) {\n errors.push({\n index,\n error: normalizeUnknownError(error),\n });\n }\n }\n };\n\n const workerCount = Math.min(itemCount, concurrency);\n const workers: Promise<void>[] = new Array<Promise<void>>(workerCount);\n for (let index = 0; index < workerCount; index += 1) {\n workers[index] = next();\n }\n\n await Promise.allSettled(workers);\n // A deadline (AbortSignal.timeout) hit during the run surfaces here as\n // signal.reason — a TimeoutError — rather than a fresh AbortError, so\n // callers see TIMEOUT, not CANCELLED. Only a run that actually skipped\n // items reports the abort: a deadline firing after the last item\n // finished leaves a complete batch, and returning it beats telling the\n // caller that committed writes failed. The per-item throws above are\n // swallowed by allSettled.\n if (truncated) signal?.throwIfAborted();\n\n results.sort((left, right) => left.index - right.index);\n return { results, errors };\n}\n\n/**\n * The streaming sibling of {@link processInParallel}: bounded-concurrency\n * dispatch over an AsyncIterable that may be far larger than the caller wants\n * to walk, so it stops early and reports why.\n *\n * `maxEntries` caps how many entries are dispatched (maxFiles); `shouldStop`\n * lets the caller stop on its own accumulating result count (maxResults). Both\n * are checked before dispatch, so the returned reason is exactly one — the\n * loop breaks on the first that fires. `undefined` means every entry was\n * dispatched.\n */\nexport async function processEntriesConcurrently(\n entries: AsyncIterable<{ path: string }> | Iterable<{ path: string }>,\n options: {\n signal: AbortSignal | undefined;\n concurrency: number;\n maxEntries?: number;\n shouldStop?: () => boolean;\n onEntry: () => void;\n onError?: (entryPath: string, err: unknown) => void;\n runEntry: (entryPath: string) => Promise<void>;\n },\n): Promise<StoppedReason | undefined> {\n const pending = new Set<Promise<void>>();\n const { signal, concurrency, maxEntries, shouldStop, onEntry, onError, runEntry } = options;\n let stoppedReason: StoppedReason | undefined;\n let dispatched = 0;\n\n const waitForSlot = async (): Promise<void> => {\n if (pending.size < concurrency) return;\n await Promise.race(pending);\n };\n\n for await (const entry of entries) {\n // The signal is cancellation OR the caller's timeout: stop dispatching and\n // let the caller report the run as incomplete rather than as a full sweep.\n if (signal?.aborted) {\n stoppedReason = 'timeout';\n break;\n }\n if (maxEntries !== undefined && dispatched >= maxEntries) {\n stoppedReason = 'maxFiles';\n break;\n }\n // Check the result cap before waiting for a slot so an in-flight task that\n // already crossed the cap stops dispatch without an extra wait...\n if (shouldStop?.()) {\n stoppedReason = 'maxResults';\n break;\n }\n await waitForSlot();\n // ...and again after the slot frees, since tasks settle concurrently. The\n // cap can still be exceeded by at most `concurrency - 1` already-dispatched\n // tasks that are mid-flight; that overrun is inherent to concurrent dispatch.\n if (shouldStop?.()) {\n stoppedReason = 'maxResults';\n break;\n }\n onEntry();\n dispatched++;\n\n // Track a non-rejecting wrapper so a rejected task can never propagate out of\n // Promise.race(pending) in waitForSlot() and abort the loop before the final\n // drain below (which would silently abandon other in-flight tasks).\n // runEntry is expected to catch its own errors; if it unexpectedly throws,\n // record it as a failure rather than silently dropping it.\n const tracked = runEntry(entry.path).catch((err: unknown) => {\n onError?.(entry.path, err);\n });\n pending.add(tracked);\n void tracked.finally(() => {\n pending.delete(tracked);\n });\n }\n\n if (pending.size > 0) {\n await Promise.allSettled([...pending]);\n }\n\n return stoppedReason;\n}\n\nexport function withAbort<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) {\n return promise;\n }\n signal.throwIfAborted();\n let onAbort: (() => void) | undefined;\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n onAbort = () => {\n reject(signal.reason instanceof Error ? signal.reason : new Error('Operation aborted'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n ]).finally(() => {\n if (onAbort) {\n signal.removeEventListener('abort', onAbort);\n }\n });\n}\n"]}
|
package/dist/core/cursor.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PageSnapshotStore } from './
|
|
1
|
+
import type { PageSnapshotStore } from './store.ts';
|
|
2
2
|
/**
|
|
3
3
|
* The full result set a paged tool produced, before slicing. `truncated` is the
|
|
4
4
|
* engine's own stop state — the hard result cap or a timeout cut the set — and
|
|
@@ -24,17 +24,6 @@ export interface PaginatedPage<T, M, R> extends Page<T, M> {
|
|
|
24
24
|
/** The externalized full set. First page only, and only when incomplete. */
|
|
25
25
|
readonly resource?: R;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* The single home of the pagination cache-key rule: `JSON.stringify` of a
|
|
29
|
-
* flat object whose `method` names the tool and whose remaining fields
|
|
30
|
-
* identify the query. The literal's field order fixes key stability;
|
|
31
|
-
* `method` keeps tool key spaces disjoint. Byte-identical to the three
|
|
32
|
-
* hand-written tool builders it replaces.
|
|
33
|
-
*/
|
|
34
|
-
export declare function pageQueryKey(query: {
|
|
35
|
-
readonly method: string;
|
|
36
|
-
readonly path: string;
|
|
37
|
-
} & Record<string, unknown>): string;
|
|
38
27
|
/**
|
|
39
28
|
* The one replay-or-produce branch every paged tool runs. A cursor replays a
|
|
40
29
|
* stored snapshot; without one, `produce` runs the query and its result is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/core/cursor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/core/cursor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgClE;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAE,SAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;IACxD,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;IAC9C,KAAK,EAAE,iBAAiB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;CACrE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAwBlC"}
|
package/dist/core/cursor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ErrorCode, FsError } from
|
|
2
|
-
import { invalidCursor } from
|
|
1
|
+
import { ErrorCode, FsError } from "./errors.js";
|
|
2
|
+
import { invalidCursor } from "./store.js";
|
|
3
3
|
function encodePageCursor(cursor) {
|
|
4
4
|
return Buffer.from(JSON.stringify(cursor)).toString('base64url');
|
|
5
5
|
}
|
|
@@ -17,16 +17,6 @@ function pageResult(snapshotId, offset, pageSize, snapshot) {
|
|
|
17
17
|
: undefined,
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
21
|
-
* The single home of the pagination cache-key rule: `JSON.stringify` of a
|
|
22
|
-
* flat object whose `method` names the tool and whose remaining fields
|
|
23
|
-
* identify the query. The literal's field order fixes key stability;
|
|
24
|
-
* `method` keeps tool key spaces disjoint. Byte-identical to the three
|
|
25
|
-
* hand-written tool builders it replaces.
|
|
26
|
-
*/
|
|
27
|
-
export function pageQueryKey(query) {
|
|
28
|
-
return JSON.stringify(query);
|
|
29
|
-
}
|
|
30
20
|
/**
|
|
31
21
|
* The one replay-or-produce branch every paged tool runs. A cursor replays a
|
|
32
22
|
* stored snapshot; without one, `produce` runs the query and its result is
|
package/dist/core/cursor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/core/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/core/cursor.ts"],"names":[],"mappings":"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","sourcesContent":["import { ErrorCode, FsError } from './errors.ts';\nimport type { PageSnapshot, PageSnapshotStore } from './store.ts';\nimport { invalidCursor } from './store.ts';\n\ninterface PageCursor {\n readonly snapshotId: string;\n readonly offset: number;\n}\n\nfunction encodePageCursor(cursor: PageCursor): string {\n return Buffer.from(JSON.stringify(cursor)).toString('base64url');\n}\n\nfunction pageResult<T, M>(\n snapshotId: string,\n offset: number,\n pageSize: number,\n snapshot: PageSnapshot<T, M>,\n): Page<T, M> {\n if (offset >= snapshot.items.length) throw invalidCursor();\n const page = snapshot.items.slice(offset, offset + pageSize);\n const nextOffset = offset + page.length;\n return {\n page,\n metadata: snapshot.metadata,\n offset,\n nextCursor:\n nextOffset < snapshot.items.length\n ? encodePageCursor({ snapshotId, offset: nextOffset })\n : undefined,\n };\n}\n\n/**\n * The full result set a paged tool produced, before slicing. `truncated` is the\n * engine's own stop state — the hard result cap or a timeout cut the set — and\n * says nothing about page size.\n */\nexport interface ProducedPage<T, M> {\n readonly items: readonly T[];\n readonly metadata: M;\n readonly truncated: boolean;\n}\n\ninterface Page<T, M> {\n readonly page: readonly T[];\n readonly metadata: M;\n readonly nextCursor: string | undefined;\n /**\n * Index of this page's first item in the full set. A tool that reports\n * progress in its text needs it: without it every page can only say how many\n * rows it holds, which is the same number on page 1 and page 9.\n */\n readonly offset: number;\n}\n\nexport interface PaginatedPage<T, M, R> extends Page<T, M> {\n /** The externalized full set. First page only, and only when incomplete. */\n readonly resource?: R;\n}\n\n/**\n * The one replay-or-produce branch every paged tool runs. A cursor replays a\n * stored snapshot; without one, `produce` runs the query and its result is\n * snapshotted for later pages.\n *\n * The response is incomplete when the set spans more than one page or the\n * engine truncated it. Then — and only on the first page — `externalize`\n * stores the full set and its handle rides back as `resource`. Replayed pages\n * never carry it: the stored entry expires on the resource store's own TTL and\n * LRU, not this snapshot's, so replaying its URI would hand back a dead\n * pointer. Nor do they mint a new one; the set was already stored whole.\n */\nexport async function paginate<T, M, R>(params: {\n store: PageSnapshotStore;\n queryKey: string;\n cursor: string | undefined;\n pageSize: number;\n produce: () => Promise<ProducedPage<T, M>>;\n externalize?: ((items: readonly T[], metadata: M) => R) | undefined;\n}): Promise<PaginatedPage<T, M, R>> {\n if (params.cursor !== undefined) {\n const decoded = decodePageCursor(params.cursor);\n const snapshot = params.store.read<T, M>(decoded.snapshotId, params.queryKey);\n return pageResult(decoded.snapshotId, decoded.offset, params.pageSize, snapshot);\n }\n const produced = await params.produce();\n const { items, metadata } = produced;\n const incomplete = items.length > params.pageSize || produced.truncated;\n const first: Page<T, M> =\n items.length <= params.pageSize\n ? { page: items, metadata, nextCursor: undefined, offset: 0 }\n : pageResult(\n params.store.create({\n queryKey: params.queryKey,\n items,\n metadata,\n }),\n 0,\n params.pageSize,\n { items, metadata },\n );\n if (!incomplete || params.externalize === undefined) return first;\n return { ...first, resource: params.externalize(produced.items, produced.metadata) };\n}\n\nfunction decodePageCursor(cursor: string): PageCursor {\n try {\n const text = Buffer.from(cursor, 'base64url').toString('utf-8');\n const parsed = JSON.parse(text) as { snapshotId?: unknown; offset?: unknown };\n if (\n typeof parsed.snapshotId === 'string' &&\n parsed.snapshotId.length > 0 &&\n typeof parsed.offset === 'number' &&\n Number.isInteger(parsed.offset) &&\n parsed.offset >= 0\n ) {\n return { snapshotId: parsed.snapshotId, offset: parsed.offset };\n }\n throw new Error('Invalid page cursor');\n } catch (error) {\n if (error instanceof FsError) throw error;\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n invalidCursor().message,\n undefined,\n error instanceof Error ? error : undefined,\n );\n }\n}\n"]}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -28,9 +28,7 @@ interface ProblemFactoryOptions {
|
|
|
28
28
|
export declare const Problem: {
|
|
29
29
|
readonly invalidInput: (msg: string, o?: ProblemFactoryOptions) => Problem;
|
|
30
30
|
readonly accessDenied: (msg: string, o?: ProblemFactoryOptions) => Problem;
|
|
31
|
-
readonly timeout: (msg: string, o?: ProblemFactoryOptions) => Problem;
|
|
32
31
|
readonly cancelled: (msg: string, o?: ProblemFactoryOptions) => Problem;
|
|
33
|
-
readonly unknown: (msg: string, o?: ProblemFactoryOptions) => Problem;
|
|
34
32
|
readonly fromUnknown: (error: unknown, defaultCode: ErrorCode, path?: string) => Problem;
|
|
35
33
|
readonly toText: (error: unknown, defaultCode: ErrorCode) => {
|
|
36
34
|
code: ErrorCode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;CAcZ,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,UAAU,qBAAqB;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD,eAAO,MAAM,OAAO;iCACE,MAAM,MAAM,qBAAqB,KAAG,OAAO;iCAE3C,MAAM,MAAM,qBAAqB,KAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;CAcZ,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,UAAU,qBAAqB;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD,eAAO,MAAM,OAAO;iCACE,MAAM,MAAM,qBAAqB,KAAG,OAAO;iCAE3C,MAAM,MAAM,qBAAqB,KAAG,OAAO;8BAE9C,MAAM,MAAM,qBAAqB,KAAG,OAAO;kCAEzC,OAAO,eAAe,SAAS,SAAS,MAAM,KAAG,OAAO;6BAe7D,OAAO,eAAe,SAAS,KAAG;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAIzE,CAAC;AAcX,eAAO,MAAM,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAezD,CAAC;AAOF,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,SAAS,CAOpD,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAA0C,CAAC;AA+C5F,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAE1D;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAE7D;AAmBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAK1E;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAiBrD;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQhE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE3D;AAeD,qBAAa,OAAQ,SAAQ,KAAK;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;gBAEd,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;IAY5E,IAAI,IAAI,IAAI,SAAS,CAEpB;CACF"}
|
package/dist/core/errors.js
CHANGED
|
@@ -25,9 +25,7 @@ function build(code, message, opts = {}) {
|
|
|
25
25
|
export const Problem = {
|
|
26
26
|
invalidInput: (msg, o) => build(ErrorCode.INVALID_INPUT, msg, o),
|
|
27
27
|
accessDenied: (msg, o) => build(ErrorCode.ACCESS_DENIED, msg, o),
|
|
28
|
-
timeout: (msg, o) => build(ErrorCode.TIMEOUT, msg, o),
|
|
29
28
|
cancelled: (msg, o) => build(ErrorCode.CANCELLED, msg, o),
|
|
30
|
-
unknown: (msg, o) => build(ErrorCode.UNKNOWN, msg, o),
|
|
31
29
|
fromUnknown(error, defaultCode, path) {
|
|
32
30
|
const problem = classify(error);
|
|
33
31
|
const shouldOverride = problem.code === ErrorCode.UNKNOWN || problem.code === ErrorCode.IO_ERROR;
|
|
@@ -121,24 +119,16 @@ function classifyCauseChain(error) {
|
|
|
121
119
|
if (aborted)
|
|
122
120
|
return Problem.cancelled(message);
|
|
123
121
|
if (timedOut)
|
|
124
|
-
return
|
|
122
|
+
return build(ErrorCode.TIMEOUT, message);
|
|
125
123
|
if (errno !== undefined) {
|
|
126
124
|
return build(ERRNO_MAP[errno.code] ?? ErrorCode.IO_ERROR, message, {
|
|
127
125
|
...(errno.path !== undefined ? { path: errno.path } : {}),
|
|
128
126
|
});
|
|
129
127
|
}
|
|
130
|
-
return
|
|
128
|
+
return build(ErrorCode.UNKNOWN, message);
|
|
131
129
|
}
|
|
132
130
|
export function isFsError(error) {
|
|
133
|
-
|
|
134
|
-
return false;
|
|
135
|
-
if (!('problem' in error))
|
|
136
|
-
return false;
|
|
137
|
-
const p = error.problem;
|
|
138
|
-
if (p === null || typeof p !== 'object')
|
|
139
|
-
return false;
|
|
140
|
-
const c = p;
|
|
141
|
-
return typeof c['code'] === 'string' && typeof c['message'] === 'string';
|
|
131
|
+
return error instanceof FsError;
|
|
142
132
|
}
|
|
143
133
|
/** FsError traces to a caller-supplied argument; anything else is server-side. */
|
|
144
134
|
export function fsErrorCode(error) {
|
|
@@ -146,7 +136,7 @@ export function fsErrorCode(error) {
|
|
|
146
136
|
}
|
|
147
137
|
function classify(error) {
|
|
148
138
|
if (error === null || error === undefined) {
|
|
149
|
-
return
|
|
139
|
+
return build(ErrorCode.UNKNOWN, 'Unknown error');
|
|
150
140
|
}
|
|
151
141
|
if (isFsError(error))
|
|
152
142
|
return error.problem;
|
|
@@ -154,10 +144,10 @@ function classify(error) {
|
|
|
154
144
|
// `safeParse` inside the SDK's validator seam (tools/define.ts), which never
|
|
155
145
|
// throws — it hands back `z.prettifyError`'s string — and nothing in `src/`
|
|
156
146
|
// calls `.parse()`. A ZodError reaching here would fall through to
|
|
157
|
-
//
|
|
147
|
+
// UNKNOWN with Zod's raw JSON-dump `.message`, so if a `.parse()`
|
|
158
148
|
// is ever added, add the branch back with it rather than discovering this.
|
|
159
149
|
if (!(error instanceof Error)) {
|
|
160
|
-
return
|
|
150
|
+
return build(ErrorCode.UNKNOWN, typeof error === 'string' ? error : '[non-Error thrown]');
|
|
161
151
|
}
|
|
162
152
|
return classifyCauseChain(error);
|
|
163
153
|
}
|
|
@@ -232,7 +222,6 @@ export class FsError extends Error {
|
|
|
232
222
|
...(suggestion !== undefined ? { suggestion } : {}),
|
|
233
223
|
};
|
|
234
224
|
this.name = 'FsError';
|
|
235
|
-
Object.setPrototypeOf(this, FsError.prototype);
|
|
236
225
|
}
|
|
237
226
|
get code() {
|
|
238
227
|
return this.problem.code;
|
package/dist/core/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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","sourcesContent":["import { ProtocolErrorCode } from '@modelcontextprotocol/server';\n\nexport const ErrorCode = {\n ACCESS_DENIED: 'ACCESS_DENIED',\n NOT_FOUND: 'NOT_FOUND',\n NOT_FILE: 'NOT_FILE',\n NOT_DIRECTORY: 'NOT_DIRECTORY',\n TOO_LARGE: 'TOO_LARGE',\n TIMEOUT: 'TIMEOUT',\n CANCELLED: 'CANCELLED',\n INVALID_PATTERN: 'INVALID_PATTERN',\n INVALID_INPUT: 'INVALID_INPUT',\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n SYMLINK_NOT_ALLOWED: 'SYMLINK_NOT_ALLOWED',\n IO_ERROR: 'IO_ERROR',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\nexport interface Problem {\n readonly code: ErrorCode;\n readonly message: string;\n readonly path?: string;\n readonly suggestion?: string;\n}\n\ninterface ProblemFactoryOptions {\n path?: string;\n suggestion?: string;\n}\n\nfunction build(code: ErrorCode, message: string, opts: ProblemFactoryOptions = {}): Problem {\n return {\n code,\n message,\n ...(opts.path !== undefined ? { path: opts.path } : {}),\n ...(opts.suggestion !== undefined ? { suggestion: opts.suggestion } : {}),\n };\n}\n\nexport const Problem = {\n invalidInput: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.INVALID_INPUT, msg, o),\n accessDenied: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.ACCESS_DENIED, msg, o),\n timeout: (msg: string, o?: ProblemFactoryOptions): Problem => build(ErrorCode.TIMEOUT, msg, o),\n cancelled: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.CANCELLED, msg, o),\n unknown: (msg: string, o?: ProblemFactoryOptions): Problem => build(ErrorCode.UNKNOWN, msg, o),\n fromUnknown(error: unknown, defaultCode: ErrorCode, path?: string): Problem {\n const problem = classify(error);\n const shouldOverride =\n problem.code === ErrorCode.UNKNOWN || problem.code === ErrorCode.IO_ERROR;\n const code = shouldOverride ? defaultCode : problem.code;\n const suggestion =\n (shouldOverride ? DEFAULT_SUGGESTIONS[code] : undefined) ??\n problem.suggestion ??\n DEFAULT_SUGGESTIONS[problem.code];\n const resolvedPath = path ?? problem.path;\n return build(code, problem.message, {\n ...(resolvedPath !== undefined ? { path: resolvedPath } : {}),\n ...(suggestion !== undefined ? { suggestion } : {}),\n });\n },\n toText(error: unknown, defaultCode: ErrorCode): { code: ErrorCode; text: string } {\n const resolved = Problem.fromUnknown(error, defaultCode);\n return { code: resolved.code, text: formatDetailedError(resolved) };\n },\n} as const;\n\nconst DEFAULT_SUGGESTIONS: Readonly<Partial<Record<ErrorCode, string>>> = {\n [ErrorCode.ACCESS_DENIED]: 'Run list_roots to list allowed directories.',\n [ErrorCode.NOT_FOUND]: 'Run list or find_files to verify the path.',\n [ErrorCode.NOT_FILE]: 'Target is a directory, not a file.',\n [ErrorCode.NOT_DIRECTORY]: 'Target is a file, not a directory.',\n [ErrorCode.TOO_LARGE]: 'Use head/tail or line ranges to read partially.',\n [ErrorCode.TIMEOUT]: 'Reduce scope, depth, or maxResults.',\n [ErrorCode.INVALID_PATTERN]: 'Check syntax and escape special characters.',\n [ErrorCode.PERMISSION_DENIED]: 'Check OS file permissions.',\n [ErrorCode.SYMLINK_NOT_ALLOWED]: 'Symlink escapes allowed directories.',\n};\n\nexport const ERRNO_MAP: Readonly<Record<string, ErrorCode>> = {\n ENOENT: ErrorCode.NOT_FOUND,\n EACCES: ErrorCode.PERMISSION_DENIED,\n EPERM: ErrorCode.PERMISSION_DENIED,\n ENOTDIR: ErrorCode.NOT_DIRECTORY,\n EISDIR: ErrorCode.NOT_FILE,\n ELOOP: ErrorCode.SYMLINK_NOT_ALLOWED,\n ENAMETOOLONG: ErrorCode.INVALID_INPUT,\n ETIMEDOUT: ErrorCode.TIMEOUT,\n EMFILE: ErrorCode.IO_ERROR,\n ENFILE: ErrorCode.IO_ERROR,\n EBUSY: ErrorCode.IO_ERROR,\n ENOTEMPTY: ErrorCode.NOT_DIRECTORY,\n EEXIST: ErrorCode.INVALID_INPUT,\n EINVAL: ErrorCode.INVALID_INPUT,\n};\n\nconst ERRNO_RE = /^E[A-Z]+$/;\n\n// NOT_FOUND is in here (not just ENOENT) because a dangling symlink whose\n// target sits inside an allowed root surfaces as an FsError NOT_FOUND. Skipping\n// the entry is the point of a listing; rethrowing would fail the whole listing.\nexport const SKIPPABLE_FS_CODES: ReadonlySet<ErrorCode> = new Set([\n ErrorCode.ACCESS_DENIED,\n ErrorCode.NOT_FOUND,\n // OS-level EACCES/EPERM on a symlink target during a listing is exactly as\n // skippable as the other three codes.\n ErrorCode.PERMISSION_DENIED,\n ErrorCode.SYMLINK_NOT_ALLOWED,\n]);\n\nexport const SKIPPABLE_ERRNOS: ReadonlySet<string> = new Set(['ENOENT', 'EACCES', 'ELOOP']);\n\n/**\n * Walk `error` and its `cause` chain for the one fact that decides the code: an\n * abort anywhere wins, then a timeout anywhere, then the FIRST errno seen.\n * `visited` guards a cyclic chain. Returns the Problem directly — the\n * intermediate signal union this replaced existed only to be destructured back\n * into a Problem two functions later, and carried a `syscall` nobody read.\n */\nfunction classifyCauseChain(error: unknown): Problem {\n const message = formatUnknownErrorMessage(error);\n const visited = new Set<unknown>();\n let aborted = false;\n let timedOut = false;\n let errno: { code: string; path?: string } | undefined;\n\n for (\n let current: unknown = error;\n current !== undefined && current !== null && !visited.has(current);\n current = (current as { cause?: unknown }).cause\n ) {\n visited.add(current);\n if (!(current instanceof Error)) continue;\n const raw = (current as { code?: unknown }).code;\n const code = typeof raw === 'string' ? raw : undefined;\n // Ordered like the per-error read it replaces: a node that reads as an\n // abort or a timeout never also contributes its errno.\n if (current.name === 'AbortError' || code === 'ABORT_ERR') {\n aborted = true;\n } else if (current.name === 'TimeoutError' || code === 'ETIMEDOUT') {\n timedOut = true;\n } else if (errno === undefined && code !== undefined && ERRNO_RE.test(code)) {\n const { path } = current as NodeJS.ErrnoException;\n errno = { code, ...(typeof path === 'string' ? { path } : {}) };\n }\n }\n\n if (aborted) return Problem.cancelled(message);\n if (timedOut) return Problem.timeout(message);\n if (errno !== undefined) {\n return build(ERRNO_MAP[errno.code] ?? ErrorCode.IO_ERROR, message, {\n ...(errno.path !== undefined ? { path: errno.path } : {}),\n });\n }\n return Problem.unknown(message);\n}\n\nexport function isFsError(error: unknown): error is FsError {\n if (!(error instanceof Error) || error.name !== 'FsError') return false;\n if (!('problem' in error)) return false;\n const p = (error as { problem?: unknown }).problem;\n if (p === null || typeof p !== 'object') return false;\n const c = p as Record<string, unknown>;\n return typeof c['code'] === 'string' && typeof c['message'] === 'string';\n}\n\n/** FsError traces to a caller-supplied argument; anything else is server-side. */\nexport function fsErrorCode(error: unknown): ProtocolErrorCode {\n return isFsError(error) ? ProtocolErrorCode.InvalidParams : ProtocolErrorCode.InternalError;\n}\n\nfunction classify(error: unknown): Problem {\n if (error === null || error === undefined) {\n return Problem.unknown('Unknown error');\n }\n if (isFsError(error)) return error.problem;\n // No `ZodError` branch, deliberately. Tool arguments are validated by\n // `safeParse` inside the SDK's validator seam (tools/define.ts), which never\n // throws — it hands back `z.prettifyError`'s string — and nothing in `src/`\n // calls `.parse()`. A ZodError reaching here would fall through to\n // `Problem.unknown` with Zod's raw JSON-dump `.message`, so if a `.parse()`\n // is ever added, add the branch back with it rather than discovering this.\n if (!(error instanceof Error)) {\n return Problem.unknown(typeof error === 'string' ? error : '[non-Error thrown]');\n }\n return classifyCauseChain(error);\n}\n\nexport function isNodeError(error: unknown): error is NodeJS.ErrnoException {\n if (!(error instanceof Error)) return false;\n if (!('code' in error)) return false;\n const { code } = error as { code?: unknown };\n return typeof code === 'string';\n}\n\n/** True when `error` is a Node errno error with code `ENOENT` (path not found). */\nexport function isNotFoundErrno(error: unknown): error is NodeJS.ErrnoException {\n return isNodeError(error) && error.code === 'ENOENT';\n}\n\n/**\n * Rethrow when `error` reads as cancelled. Answers the question directly rather\n * than through `classify`, which allocated a Problem — and ran\n * `formatUnknownErrorMessage`, i.e. a `JSON.stringify` on a non-Error — for a\n * boolean. This sits in eight catch blocks, several inside per-entry scan loops.\n */\nexport function rethrowIfAborted(error: unknown): void {\n if (isFsError(error)) {\n if (error.code === ErrorCode.CANCELLED) throw error;\n return;\n }\n const visited = new Set<unknown>();\n for (\n let current: unknown = error;\n current !== undefined && current !== null && !visited.has(current);\n current = (current as { cause?: unknown }).cause\n ) {\n visited.add(current);\n if (!(current instanceof Error)) continue;\n if (current.name === 'AbortError' || (current as { code?: unknown }).code === 'ABORT_ERR') {\n throw error;\n }\n }\n}\n\nexport function formatUnknownErrorMessage(error: unknown): string {\n if (typeof error === 'string') return error;\n if (error instanceof Error) return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return `[non-serializable: ${Object.prototype.toString.call(error)}]`;\n }\n}\n\nexport function normalizeUnknownError(error: unknown): Error {\n return error instanceof Error ? error : new Error(formatUnknownErrorMessage(error));\n}\n\nfunction formatDetailedError(\n error: Pick<Problem, 'code' | 'message' | 'path' | 'suggestion'>,\n): string {\n const lines: string[] = [`${error.code}: ${error.message}`];\n if (error.path && !error.message.includes(error.path)) {\n lines.push(error.path);\n }\n if (error.suggestion) {\n lines.push(error.suggestion);\n }\n return lines.join('\\n');\n}\n\nexport class FsError extends Error {\n readonly problem: Problem;\n\n constructor(code: ErrorCode, message: string, path?: string, cause?: unknown) {\n super(message, cause === undefined ? {} : { cause });\n const suggestion = DEFAULT_SUGGESTIONS[code];\n this.problem = {\n code,\n message,\n ...(path !== undefined ? { path } : {}),\n ...(suggestion !== undefined ? { suggestion } : {}),\n };\n this.name = 'FsError';\n Object.setPrototypeOf(this, FsError.prototype);\n }\n\n get code(): ErrorCode {\n return this.problem.code;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,aAAa,EAAE,eAAe;IAC9B,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,aAAa,EAAE,eAAe;IAC9B,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,eAAe,EAAE,iBAAiB;IAClC,aAAa,EAAE,eAAe;IAC9B,iBAAiB,EAAE,mBAAmB;IACtC,mBAAmB,EAAE,qBAAqB;IAC1C,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;CACV,CAAC;AAgBX,SAAS,KAAK,CAAC,IAAe,EAAE,OAAe,EAAE,OAA8B,EAAE;IAC/E,OAAO;QACL,IAAI;QACJ,OAAO;QACP,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,YAAY,EAAE,CAAC,GAAW,EAAE,CAAyB,EAAW,EAAE,CAChE,KAAK,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,YAAY,EAAE,CAAC,GAAW,EAAE,CAAyB,EAAW,EAAE,CAChE,KAAK,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,SAAS,EAAE,CAAC,GAAW,EAAE,CAAyB,EAAW,EAAE,CAC7D,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,WAAW,CAAC,KAAc,EAAE,WAAsB,EAAE,IAAa;QAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,cAAc,GAClB,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,QAAQ,CAAC;QAC5E,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;QACzD,MAAM,UAAU,GACd,CAAC,cAAc,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACxD,OAAO,CAAC,UAAU;YAClB,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,YAAY,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;QAC1C,OAAO,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE;YAClC,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,KAAc,EAAE,WAAsB;QAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtE,CAAC;CACO,CAAC;AAEX,MAAM,mBAAmB,GAAiD;IACxE,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,6CAA6C;IACxE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,4CAA4C;IACnE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,oCAAoC;IAC1D,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,oCAAoC;IAC/D,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,iDAAiD;IACxE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,qCAAqC;IAC1D,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,6CAA6C;IAC1E,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAAE,4BAA4B;IAC3D,CAAC,SAAS,CAAC,mBAAmB,CAAC,EAAE,sCAAsC;CACxE,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAwC;IAC5D,MAAM,EAAE,SAAS,CAAC,SAAS;IAC3B,MAAM,EAAE,SAAS,CAAC,iBAAiB;IACnC,KAAK,EAAE,SAAS,CAAC,iBAAiB;IAClC,OAAO,EAAE,SAAS,CAAC,aAAa;IAChC,MAAM,EAAE,SAAS,CAAC,QAAQ;IAC1B,KAAK,EAAE,SAAS,CAAC,mBAAmB;IACpC,YAAY,EAAE,SAAS,CAAC,aAAa;IACrC,SAAS,EAAE,SAAS,CAAC,OAAO;IAC5B,MAAM,EAAE,SAAS,CAAC,QAAQ;IAC1B,MAAM,EAAE,SAAS,CAAC,QAAQ;IAC1B,KAAK,EAAE,SAAS,CAAC,QAAQ;IACzB,SAAS,EAAE,SAAS,CAAC,aAAa;IAClC,MAAM,EAAE,SAAS,CAAC,aAAa;IAC/B,MAAM,EAAE,SAAS,CAAC,aAAa;CAChC,CAAC;AAEF,MAAM,QAAQ,GAAG,WAAW,CAAC;AAE7B,0EAA0E;AAC1E,gFAAgF;AAChF,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAA2B,IAAI,GAAG,CAAC;IAChE,SAAS,CAAC,aAAa;IACvB,SAAS,CAAC,SAAS;IACnB,2EAA2E;IAC3E,sCAAsC;IACtC,SAAS,CAAC,iBAAiB;IAC3B,SAAS,CAAC,mBAAmB;CAC9B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAwB,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5F;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAW,CAAC;IACnC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,KAAkD,CAAC;IAEvD,KACE,IAAI,OAAO,GAAY,KAAK,EAC5B,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAClE,OAAO,GAAI,OAA+B,CAAC,KAAK,EAChD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,CAAC,OAAO,YAAY,KAAK,CAAC;YAAE,SAAS;QAC1C,MAAM,GAAG,GAAI,OAA8B,CAAC,IAAI,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;QACvD,uEAAuE;QACvE,uDAAuD;QACvD,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAC1D,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YACnE,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5E,MAAM,EAAE,IAAI,EAAE,GAAG,OAAgC,CAAC;YAClD,KAAK,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAClE,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,QAAQ;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE;YACjE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1D,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,OAAO,CAAC;AAClC,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,aAAa,CAAC;AAC9F,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,SAAS,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IAC3C,sEAAsE;IACtE,6EAA6E;IAC7E,4EAA4E;IAC5E,mEAAmE;IACnE,kEAAkE;IAClE,2EAA2E;IAC3E,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,MAAM,EAAE,IAAI,EAAE,GAAG,KAA2B,CAAC;IAC7C,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC;AAClC,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,SAAS;YAAE,MAAM,KAAK,CAAC;QACpD,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAW,CAAC;IACnC,KACE,IAAI,OAAO,GAAY,KAAK,EAC5B,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAClE,OAAO,GAAI,OAA+B,CAAC,KAAK,EAChD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,CAAC,OAAO,YAAY,KAAK,CAAC;YAAE,SAAS;QAC1C,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,IAAK,OAA8B,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC1F,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAc;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IACjD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,sBAAsB,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IACxE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAgE;IAEhE,MAAM,KAAK,GAAa,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,OAAQ,SAAQ,KAAK;IACvB,OAAO,CAAU;IAE1B,YAAY,IAAe,EAAE,OAAe,EAAE,IAAa,EAAE,KAAe;QAC1E,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,GAAG;YACb,IAAI;YACJ,OAAO;YACP,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;IACxB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF","sourcesContent":["import { ProtocolErrorCode } from '@modelcontextprotocol/server';\n\nexport const ErrorCode = {\n ACCESS_DENIED: 'ACCESS_DENIED',\n NOT_FOUND: 'NOT_FOUND',\n NOT_FILE: 'NOT_FILE',\n NOT_DIRECTORY: 'NOT_DIRECTORY',\n TOO_LARGE: 'TOO_LARGE',\n TIMEOUT: 'TIMEOUT',\n CANCELLED: 'CANCELLED',\n INVALID_PATTERN: 'INVALID_PATTERN',\n INVALID_INPUT: 'INVALID_INPUT',\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n SYMLINK_NOT_ALLOWED: 'SYMLINK_NOT_ALLOWED',\n IO_ERROR: 'IO_ERROR',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\nexport interface Problem {\n readonly code: ErrorCode;\n readonly message: string;\n readonly path?: string;\n readonly suggestion?: string;\n}\n\ninterface ProblemFactoryOptions {\n path?: string;\n suggestion?: string;\n}\n\nfunction build(code: ErrorCode, message: string, opts: ProblemFactoryOptions = {}): Problem {\n return {\n code,\n message,\n ...(opts.path !== undefined ? { path: opts.path } : {}),\n ...(opts.suggestion !== undefined ? { suggestion: opts.suggestion } : {}),\n };\n}\n\nexport const Problem = {\n invalidInput: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.INVALID_INPUT, msg, o),\n accessDenied: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.ACCESS_DENIED, msg, o),\n cancelled: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.CANCELLED, msg, o),\n fromUnknown(error: unknown, defaultCode: ErrorCode, path?: string): Problem {\n const problem = classify(error);\n const shouldOverride =\n problem.code === ErrorCode.UNKNOWN || problem.code === ErrorCode.IO_ERROR;\n const code = shouldOverride ? defaultCode : problem.code;\n const suggestion =\n (shouldOverride ? DEFAULT_SUGGESTIONS[code] : undefined) ??\n problem.suggestion ??\n DEFAULT_SUGGESTIONS[problem.code];\n const resolvedPath = path ?? problem.path;\n return build(code, problem.message, {\n ...(resolvedPath !== undefined ? { path: resolvedPath } : {}),\n ...(suggestion !== undefined ? { suggestion } : {}),\n });\n },\n toText(error: unknown, defaultCode: ErrorCode): { code: ErrorCode; text: string } {\n const resolved = Problem.fromUnknown(error, defaultCode);\n return { code: resolved.code, text: formatDetailedError(resolved) };\n },\n} as const;\n\nconst DEFAULT_SUGGESTIONS: Readonly<Partial<Record<ErrorCode, string>>> = {\n [ErrorCode.ACCESS_DENIED]: 'Run list_roots to list allowed directories.',\n [ErrorCode.NOT_FOUND]: 'Run list or find_files to verify the path.',\n [ErrorCode.NOT_FILE]: 'Target is a directory, not a file.',\n [ErrorCode.NOT_DIRECTORY]: 'Target is a file, not a directory.',\n [ErrorCode.TOO_LARGE]: 'Use head/tail or line ranges to read partially.',\n [ErrorCode.TIMEOUT]: 'Reduce scope, depth, or maxResults.',\n [ErrorCode.INVALID_PATTERN]: 'Check syntax and escape special characters.',\n [ErrorCode.PERMISSION_DENIED]: 'Check OS file permissions.',\n [ErrorCode.SYMLINK_NOT_ALLOWED]: 'Symlink escapes allowed directories.',\n};\n\nexport const ERRNO_MAP: Readonly<Record<string, ErrorCode>> = {\n ENOENT: ErrorCode.NOT_FOUND,\n EACCES: ErrorCode.PERMISSION_DENIED,\n EPERM: ErrorCode.PERMISSION_DENIED,\n ENOTDIR: ErrorCode.NOT_DIRECTORY,\n EISDIR: ErrorCode.NOT_FILE,\n ELOOP: ErrorCode.SYMLINK_NOT_ALLOWED,\n ENAMETOOLONG: ErrorCode.INVALID_INPUT,\n ETIMEDOUT: ErrorCode.TIMEOUT,\n EMFILE: ErrorCode.IO_ERROR,\n ENFILE: ErrorCode.IO_ERROR,\n EBUSY: ErrorCode.IO_ERROR,\n ENOTEMPTY: ErrorCode.NOT_DIRECTORY,\n EEXIST: ErrorCode.INVALID_INPUT,\n EINVAL: ErrorCode.INVALID_INPUT,\n};\n\nconst ERRNO_RE = /^E[A-Z]+$/;\n\n// NOT_FOUND is in here (not just ENOENT) because a dangling symlink whose\n// target sits inside an allowed root surfaces as an FsError NOT_FOUND. Skipping\n// the entry is the point of a listing; rethrowing would fail the whole listing.\nexport const SKIPPABLE_FS_CODES: ReadonlySet<ErrorCode> = new Set([\n ErrorCode.ACCESS_DENIED,\n ErrorCode.NOT_FOUND,\n // OS-level EACCES/EPERM on a symlink target during a listing is exactly as\n // skippable as the other three codes.\n ErrorCode.PERMISSION_DENIED,\n ErrorCode.SYMLINK_NOT_ALLOWED,\n]);\n\nexport const SKIPPABLE_ERRNOS: ReadonlySet<string> = new Set(['ENOENT', 'EACCES', 'ELOOP']);\n\n/**\n * Walk `error` and its `cause` chain for the one fact that decides the code: an\n * abort anywhere wins, then a timeout anywhere, then the FIRST errno seen.\n * `visited` guards a cyclic chain. Returns the Problem directly — the\n * intermediate signal union this replaced existed only to be destructured back\n * into a Problem two functions later, and carried a `syscall` nobody read.\n */\nfunction classifyCauseChain(error: unknown): Problem {\n const message = formatUnknownErrorMessage(error);\n const visited = new Set<unknown>();\n let aborted = false;\n let timedOut = false;\n let errno: { code: string; path?: string } | undefined;\n\n for (\n let current: unknown = error;\n current !== undefined && current !== null && !visited.has(current);\n current = (current as { cause?: unknown }).cause\n ) {\n visited.add(current);\n if (!(current instanceof Error)) continue;\n const raw = (current as { code?: unknown }).code;\n const code = typeof raw === 'string' ? raw : undefined;\n // Ordered like the per-error read it replaces: a node that reads as an\n // abort or a timeout never also contributes its errno.\n if (current.name === 'AbortError' || code === 'ABORT_ERR') {\n aborted = true;\n } else if (current.name === 'TimeoutError' || code === 'ETIMEDOUT') {\n timedOut = true;\n } else if (errno === undefined && code !== undefined && ERRNO_RE.test(code)) {\n const { path } = current as NodeJS.ErrnoException;\n errno = { code, ...(typeof path === 'string' ? { path } : {}) };\n }\n }\n\n if (aborted) return Problem.cancelled(message);\n if (timedOut) return build(ErrorCode.TIMEOUT, message);\n if (errno !== undefined) {\n return build(ERRNO_MAP[errno.code] ?? ErrorCode.IO_ERROR, message, {\n ...(errno.path !== undefined ? { path: errno.path } : {}),\n });\n }\n return build(ErrorCode.UNKNOWN, message);\n}\n\nexport function isFsError(error: unknown): error is FsError {\n return error instanceof FsError;\n}\n\n/** FsError traces to a caller-supplied argument; anything else is server-side. */\nexport function fsErrorCode(error: unknown): ProtocolErrorCode {\n return isFsError(error) ? ProtocolErrorCode.InvalidParams : ProtocolErrorCode.InternalError;\n}\n\nfunction classify(error: unknown): Problem {\n if (error === null || error === undefined) {\n return build(ErrorCode.UNKNOWN, 'Unknown error');\n }\n if (isFsError(error)) return error.problem;\n // No `ZodError` branch, deliberately. Tool arguments are validated by\n // `safeParse` inside the SDK's validator seam (tools/define.ts), which never\n // throws — it hands back `z.prettifyError`'s string — and nothing in `src/`\n // calls `.parse()`. A ZodError reaching here would fall through to\n // UNKNOWN with Zod's raw JSON-dump `.message`, so if a `.parse()`\n // is ever added, add the branch back with it rather than discovering this.\n if (!(error instanceof Error)) {\n return build(ErrorCode.UNKNOWN, typeof error === 'string' ? error : '[non-Error thrown]');\n }\n return classifyCauseChain(error);\n}\n\nexport function isNodeError(error: unknown): error is NodeJS.ErrnoException {\n if (!(error instanceof Error)) return false;\n if (!('code' in error)) return false;\n const { code } = error as { code?: unknown };\n return typeof code === 'string';\n}\n\n/** True when `error` is a Node errno error with code `ENOENT` (path not found). */\nexport function isNotFoundErrno(error: unknown): error is NodeJS.ErrnoException {\n return isNodeError(error) && error.code === 'ENOENT';\n}\n\n/**\n * Rethrow when `error` reads as cancelled. Answers the question directly rather\n * than through `classify`, which allocated a Problem — and ran\n * `formatUnknownErrorMessage`, i.e. a `JSON.stringify` on a non-Error — for a\n * boolean. This sits in eight catch blocks, several inside per-entry scan loops.\n */\nexport function rethrowIfAborted(error: unknown): void {\n if (isFsError(error)) {\n if (error.code === ErrorCode.CANCELLED) throw error;\n return;\n }\n const visited = new Set<unknown>();\n for (\n let current: unknown = error;\n current !== undefined && current !== null && !visited.has(current);\n current = (current as { cause?: unknown }).cause\n ) {\n visited.add(current);\n if (!(current instanceof Error)) continue;\n if (current.name === 'AbortError' || (current as { code?: unknown }).code === 'ABORT_ERR') {\n throw error;\n }\n }\n}\n\nexport function formatUnknownErrorMessage(error: unknown): string {\n if (typeof error === 'string') return error;\n if (error instanceof Error) return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return `[non-serializable: ${Object.prototype.toString.call(error)}]`;\n }\n}\n\nexport function normalizeUnknownError(error: unknown): Error {\n return error instanceof Error ? error : new Error(formatUnknownErrorMessage(error));\n}\n\nfunction formatDetailedError(\n error: Pick<Problem, 'code' | 'message' | 'path' | 'suggestion'>,\n): string {\n const lines: string[] = [`${error.code}: ${error.message}`];\n if (error.path && !error.message.includes(error.path)) {\n lines.push(error.path);\n }\n if (error.suggestion) {\n lines.push(error.suggestion);\n }\n return lines.join('\\n');\n}\n\nexport class FsError extends Error {\n readonly problem: Problem;\n\n constructor(code: ErrorCode, message: string, path?: string, cause?: unknown) {\n super(message, cause === undefined ? {} : { cause });\n const suggestion = DEFAULT_SUGGESTIONS[code];\n this.problem = {\n code,\n message,\n ...(path !== undefined ? { path } : {}),\n ...(suggestion !== undefined ? { suggestion } : {}),\n };\n this.name = 'FsError';\n }\n\n get code(): ErrorCode {\n return this.problem.code;\n }\n}\n"]}
|
package/dist/core/file-uri.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ContentBlock } from '@modelcontextprotocol/server';
|
|
2
|
-
import type { FileKind } from './schema.
|
|
3
|
-
import type { ResourceStore } from './store.
|
|
2
|
+
import type { FileKind } from './schema.ts';
|
|
3
|
+
import type { ResourceStore } from './store.ts';
|
|
4
4
|
export declare const FILESYSTEM_FILE_URI_TEMPLATE = "filesystem-mcp://file/{+path}";
|
|
5
5
|
/**
|
|
6
6
|
* The `{+path}` template-variable form of a path — what `completion/complete`
|
package/dist/core/file-uri.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
|
-
import { detectMimeFromContent } from
|
|
3
|
-
import { countLines } from
|
|
4
|
-
import { getMaxTextFileSize } from
|
|
2
|
+
import { detectMimeFromContent } from "./mime.js";
|
|
3
|
+
import { countLines } from "./read.js";
|
|
4
|
+
import { getMaxTextFileSize } from "./util.js";
|
|
5
5
|
// Single owner of the `filesystem-mcp://file/` URI scheme — the template string,
|
|
6
6
|
// the path→URI encoder, the URI→path decoder, the link blocks built from them,
|
|
7
7
|
// and the post-write metadata block every write tool reports alongside them.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-uri.js","sourceRoot":"","sources":["../../src/core/file-uri.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\nimport { detectMimeFromContent } from './mime.
|
|
1
|
+
{"version":3,"file":"file-uri.js","sourceRoot":"","sources":["../../src/core/file-uri.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\nimport { detectMimeFromContent } from './mime.ts';\nimport { countLines } from './read.ts';\nimport type { FileKind } from './schema.ts';\nimport type { ResourceStore } from './store.ts';\nimport { getMaxTextFileSize } from './util.ts';\n\n// Single owner of the `filesystem-mcp://file/` URI scheme — the template string,\n// the path→URI encoder, the URI→path decoder, the link blocks built from them,\n// and the post-write metadata block every write tool reports alongside them.\n\nexport const FILESYSTEM_FILE_URI_TEMPLATE = 'filesystem-mcp://file/{+path}';\n\n/**\n * The `{+path}` template-variable form of a path — what `completion/complete`\n * must return, since a client expands a suggestion into the template verbatim.\n * Unescaped, a '#' or '?' in a filename truncates the URI into a fragment or\n * query (silently naming a different path) and a '%' makes the decode throw.\n * Separators are restored so the value still reads as a path.\n */\nexport function encodeFileUriPath(validPath: string): string {\n const posix = validPath.replace(/\\\\/g, '/');\n return encodeURIComponent(posix).replace(/%2F/gi, '/');\n}\n\n/** Inverse of {@link encodeFileUriPath}; `undefined` on invalid percent-encoding. */\nexport function decodeFileUriPath(encoded: string): string | undefined {\n try {\n return decodeURIComponent(encoded);\n } catch {\n return undefined;\n }\n}\n\nexport function buildFileResourceUri(validPath: string): string {\n return `filesystem-mcp://file/${encodeFileUriPath(validPath)}`;\n}\n\n/**\n * The link block for a URI already built by `buildFileResourceUri`. Callers that\n * hold the URI must use this rather than rebuilding from a path: a path that\n * differs only in case (the drive letter, on Windows) yields a *different* URI\n * string, and watchers key on that string — a link and a `resourceUri` that\n * disagree hand the client two subscriptions for one file.\n */\nexport function buildFileResourceLinkFor(\n uri: string,\n name: string,\n mimeType: string,\n size: number,\n): ContentBlock {\n return {\n type: 'resource_link',\n uri,\n name,\n mimeType,\n size,\n annotations: { audience: ['user', 'assistant'] },\n };\n}\n\nexport function buildFileResourceLink(\n validPath: string,\n mimeType: string,\n size: number,\n): ContentBlock {\n return buildFileResourceLinkFor(\n buildFileResourceUri(validPath),\n basename(validPath),\n mimeType,\n size,\n );\n}\n\nexport function extractPath(uri: string): string | undefined {\n try {\n const url = new URL(uri);\n if (url.protocol !== 'filesystem-mcp:' || url.host !== 'file') return undefined;\n return decodeFileUriPath(url.pathname.slice(1));\n } catch {\n return undefined;\n }\n}\n\nexport interface WrittenFileMeta {\n size: number;\n lineCount: number;\n mimeType: string;\n kind: FileKind;\n /**\n * Undefined when the resulting file exceeds the text-size cap: the store\n * serves the URI via readRaw, which would reject it with TOO_LARGE.\n */\n resourceUri: string | undefined;\n /** Undefined when no resource store is configured — nothing to link into. */\n resourceLink: ContentBlock | undefined;\n}\n\n/**\n * The five-step block every write tool runs on its post-write content: size,\n * line count, MIME, the file's resource URI, and the store-gated link block.\n */\nexport function buildWrittenFileMeta(\n validPath: string,\n content: string,\n resourceStore: ResourceStore | undefined,\n): WrittenFileMeta {\n const size = Buffer.byteLength(content, 'utf-8');\n const mimeInfo = detectMimeFromContent(validPath, content);\n // An edit or patch can push a readable file past the text-size cap; the\n // store serves the URI via readRaw, which would reject it with TOO_LARGE.\n const servable = size <= getMaxTextFileSize();\n return {\n size,\n lineCount: countLines(content),\n mimeType: mimeInfo.mimeType,\n kind: mimeInfo.kind,\n resourceUri: servable ? buildFileResourceUri(validPath) : undefined,\n resourceLink:\n resourceStore && servable\n ? buildFileResourceLink(validPath, mimeInfo.mimeType, size)\n : undefined,\n };\n}\n"]}
|
package/dist/core/fmt.d.ts
CHANGED
|
@@ -41,15 +41,5 @@ export declare function pageTrailer(p: {
|
|
|
41
41
|
nextCursor?: string | undefined;
|
|
42
42
|
stoppedReason?: string | undefined;
|
|
43
43
|
}): string;
|
|
44
|
-
export declare function padEndVisible(s: string, width: number): string;
|
|
45
|
-
export declare const cliFmt: {
|
|
46
|
-
bold: (t: string) => string;
|
|
47
|
-
dim: (t: string) => string;
|
|
48
|
-
cyan: (t: string) => string;
|
|
49
|
-
yellow: (t: string) => string;
|
|
50
|
-
flag: (t: string) => string;
|
|
51
|
-
section: (t: string) => string;
|
|
52
|
-
bool: (v: boolean) => string;
|
|
53
|
-
};
|
|
54
44
|
export {};
|
|
55
45
|
//# sourceMappingURL=fmt.d.ts.map
|
package/dist/core/fmt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fmt.d.ts","sourceRoot":"","sources":["../../src/core/fmt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fmt.d.ts","sourceRoot":"","sources":["../../src/core/fmt.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAkCtC,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAGnE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAiB,GAAG,MAAM,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAKD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,SAAQ,GAAG,MAAM,CAI9E;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAK,GAAG,MAAM,CAE/E;AAYD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,GAAG,MAAM,CAoBT"}
|
package/dist/core/fmt.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
|
-
import {
|
|
3
|
-
import { MAX_SEARCH_RESULTS } from './util.js';
|
|
2
|
+
import { MAX_SEARCH_RESULTS } from "./util.js";
|
|
4
3
|
function buildBody(ctx, phase) {
|
|
5
4
|
const items = [];
|
|
6
5
|
if (ctx.subject) {
|
|
@@ -96,20 +95,4 @@ export function pageTrailer(p) {
|
|
|
96
95
|
}
|
|
97
96
|
return lines.length > 0 ? `\n\n${lines.join('\n')}` : '';
|
|
98
97
|
}
|
|
99
|
-
// ---------------------------------------------------------------------------
|
|
100
|
-
// CLI color helpers
|
|
101
|
-
// ---------------------------------------------------------------------------
|
|
102
|
-
export function padEndVisible(s, width) {
|
|
103
|
-
const visible = stripVTControlCharacters(s).length;
|
|
104
|
-
return visible >= width ? s : s + ' '.repeat(width - visible);
|
|
105
|
-
}
|
|
106
|
-
export const cliFmt = {
|
|
107
|
-
bold: (t) => styleText('bold', t),
|
|
108
|
-
dim: (t) => styleText('dim', t),
|
|
109
|
-
cyan: (t) => styleText('cyan', t),
|
|
110
|
-
yellow: (t) => styleText('yellow', t),
|
|
111
|
-
flag: (t) => styleText('green', t),
|
|
112
|
-
section: (t) => styleText(['cyan', 'bold'], t),
|
|
113
|
-
bool: (v) => (v ? styleText('green', 'true') : styleText('red', 'false')),
|
|
114
|
-
};
|
|
115
98
|
//# sourceMappingURL=fmt.js.map
|
package/dist/core/fmt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fmt.js","sourceRoot":"","sources":["../../src/core/fmt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"fmt.js","sourceRoot":"","sources":["../../src/core/fmt.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename } from 'node:path';\n\nimport { MAX_SEARCH_RESULTS } from './util.ts';\n\nexport interface ProgressCtx {\n label: string;\n subject?: string;\n scope?: string;\n current?: number;\n total?: number;\n detail?: string;\n error?: string;\n}\n\ntype Phase = 'tick' | 'done' | 'fail';\n\nfunction buildBody(ctx: ProgressCtx, phase: Phase): string {\n const items: string[] = [];\n if (ctx.subject) {\n items.push(ctx.subject);\n }\n\n switch (phase) {\n case 'tick':\n if (ctx.current !== undefined && ctx.total !== undefined) {\n items.push(`${ctx.current}/${ctx.total}`);\n } else if (ctx.current !== undefined) {\n items.push(String(ctx.current));\n }\n break;\n case 'done':\n if (ctx.scope) {\n items.push(ctx.scope);\n }\n if (ctx.detail) {\n items.push(ctx.detail);\n }\n break;\n case 'fail':\n if (ctx.error) {\n items.push(ctx.error);\n }\n break;\n }\n\n return items.join(' · ');\n}\n\nexport function plainMessage(phase: Phase, ctx: ProgressCtx): string {\n const body = buildBody(ctx, phase);\n return body ? `${ctx.label}: ${body}` : `${ctx.label}:`;\n}\n\nexport function formatCount(count: number, singular: string, plural = `${singular}s`): string {\n return `${String(count)} ${count === 1 ? singular : plural}`;\n}\n\n/**\n * Short label for a path in summary text. `basename` returns '' for a root\n * (`C:\\`, `/`) and for a trailing-slash path, which rendered as a bare\n * separator in the per-path summaries, so fall back to the full path.\n */\nexport function pathLabel(path: string): string {\n return basename(path) || path;\n}\n\n/** Names past this point are noise in a summary line; structuredContent holds them all. */\nconst MAX_ROSTER_ITEMS = 20;\n\n/**\n * Join a per-path summary roster, capped. A 1000-path delete would otherwise\n * name every entry in the text block that `structuredContent` already carries\n * in full.\n */\nexport function joinRoster(items: readonly string[], separator = ' · '): string {\n if (items.length <= MAX_ROSTER_ITEMS) return items.join(separator);\n const shown = items.slice(0, MAX_ROSTER_ITEMS).join(separator);\n return `${shown}${separator}+${String(items.length - MAX_ROSTER_ITEMS)} more`;\n}\n\nexport function truncateProgressPattern(pattern: string, maxLength = 40): string {\n return pattern.length <= maxLength ? pattern : `${pattern.slice(0, maxLength)}…`;\n}\n\n/**\n * `stoppedReason` names the engine's own cap, and `maxResults` is also the name\n * of the caller's page-size argument — spelling the cap out keeps a caller who\n * passed `maxResults: 5` from reading their own argument back.\n */\nconst STOP_REASON_TEXT: Record<string, string> = {\n maxResults: `hit the server's ${String(MAX_SEARCH_RESULTS)}-result scan cap, not your maxResults`,\n timeout: 'hit the time limit, or the request was cancelled',\n};\n\n/**\n * The `//` lines a paged search appends to its text block. Paging and the\n * engine's stop state live in the structured half, which `defineTool` ships\n * under `_meta` for a tool that authors its own text — and no client renders\n * that. These lines are the only place a caller learns that more remains or\n * that the scan was cut. They are independent: a scan can stop early with too\n * few results to page, so a truncation with no cursor must still say so.\n * Prefixed `//` so neither can be mistaken for a result row.\n */\nexport function pageTrailer(p: {\n offset: number;\n shown: number;\n total: number;\n noun: string;\n tool: string;\n nextCursor?: string | undefined;\n stoppedReason?: string | undefined;\n}): string {\n const lines: string[] = [];\n // Position is owed on every page of a split set, including the last one —\n // which has no cursor and would otherwise read as the whole answer.\n if (p.offset > 0 || p.total > p.shown) {\n const next =\n p.nextCursor === undefined\n ? ''\n : ` Next page: ${p.tool} ${JSON.stringify({ cursor: p.nextCursor })}`;\n lines.push(\n `// showing ${String(p.offset + 1)}-${String(p.offset + p.shown)} of ${String(p.total)} ${p.noun}.${next}`,\n );\n }\n if (p.stoppedReason !== undefined) {\n const cause = STOP_REASON_TEXT[p.stoppedReason] ?? `stopped (${p.stoppedReason})`;\n lines.push(\n `// scan stopped early: ${cause}. That total is a floor, not the count. Narrow path or pattern for the rest.`,\n );\n }\n return lines.length > 0 ? `\\n\\n${lines.join('\\n')}` : '';\n}\n"]}
|
package/dist/core/fs.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Stats } from 'node:fs';
|
|
2
2
|
import type { FileHandle } from 'node:fs/promises';
|
|
3
3
|
import { cp as fsCp, mkdir as fsMkdir, readlink as fsReadlink, rm as fsRm, rmdir as fsRmdir } from 'node:fs/promises';
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
6
|
-
import type { ReadFileResult, ReadSpec } from './read.
|
|
4
|
+
import type { EntryType as FileType } from './path-utils.ts';
|
|
5
|
+
import type { PathGuard } from './path.ts';
|
|
6
|
+
import type { ReadFileResult, ReadSpec } from './read.ts';
|
|
7
7
|
export type { FileType };
|
|
8
8
|
export type { Stats };
|
|
9
9
|
export type { FileHandle };
|
package/dist/core/fs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/core/fs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAEL,EAAE,IAAI,IAAI,EAEV,KAAK,IAAI,OAAO,EAIhB,QAAQ,IAAI,UAAU,EAEtB,EAAE,IAAI,IAAI,EACV,KAAK,IAAI,OAAO,EAIjB,MAAM,kBAAkB,CAAC;AAO1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/core/fs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAEL,EAAE,IAAI,IAAI,EAEV,KAAK,IAAI,OAAO,EAIhB,QAAQ,IAAI,UAAU,EAEtB,EAAE,IAAI,IAAI,EACV,KAAK,IAAI,OAAO,EAIjB,MAAM,kBAAkB,CAAC;AAO1B,OAAO,KAAK,EAAE,SAAS,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI1D,YAAY,EAAE,QAAQ,EAAE,CAAC;AACzB,YAAY,EAAE,KAAK,EAAE,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,CAAC;AA8E3B,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAKD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB5F;AAED,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;gBAElB,SAAS,EAAE,SAAS;IAI1B,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAMzC,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAMzC,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,GACzC,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAU/C,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAMvD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IASzF,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAO,GAC5E,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAIjC;;;;;OAKG;IACG,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,cAAc,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAO,GAC5E,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAgEjC;;;;OAIG;IACG,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;KAAO,GACjD,OAAO,CAAC,MAAM,CAAC;IAaZ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1F,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,GACtC,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAM3B,EAAE,CACN,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAShD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC;IAOnE,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAChD,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IAmB1D,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAmB9D,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAS3C,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IAOjE,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAa9D;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAalB"}
|
package/dist/core/fs.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { chmod as fsChmod, cp as fsCp, lstat as fsLstat, mkdir as fsMkdir, open as fsOpen, opendir as fsOpendir, readFile as fsReadFile, readlink as fsReadlink, rename as fsRename, rm as fsRm, rmdir as fsRmdir, stat as fsStat, unlink as fsUnlink, writeFile as fsWriteFile, } from 'node:fs/promises';
|
|
3
3
|
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
4
|
-
import { withAbort } from
|
|
5
|
-
import { ErrorCode, formatUnknownErrorMessage, FsError, isFsError, isNodeError } from
|
|
6
|
-
import { detectMimeFromContent } from
|
|
7
|
-
import { Logger } from
|
|
8
|
-
import { assertFileStats, createTooLargeError,
|
|
9
|
-
import { getMaxTextFileSize } from
|
|
4
|
+
import { withAbort } from "./concurrency.js";
|
|
5
|
+
import { ErrorCode, formatUnknownErrorMessage, FsError, isFsError, isNodeError } from "./errors.js";
|
|
6
|
+
import { detectMimeFromContent } from "./mime.js";
|
|
7
|
+
import { Logger } from "./observability.js";
|
|
8
|
+
import { assertFileStats, createTooLargeError, readFileWithStats } from "./read.js";
|
|
9
|
+
import { getMaxTextFileSize } from "./util.js";
|
|
10
10
|
// ─── Domain primitives ────────────────────────────────────────────────────────
|
|
11
11
|
/**
|
|
12
12
|
* validatePathForWrite + symlink resolution: a write aimed at a link must land
|
|
@@ -263,11 +263,10 @@ export class GuardedFileSystem {
|
|
|
263
263
|
return { validSource, validDest };
|
|
264
264
|
}
|
|
265
265
|
async readFile(filePath, spec) {
|
|
266
|
-
|
|
266
|
+
spec.signal?.throwIfAborted();
|
|
267
267
|
const validPath = await this.pathGuard.validateExistingPath(filePath);
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return readNormalized(filePath, validPath, stats, normalized);
|
|
268
|
+
const stats = await withAbort(fsStat(validPath), spec.signal);
|
|
269
|
+
return readFileWithStats(filePath, validPath, stats, spec);
|
|
271
270
|
}
|
|
272
271
|
async readEditableText(filePath, options) {
|
|
273
272
|
const { stats, validPath } = await this.stat(filePath, options);
|