@j0hanz/filesystem-mcp 1.19.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +333 -838
- package/dist/cli-help.d.ts +3 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +169 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.d.ts +28 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +168 -123
- package/dist/cli.js.map +1 -0
- package/dist/core/concurrency.d.ts +70 -0
- package/dist/core/concurrency.d.ts.map +1 -0
- package/dist/core/concurrency.js +173 -0
- package/dist/core/concurrency.js.map +1 -0
- package/dist/core/config.d.ts +19 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +11 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/cursor.d.ts +23 -0
- package/dist/core/cursor.d.ts.map +1 -0
- package/dist/core/cursor.js +62 -0
- package/dist/core/cursor.js.map +1 -0
- package/dist/core/errors.d.ts +96 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +356 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/file-uri.d.ts +24 -0
- package/dist/core/file-uri.d.ts.map +1 -0
- package/dist/core/file-uri.js +52 -0
- package/dist/core/file-uri.js.map +1 -0
- package/dist/core/fmt.d.ts +38 -0
- package/dist/core/fmt.d.ts.map +1 -0
- package/dist/core/fmt.js +109 -0
- package/dist/core/fmt.js.map +1 -0
- package/dist/core/fs.d.ts +108 -0
- package/dist/core/fs.d.ts.map +1 -0
- package/dist/core/fs.js +243 -0
- package/dist/core/fs.js.map +1 -0
- package/dist/core/glob.d.ts +41 -0
- package/dist/core/glob.d.ts.map +1 -0
- package/dist/core/glob.js +399 -0
- package/dist/core/glob.js.map +1 -0
- package/dist/core/input-required.d.ts +147 -0
- package/dist/core/input-required.d.ts.map +1 -0
- package/dist/core/input-required.js +261 -0
- package/dist/core/input-required.js.map +1 -0
- package/dist/core/mime.d.ts +15 -0
- package/dist/core/mime.d.ts.map +1 -0
- package/dist/core/mime.js +188 -0
- package/dist/core/mime.js.map +1 -0
- package/dist/core/observability.d.ts +10 -0
- package/dist/core/observability.d.ts.map +1 -0
- package/dist/core/observability.js +76 -0
- package/dist/core/observability.js.map +1 -0
- package/dist/core/page-store.d.ts +41 -0
- package/dist/core/page-store.d.ts.map +1 -0
- package/dist/core/page-store.js +74 -0
- package/dist/core/page-store.js.map +1 -0
- package/dist/core/path-completer.d.ts +10 -0
- package/dist/core/path-completer.d.ts.map +1 -0
- package/dist/core/path-completer.js +227 -0
- package/dist/core/path-completer.js.map +1 -0
- package/dist/core/path-discovery.d.ts +8 -0
- package/dist/core/path-discovery.d.ts.map +1 -0
- package/dist/core/path-discovery.js +105 -0
- package/dist/core/path-discovery.js.map +1 -0
- package/dist/core/path-utils.d.ts +9 -0
- package/dist/core/path-utils.d.ts.map +1 -0
- package/dist/core/path-utils.js +121 -0
- package/dist/core/path-utils.js.map +1 -0
- package/dist/core/path.d.ts +148 -0
- package/dist/core/path.d.ts.map +1 -0
- package/dist/core/path.js +674 -0
- package/dist/core/path.js.map +1 -0
- package/dist/core/primitives.d.ts +23 -0
- package/dist/core/primitives.d.ts.map +1 -0
- package/dist/core/primitives.js +54 -0
- package/dist/core/primitives.js.map +1 -0
- package/dist/core/read.d.ts +74 -0
- package/dist/core/read.d.ts.map +1 -0
- package/dist/core/read.js +562 -0
- package/dist/core/read.js.map +1 -0
- package/dist/core/schema.d.ts +139 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +345 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/search.d.ts +100 -0
- package/dist/core/search.d.ts.map +1 -0
- package/dist/core/search.js +248 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/sensitive.d.ts +6 -0
- package/dist/core/sensitive.d.ts.map +1 -0
- package/dist/core/sensitive.js +142 -0
- package/dist/core/sensitive.js.map +1 -0
- package/dist/core/store.d.ts +57 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +162 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/util.d.ts +26 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/core/util.js +66 -0
- package/dist/core/util.js.map +1 -0
- package/dist/core/watcher-registry.d.ts +68 -0
- package/dist/core/watcher-registry.d.ts.map +1 -0
- package/dist/core/watcher-registry.js +312 -0
- package/dist/core/watcher-registry.js.map +1 -0
- package/dist/http-policy.d.ts +121 -0
- package/dist/http-policy.d.ts.map +1 -0
- package/dist/http-policy.js +340 -0
- package/dist/http-policy.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -41
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +12 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +71 -0
- package/dist/instructions.js.map +1 -0
- package/dist/prompts.d.ts +8 -6
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +74 -168
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +73 -9
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +392 -163
- package/dist/resources.js.map +1 -0
- package/dist/server.d.ts +62 -1
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +139 -1
- package/dist/server.js.map +1 -0
- package/dist/tools/batch.d.ts +89 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +157 -0
- package/dist/tools/batch.js.map +1 -0
- package/dist/tools/create.d.ts +2 -0
- package/dist/tools/create.d.ts.map +1 -0
- package/dist/tools/create.js +142 -0
- package/dist/tools/create.js.map +1 -0
- package/dist/tools/define.d.ts +110 -0
- package/dist/tools/define.d.ts.map +1 -0
- package/dist/tools/define.js +394 -0
- package/dist/tools/define.js.map +1 -0
- package/dist/tools/delete-file.d.ts +2 -4
- package/dist/tools/delete-file.d.ts.map +1 -0
- package/dist/tools/delete-file.js +330 -87
- package/dist/tools/delete-file.js.map +1 -0
- package/dist/tools/diff.d.ts +2 -0
- package/dist/tools/diff.d.ts.map +1 -0
- package/dist/tools/diff.js +94 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +442 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/index.d.ts +26 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list.d.ts +2 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +291 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/move.d.ts +2 -0
- package/dist/tools/move.d.ts.map +1 -0
- package/dist/tools/move.js +321 -0
- package/dist/tools/move.js.map +1 -0
- package/dist/tools/patch.d.ts +2 -0
- package/dist/tools/patch.d.ts.map +1 -0
- package/dist/tools/patch.js +155 -0
- package/dist/tools/patch.js.map +1 -0
- package/dist/tools/progress.d.ts +52 -0
- package/dist/tools/progress.d.ts.map +1 -0
- package/dist/tools/progress.js +172 -0
- package/dist/tools/progress.js.map +1 -0
- package/dist/tools/read.d.ts +2 -4
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +398 -152
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/replace-in-files.d.ts +2 -4
- package/dist/tools/replace-in-files.d.ts.map +1 -0
- package/dist/tools/replace-in-files.js +435 -264
- package/dist/tools/replace-in-files.js.map +1 -0
- package/dist/tools/roots.d.ts +2 -4
- package/dist/tools/roots.d.ts.map +1 -0
- package/dist/tools/roots.js +29 -52
- package/dist/tools/roots.js.map +1 -0
- package/dist/tools/search-content.d.ts +2 -4
- package/dist/tools/search-content.d.ts.map +1 -0
- package/dist/tools/search-content.js +262 -228
- package/dist/tools/search-content.js.map +1 -0
- package/dist/tools/search-files.d.ts +2 -4
- package/dist/tools/search-files.d.ts.map +1 -0
- package/dist/tools/search-files.js +162 -161
- package/dist/tools/search-files.js.map +1 -0
- package/dist/tools/stat.d.ts +2 -4
- package/dist/tools/stat.d.ts.map +1 -0
- package/dist/tools/stat.js +202 -62
- package/dist/tools/stat.js.map +1 -0
- package/dist/transport/http.d.ts +5 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +276 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/shared.d.ts +45 -0
- package/dist/transport/shared.d.ts.map +1 -0
- package/dist/transport/shared.js +65 -0
- package/dist/transport/shared.js.map +1 -0
- package/dist/transport/stdio.d.ts +32 -0
- package/dist/transport/stdio.d.ts.map +1 -0
- package/dist/transport/stdio.js +279 -0
- package/dist/transport/stdio.js.map +1 -0
- package/dist/transport.d.ts +5 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +4 -0
- package/dist/transport.js.map +1 -0
- package/package.json +37 -46
- package/dist/assets/logo.svg +0 -35
- package/dist/completions.d.ts +0 -2
- package/dist/completions.js +0 -572
- package/dist/config.d.ts +0 -119
- package/dist/config.js +0 -31
- package/dist/lib/abort.d.ts +0 -7
- package/dist/lib/abort.js +0 -81
- package/dist/lib/constants.d.ts +0 -42
- package/dist/lib/constants.js +0 -313
- package/dist/lib/errors.d.ts +0 -28
- package/dist/lib/errors.js +0 -301
- package/dist/lib/file-operations/core.d.ts +0 -53
- package/dist/lib/file-operations/core.js +0 -144
- package/dist/lib/file-operations/metadata.d.ts +0 -77
- package/dist/lib/file-operations/metadata.js +0 -878
- package/dist/lib/file-operations/search.d.ts +0 -46
- package/dist/lib/file-operations/search.js +0 -1194
- package/dist/lib/file-operations/traversal.d.ts +0 -40
- package/dist/lib/file-operations/traversal.js +0 -310
- package/dist/lib/fs-helpers.d.ts +0 -46
- package/dist/lib/fs-helpers.js +0 -606
- package/dist/lib/globs.d.ts +0 -2
- package/dist/lib/globs.js +0 -19
- package/dist/lib/logger.d.ts +0 -27
- package/dist/lib/logger.js +0 -91
- package/dist/lib/observability.d.ts +0 -33
- package/dist/lib/observability.js +0 -373
- package/dist/lib/paths.d.ts +0 -35
- package/dist/lib/paths.js +0 -634
- package/dist/lib/resource-store.d.ts +0 -28
- package/dist/lib/resource-store.js +0 -195
- package/dist/lib/utils.d.ts +0 -7
- package/dist/lib/utils.js +0 -37
- package/dist/lib/zod-codecs.d.ts +0 -2
- package/dist/lib/zod-codecs.js +0 -18
- package/dist/pkg-info.d.ts +0 -7
- package/dist/pkg-info.js +0 -9
- package/dist/resources/generated-instructions.d.ts +0 -1
- package/dist/resources/generated-instructions.js +0 -105
- package/dist/resources/tool-catalog.d.ts +0 -2
- package/dist/resources/tool-catalog.js +0 -78
- package/dist/resources/tool-info.d.ts +0 -9
- package/dist/resources/tool-info.js +0 -206
- package/dist/resources/workflows.d.ts +0 -1
- package/dist/resources/workflows.js +0 -72
- package/dist/schemas.d.ts +0 -505
- package/dist/schemas.js +0 -676
- package/dist/server/bootstrap.d.ts +0 -6
- package/dist/server/bootstrap.js +0 -585
- package/dist/server/event-store.d.ts +0 -18
- package/dist/server/event-store.js +0 -71
- package/dist/server/roots-manager.d.ts +0 -28
- package/dist/server/roots-manager.js +0 -227
- package/dist/server/task-store.d.ts +0 -10
- package/dist/server/task-store.js +0 -91
- package/dist/tools/apply-patch.d.ts +0 -4
- package/dist/tools/apply-patch.js +0 -235
- package/dist/tools/calculate-hash.d.ts +0 -4
- package/dist/tools/calculate-hash.js +0 -187
- package/dist/tools/contract.d.ts +0 -50
- package/dist/tools/contract.js +0 -1
- package/dist/tools/create-directory.d.ts +0 -4
- package/dist/tools/create-directory.js +0 -68
- package/dist/tools/diff-files.d.ts +0 -4
- package/dist/tools/diff-files.js +0 -136
- package/dist/tools/edit-file.d.ts +0 -4
- package/dist/tools/edit-file.js +0 -256
- package/dist/tools/icons.d.ts +0 -15
- package/dist/tools/icons.js +0 -24
- package/dist/tools/list-directory.d.ts +0 -4
- package/dist/tools/list-directory.js +0 -218
- package/dist/tools/move-file.d.ts +0 -4
- package/dist/tools/move-file.js +0 -178
- package/dist/tools/read-multiple.d.ts +0 -4
- package/dist/tools/read-multiple.js +0 -207
- package/dist/tools/shared.d.ts +0 -172
- package/dist/tools/shared.js +0 -599
- package/dist/tools/stat-many.d.ts +0 -4
- package/dist/tools/stat-many.js +0 -104
- package/dist/tools/task-support.d.ts +0 -29
- package/dist/tools/task-support.js +0 -473
- package/dist/tools/tree.d.ts +0 -4
- package/dist/tools/tree.js +0 -102
- package/dist/tools/write-file.d.ts +0 -4
- package/dist/tools/write-file.js +0 -60
- package/dist/tools.d.ts +0 -5
- package/dist/tools.js +0 -54
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fmt.js","sourceRoot":"","sources":["../../src/core/fmt.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename } from 'node:path';\nimport { stripVTControlCharacters, styleText } from 'node:util';\n\nimport { GIB, KIB, MIB } from './util.js';\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\nexport type Phase = 'start' | '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 'start':\n if (ctx.scope) {\n items.push(ctx.scope);\n }\n break;\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 formatBytes(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes < 0) {\n return '0 B';\n }\n if (bytes < KIB) {\n return `${bytes} B`;\n }\n if (bytes < MIB) {\n return `${(bytes / KIB).toFixed(1)} KB`;\n }\n if (bytes < GIB) {\n return `${(bytes / MIB).toFixed(1)} MB`;\n }\n return `${(bytes / GIB).toFixed(1)} GB`;\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// CLI color helpers\n// ---------------------------------------------------------------------------\n\nfunction isColorEnabled(stream: { isTTY?: boolean } = process.stdout): boolean {\n return stream.isTTY === true && !process.env['NO_COLOR'];\n}\n\nexport function padEndVisible(s: string, width: number): string {\n const visible = stripVTControlCharacters(s).length;\n return visible >= width ? s : s + ' '.repeat(width - visible);\n}\n\ntype Style = Parameters<typeof styleText>[0];\n\n/** Same palette as above, but only when the target stream wants color. */\nfunction tint(format: Style, text: string, stream?: { isTTY?: boolean }): string {\n return isColorEnabled(stream) ? styleText(format, text) : text;\n}\n\nexport const cliFmt = {\n bold: (t: string) => tint('bold', t),\n dim: (t: string) => tint('dim', t),\n cyan: (t: string) => tint('cyan', t),\n yellow: (t: string) => tint('yellow', t),\n flag: (t: string) => tint('green', t),\n placeholder: (t: string) => tint('yellow', t),\n section: (t: string) => tint(['cyan', 'bold'], t),\n bool: (v: boolean) => (v ? tint('green', 'true') : tint('red', 'false')),\n};\n"]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { ReadStream, Stats } from 'node:fs';
|
|
2
|
+
import { createReadStream } from 'node:fs';
|
|
3
|
+
import type { FileHandle } from 'node:fs/promises';
|
|
4
|
+
import { cp as fsCp, mkdir as fsMkdir, readlink as fsReadlink, rm as fsRm, rmdir as fsRmdir } from 'node:fs/promises';
|
|
5
|
+
import type { PathGuard } from './path.js';
|
|
6
|
+
import type { EntryType as FileType } from './primitives.js';
|
|
7
|
+
import type { ReadFileResult, ReadSpec } from './read.js';
|
|
8
|
+
export type { FileType };
|
|
9
|
+
export type { Stats, ReadStream };
|
|
10
|
+
export type { FileHandle };
|
|
11
|
+
export interface FileInfo {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly path: string;
|
|
14
|
+
readonly type: FileType;
|
|
15
|
+
readonly size: number;
|
|
16
|
+
readonly tokenEstimate?: number;
|
|
17
|
+
readonly created: Date;
|
|
18
|
+
readonly modified: Date;
|
|
19
|
+
readonly accessed: Date;
|
|
20
|
+
readonly permissions: string;
|
|
21
|
+
readonly isHidden: boolean;
|
|
22
|
+
readonly mimeType?: string;
|
|
23
|
+
readonly symlinkTarget?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function getFileType(stats: Stats): FileType;
|
|
26
|
+
export declare function isHidden(name: string): boolean;
|
|
27
|
+
export declare class GuardedFileSystem {
|
|
28
|
+
readonly pathGuard: PathGuard;
|
|
29
|
+
constructor(pathGuard: PathGuard);
|
|
30
|
+
stat(filePath: string, options?: {
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
stats: Stats;
|
|
34
|
+
validPath: string;
|
|
35
|
+
}>;
|
|
36
|
+
lstat(filePath: string, options?: {
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
stats: Stats;
|
|
40
|
+
validPath: string;
|
|
41
|
+
}>;
|
|
42
|
+
readlink(filePath: string, options?: Parameters<typeof fsReadlink>[1]): Promise<{
|
|
43
|
+
linkString: string;
|
|
44
|
+
validPath: string;
|
|
45
|
+
}>;
|
|
46
|
+
mkdir(filePath: string, options?: Parameters<typeof fsMkdir>[1]): Promise<{
|
|
47
|
+
validPath: string;
|
|
48
|
+
result: string | undefined;
|
|
49
|
+
}>;
|
|
50
|
+
rename(oldPath: string, newPath: string): Promise<{
|
|
51
|
+
validOld: string;
|
|
52
|
+
validNew: string;
|
|
53
|
+
}>;
|
|
54
|
+
writeFile(filePath: string, content: string, options?: {
|
|
55
|
+
encoding?: BufferEncoding;
|
|
56
|
+
signal?: AbortSignal | undefined;
|
|
57
|
+
}): Promise<{
|
|
58
|
+
validPath: string;
|
|
59
|
+
}>;
|
|
60
|
+
rm(filePath: string, options?: Parameters<typeof fsRm>[1]): Promise<{
|
|
61
|
+
validPath: string;
|
|
62
|
+
}>;
|
|
63
|
+
rmdir(filePath: string, options?: Parameters<typeof fsRmdir>[1]): Promise<{
|
|
64
|
+
validPath: string;
|
|
65
|
+
}>;
|
|
66
|
+
cp(source: string, destination: string, options?: Parameters<typeof fsCp>[2]): Promise<{
|
|
67
|
+
validSource: string;
|
|
68
|
+
validDest: string;
|
|
69
|
+
}>;
|
|
70
|
+
hash(filePath: string, signal?: AbortSignal): Promise<string>;
|
|
71
|
+
readFile(filePath: string, spec: ReadSpec): Promise<ReadFileResult>;
|
|
72
|
+
readEditableText(filePath: string, options?: {
|
|
73
|
+
signal?: AbortSignal;
|
|
74
|
+
tool?: string;
|
|
75
|
+
}): Promise<{
|
|
76
|
+
validPath: string;
|
|
77
|
+
content: string;
|
|
78
|
+
stats: Stats;
|
|
79
|
+
}>;
|
|
80
|
+
readRaw(filePath: string, options?: {
|
|
81
|
+
signal?: AbortSignal;
|
|
82
|
+
}): Promise<{
|
|
83
|
+
content: Buffer;
|
|
84
|
+
mimeType: string;
|
|
85
|
+
isBinary: boolean;
|
|
86
|
+
}>;
|
|
87
|
+
open(filePath: string, flags: string | number, mode?: string | number): Promise<FileHandle>;
|
|
88
|
+
createReadStream(filePath: string, options?: Parameters<typeof createReadStream>[1]): Promise<ReadStream>;
|
|
89
|
+
statDetailed(filePath: string, options?: {
|
|
90
|
+
signal?: AbortSignal;
|
|
91
|
+
}): Promise<{
|
|
92
|
+
requestedPath: string;
|
|
93
|
+
isSymlink: boolean;
|
|
94
|
+
stats: Stats;
|
|
95
|
+
}>;
|
|
96
|
+
hasChildrenUnchecked(dirPath: string): Promise<boolean>;
|
|
97
|
+
}
|
|
98
|
+
export interface StatPath {
|
|
99
|
+
stat(filePath: string, options?: {
|
|
100
|
+
signal?: AbortSignal;
|
|
101
|
+
}): Promise<unknown>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Returns whether `path` exists, treating "not found" as absent and logging any
|
|
105
|
+
* other stat failure. Used for TOCTOU re-checks between plan and execute phases.
|
|
106
|
+
*/
|
|
107
|
+
export declare function destExists(fs: StatPath, path: string, label: string): Promise<boolean>;
|
|
108
|
+
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/core/fs.ts"],"names":[],"mappings":"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"}
|
package/dist/core/fs.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { createReadStream, constants as fsConstants } from 'node:fs';
|
|
3
|
+
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';
|
|
4
|
+
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
5
|
+
import { pipeline } from 'node:stream/promises';
|
|
6
|
+
import { withAbort } from './concurrency.js';
|
|
7
|
+
import { ErrorCode, formatUnknownErrorMessage, FsError, isFsError, isNodeError } from './errors.js';
|
|
8
|
+
import { detectMimeFromContent } from './mime.js';
|
|
9
|
+
import { Logger } from './observability.js';
|
|
10
|
+
import { assertFileStats, createTooLargeError, normalizeSpec, readFileWithStats, readNormalized, STREAM_CHUNK_SIZE, } from './read.js';
|
|
11
|
+
import { getMaxTextFileSize } from './util.js';
|
|
12
|
+
// ─── File hashing ────────────────────────────────────────────────────────────
|
|
13
|
+
async function calculateFileContentHash(filePath, signal) {
|
|
14
|
+
const hasher = createHash('sha256');
|
|
15
|
+
await pipeline(createReadStream(filePath, { signal, highWaterMark: STREAM_CHUNK_SIZE }), hasher, {
|
|
16
|
+
signal,
|
|
17
|
+
});
|
|
18
|
+
return hasher.digest('hex');
|
|
19
|
+
}
|
|
20
|
+
async function atomicWriteFile(filePath, content, pathGuard, options = {}) {
|
|
21
|
+
const { encoding = 'utf-8', signal } = options;
|
|
22
|
+
let validPath = await pathGuard.validatePathForWrite(filePath);
|
|
23
|
+
try {
|
|
24
|
+
const stats = await fsLstat(validPath);
|
|
25
|
+
if (stats.isSymbolicLink()) {
|
|
26
|
+
const target = await fsReadlink(validPath);
|
|
27
|
+
const resolvedTarget = isAbsolute(target) ? target : resolve(dirname(validPath), target);
|
|
28
|
+
validPath = await pathGuard.validatePathForWrite(resolvedTarget);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (!isNodeError(error) || error.code !== 'ENOENT') {
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const tempSuffix = randomUUID().replace(/-/g, '').slice(0, 12);
|
|
37
|
+
const tempPath = `${validPath}.${tempSuffix}.tmp`;
|
|
38
|
+
// The rename below swaps in the temp file's inode, so the target would
|
|
39
|
+
// inherit fsWriteFile's default 0o666 & ~umask — silently widening a 0600
|
|
40
|
+
// file to 0644 on every write. Carry the existing mode across instead.
|
|
41
|
+
let existingMode;
|
|
42
|
+
try {
|
|
43
|
+
existingMode = (await fsStat(validPath)).mode & 0o777;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// ENOENT is the normal new-file case: the default mode is correct there.
|
|
47
|
+
// Anything else (EACCES, EIO) means the mode about to be overwritten could
|
|
48
|
+
// not be read, and the write will silently widen the file — say so rather
|
|
49
|
+
// than swallowing it.
|
|
50
|
+
if (!isNodeError(error) || error.code !== 'ENOENT') {
|
|
51
|
+
Logger.warn(`atomicWriteFile: cannot read the existing mode of ${validPath}; the write will use the default mode: ${formatUnknownErrorMessage(error)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
signal?.throwIfAborted();
|
|
56
|
+
await fsWriteFile(tempPath, content, { encoding, signal });
|
|
57
|
+
if (existingMode !== undefined) {
|
|
58
|
+
await fsChmod(tempPath, existingMode);
|
|
59
|
+
}
|
|
60
|
+
await withAbort(fsRename(tempPath, validPath), signal);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
try {
|
|
64
|
+
await fsUnlink(tempPath);
|
|
65
|
+
}
|
|
66
|
+
catch (cleanupError) {
|
|
67
|
+
Logger.warn(`Failed to clean up temp file ${tempPath} after write error (${formatUnknownErrorMessage(error)}): ${formatUnknownErrorMessage(cleanupError)}`);
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
return { validPath };
|
|
72
|
+
}
|
|
73
|
+
export function getFileType(stats) {
|
|
74
|
+
if (stats.isFile())
|
|
75
|
+
return 'file';
|
|
76
|
+
if (stats.isDirectory())
|
|
77
|
+
return 'directory';
|
|
78
|
+
if (stats.isSymbolicLink())
|
|
79
|
+
return 'symlink';
|
|
80
|
+
return 'other';
|
|
81
|
+
}
|
|
82
|
+
export function isHidden(name) {
|
|
83
|
+
return name.startsWith('.');
|
|
84
|
+
}
|
|
85
|
+
export class GuardedFileSystem {
|
|
86
|
+
pathGuard;
|
|
87
|
+
constructor(pathGuard) {
|
|
88
|
+
this.pathGuard = pathGuard;
|
|
89
|
+
}
|
|
90
|
+
async stat(filePath, options) {
|
|
91
|
+
const validPath = await this.pathGuard.validateExistingPath(filePath);
|
|
92
|
+
const stats = await withAbort(fsStat(validPath), options?.signal);
|
|
93
|
+
return { stats, validPath };
|
|
94
|
+
}
|
|
95
|
+
async lstat(filePath, options) {
|
|
96
|
+
const validPath = await this.pathGuard.validatePathForDelete(filePath);
|
|
97
|
+
const stats = await withAbort(fsLstat(validPath), options?.signal);
|
|
98
|
+
return { stats, validPath };
|
|
99
|
+
}
|
|
100
|
+
async readlink(filePath, options) {
|
|
101
|
+
// validateExistingPath resolves through the symlink, so readlink would always
|
|
102
|
+
// be handed the final target — a regular file — and fail EINVAL. This guard
|
|
103
|
+
// keeps the link itself while still enforcing containment and the denylist.
|
|
104
|
+
const validPath = await this.pathGuard.validatePathForDelete(filePath);
|
|
105
|
+
const raw = await fsReadlink(validPath, options);
|
|
106
|
+
const linkString = Buffer.isBuffer(raw) ? raw.toString('utf-8') : raw;
|
|
107
|
+
return { linkString, validPath };
|
|
108
|
+
}
|
|
109
|
+
async mkdir(filePath, options) {
|
|
110
|
+
const validPath = await this.pathGuard.validatePathForWrite(filePath);
|
|
111
|
+
const result = await fsMkdir(validPath, options);
|
|
112
|
+
return { validPath, result };
|
|
113
|
+
}
|
|
114
|
+
async rename(oldPath, newPath) {
|
|
115
|
+
// Not validateExistingPath: that resolves through a symlink, so renaming a
|
|
116
|
+
// link would rename its target and leave the link dangling.
|
|
117
|
+
const validOld = await this.pathGuard.validatePathForDelete(oldPath);
|
|
118
|
+
const validNew = await this.pathGuard.validatePathForWrite(newPath);
|
|
119
|
+
await fsRename(validOld, validNew);
|
|
120
|
+
return { validOld, validNew };
|
|
121
|
+
}
|
|
122
|
+
async writeFile(filePath, content, options = {}) {
|
|
123
|
+
return atomicWriteFile(filePath, content, this.pathGuard, options);
|
|
124
|
+
}
|
|
125
|
+
async rm(filePath, options) {
|
|
126
|
+
const validPath = await this.pathGuard.validatePathForDelete(filePath);
|
|
127
|
+
await fsRm(validPath, options);
|
|
128
|
+
return { validPath };
|
|
129
|
+
}
|
|
130
|
+
async rmdir(filePath, options) {
|
|
131
|
+
const validPath = await this.pathGuard.validatePathForDelete(filePath);
|
|
132
|
+
await fsRmdir(validPath, options);
|
|
133
|
+
return { validPath };
|
|
134
|
+
}
|
|
135
|
+
async cp(source, destination, options) {
|
|
136
|
+
// As in rename: keep the link itself so callers passing verbatimSymlinks
|
|
137
|
+
// actually copy the link rather than a dereferenced target.
|
|
138
|
+
const validSource = await this.pathGuard.validatePathForDelete(source);
|
|
139
|
+
const validDest = await this.pathGuard.validatePathForWrite(destination);
|
|
140
|
+
await fsCp(validSource, validDest, options);
|
|
141
|
+
return { validSource, validDest };
|
|
142
|
+
}
|
|
143
|
+
async hash(filePath, signal) {
|
|
144
|
+
// For hashing, we require the path to exist and be a file, so we use the stricter existing-path guard.
|
|
145
|
+
const validPath = await this.pathGuard.validateExistingPath(filePath);
|
|
146
|
+
return calculateFileContentHash(validPath, signal);
|
|
147
|
+
}
|
|
148
|
+
async readFile(filePath, spec) {
|
|
149
|
+
const normalized = normalizeSpec(spec);
|
|
150
|
+
const validPath = await this.pathGuard.validateExistingPath(filePath);
|
|
151
|
+
normalized.signal?.throwIfAborted();
|
|
152
|
+
const stats = await withAbort(fsStat(validPath), normalized.signal);
|
|
153
|
+
return readNormalized(filePath, validPath, stats, normalized);
|
|
154
|
+
}
|
|
155
|
+
async readEditableText(filePath, options) {
|
|
156
|
+
const { stats, validPath } = await this.stat(filePath, options);
|
|
157
|
+
const maxSize = getMaxTextFileSize();
|
|
158
|
+
if (stats.size > maxSize) {
|
|
159
|
+
// `tool` labels the TOO_LARGE message so the client sees which tool refused.
|
|
160
|
+
throw new FsError(ErrorCode.TOO_LARGE, `File too large for ${options?.tool ?? 'edit'} (${stats.size} bytes > ${maxSize} bytes)`, filePath, { size: stats.size, maxFileSize: maxSize });
|
|
161
|
+
}
|
|
162
|
+
const { content } = await readFileWithStats(filePath, validPath, stats, {
|
|
163
|
+
kind: 'full',
|
|
164
|
+
encoding: 'utf-8',
|
|
165
|
+
maxSize,
|
|
166
|
+
skipBinary: true,
|
|
167
|
+
...(options?.signal ? { signal: options.signal } : {}),
|
|
168
|
+
});
|
|
169
|
+
return { validPath, content, stats };
|
|
170
|
+
}
|
|
171
|
+
async readRaw(filePath, options) {
|
|
172
|
+
const validPath = await this.pathGuard.validateExistingPath(filePath);
|
|
173
|
+
const stats = await withAbort(fsStat(validPath), options?.signal);
|
|
174
|
+
assertFileStats(filePath, stats);
|
|
175
|
+
// Enforce size limit before reading to avoid loading large files into memory.
|
|
176
|
+
// Binary detection is best-effort, but this is a hard limit.
|
|
177
|
+
const maxTextFileSize = getMaxTextFileSize();
|
|
178
|
+
if (stats.size > maxTextFileSize) {
|
|
179
|
+
throw createTooLargeError(stats.size, maxTextFileSize, filePath);
|
|
180
|
+
}
|
|
181
|
+
const content = await withAbort(fsReadFile(validPath), options?.signal);
|
|
182
|
+
const mimeInfo = detectMimeFromContent(validPath, content);
|
|
183
|
+
return {
|
|
184
|
+
content,
|
|
185
|
+
mimeType: mimeInfo.mimeType,
|
|
186
|
+
isBinary: mimeInfo.kind !== 'text',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async open(filePath, flags, mode) {
|
|
190
|
+
// Only a plain read-only open ('r' / O_RDONLY) uses the existing-path guard.
|
|
191
|
+
// Every other flag (write, append, read-write, sync, numeric) is treated as
|
|
192
|
+
// write-capable and routed through the stricter write guard.
|
|
193
|
+
const isReadOnly = flags === 'r' || flags === fsConstants.O_RDONLY;
|
|
194
|
+
const validPath = isReadOnly
|
|
195
|
+
? await this.pathGuard.validateExistingPath(filePath)
|
|
196
|
+
: await this.pathGuard.validatePathForWrite(filePath);
|
|
197
|
+
return fsOpen(validPath, flags, mode);
|
|
198
|
+
}
|
|
199
|
+
async createReadStream(filePath, options) {
|
|
200
|
+
const validPath = await this.pathGuard.validateExistingPath(filePath);
|
|
201
|
+
return createReadStream(validPath, options);
|
|
202
|
+
}
|
|
203
|
+
// Single resolution + stat: validateExistingPathDetailed resolves the real
|
|
204
|
+
// path (following symlinks, re-checking sensitivity) once, then we stat the
|
|
205
|
+
// resolved target. Replaces the tool-side validateExistingPathDetailed +
|
|
206
|
+
// fs.stat pair that re-validated through the free stat() guard.
|
|
207
|
+
async statDetailed(filePath, options) {
|
|
208
|
+
const { requestedPath, resolvedPath, isSymlink } = await this.pathGuard.validateExistingPathDetailed(filePath);
|
|
209
|
+
const stats = await withAbort(fsStat(resolvedPath), options?.signal);
|
|
210
|
+
return { requestedPath, isSymlink, stats };
|
|
211
|
+
}
|
|
212
|
+
async hasChildrenUnchecked(dirPath) {
|
|
213
|
+
const dir = await fsOpendir(dirPath);
|
|
214
|
+
try {
|
|
215
|
+
const entry = await dir.read();
|
|
216
|
+
return entry !== null;
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
await dir.close().catch((closeErr) => {
|
|
220
|
+
Logger.warn(`Failed to close dir handle for ${dirPath}: ${formatUnknownErrorMessage(closeErr)}`);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Returns whether `path` exists, treating "not found" as absent and logging any
|
|
227
|
+
* other stat failure. Used for TOCTOU re-checks between plan and execute phases.
|
|
228
|
+
*/
|
|
229
|
+
export async function destExists(fs, path, label) {
|
|
230
|
+
try {
|
|
231
|
+
await fs.stat(path);
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
const missing = (isNodeError(err) && err.code === 'ENOENT') ||
|
|
236
|
+
(isFsError(err) && err.code === ErrorCode.NOT_FOUND);
|
|
237
|
+
if (!missing) {
|
|
238
|
+
Logger.warn(`${label}: dest stat failed unexpectedly for "${path}": ${String(err)}`);
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/core/fs.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport type { ReadStream, Stats } from 'node:fs';\nimport { createReadStream, constants as fsConstants } from 'node:fs';\nimport type { FileHandle } from 'node:fs/promises';\nimport {\n chmod as fsChmod,\n cp as fsCp,\n lstat as fsLstat,\n mkdir as fsMkdir,\n open as fsOpen,\n opendir as fsOpendir,\n readFile as fsReadFile,\n readlink as fsReadlink,\n rename as fsRename,\n rm as fsRm,\n rmdir as fsRmdir,\n stat as fsStat,\n unlink as fsUnlink,\n writeFile as fsWriteFile,\n} from 'node:fs/promises';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { pipeline } from 'node:stream/promises';\n\nimport { withAbort } from './concurrency.js';\nimport { ErrorCode, formatUnknownErrorMessage, FsError, isFsError, isNodeError } from './errors.js';\nimport { detectMimeFromContent } from './mime.js';\nimport { Logger } from './observability.js';\nimport type { PathGuard } from './path.js';\nimport type { EntryType as FileType } from './primitives.js';\nimport type { ReadFileResult, ReadSpec } from './read.js';\nimport {\n assertFileStats,\n createTooLargeError,\n normalizeSpec,\n readFileWithStats,\n readNormalized,\n STREAM_CHUNK_SIZE,\n} from './read.js';\nimport { getMaxTextFileSize } from './util.js';\n\nexport type { FileType };\nexport type { Stats, ReadStream };\nexport type { FileHandle };\n\n// ─── Domain primitives ────────────────────────────────────────────────────────\n\nexport interface FileInfo {\n readonly name: string;\n readonly path: string;\n readonly type: FileType;\n readonly size: number;\n readonly tokenEstimate?: number;\n readonly created: Date;\n readonly modified: Date;\n readonly accessed: Date;\n readonly permissions: string;\n readonly isHidden: boolean;\n readonly mimeType?: string;\n readonly symlinkTarget?: string;\n}\n\n// ─── File hashing ────────────────────────────────────────────────────────────\n\nasync function calculateFileContentHash(filePath: string, signal?: AbortSignal): Promise<string> {\n const hasher = createHash('sha256');\n await pipeline(createReadStream(filePath, { signal, highWaterMark: STREAM_CHUNK_SIZE }), hasher, {\n signal,\n });\n return hasher.digest('hex');\n}\n\nasync function atomicWriteFile(\n filePath: string,\n content: string,\n pathGuard: PathGuard,\n options: { encoding?: BufferEncoding; signal?: AbortSignal | undefined } = {},\n): Promise<{ validPath: string }> {\n const { encoding = 'utf-8', signal } = options;\n let validPath = await pathGuard.validatePathForWrite(filePath);\n\n try {\n const stats = await fsLstat(validPath);\n if (stats.isSymbolicLink()) {\n const target = await fsReadlink(validPath);\n const resolvedTarget = isAbsolute(target) ? target : resolve(dirname(validPath), target);\n validPath = await pathGuard.validatePathForWrite(resolvedTarget);\n }\n } catch (error) {\n if (!isNodeError(error) || error.code !== 'ENOENT') {\n throw error;\n }\n }\n\n const tempSuffix = randomUUID().replace(/-/g, '').slice(0, 12);\n const tempPath = `${validPath}.${tempSuffix}.tmp`;\n\n // The rename below swaps in the temp file's inode, so the target would\n // inherit fsWriteFile's default 0o666 & ~umask — silently widening a 0600\n // file to 0644 on every write. Carry the existing mode across instead.\n let existingMode: number | undefined;\n try {\n existingMode = (await fsStat(validPath)).mode & 0o777;\n } catch (error) {\n // ENOENT is the normal new-file case: the default mode is correct there.\n // Anything else (EACCES, EIO) means the mode about to be overwritten could\n // not be read, and the write will silently widen the file — say so rather\n // than swallowing it.\n if (!isNodeError(error) || error.code !== 'ENOENT') {\n Logger.warn(\n `atomicWriteFile: cannot read the existing mode of ${validPath}; the write will use the default mode: ${formatUnknownErrorMessage(error)}`,\n );\n }\n }\n\n try {\n signal?.throwIfAborted();\n await fsWriteFile(tempPath, content, { encoding, signal });\n if (existingMode !== undefined) {\n await fsChmod(tempPath, existingMode);\n }\n await withAbort(fsRename(tempPath, validPath), signal);\n } catch (error) {\n try {\n await fsUnlink(tempPath);\n } catch (cleanupError) {\n Logger.warn(\n `Failed to clean up temp file ${tempPath} after write error (${formatUnknownErrorMessage(error)}): ${formatUnknownErrorMessage(cleanupError)}`,\n );\n }\n throw error;\n }\n return { validPath };\n}\n\nexport function getFileType(stats: Stats): FileType {\n if (stats.isFile()) return 'file';\n if (stats.isDirectory()) return 'directory';\n if (stats.isSymbolicLink()) return 'symlink';\n return 'other';\n}\n\nexport function isHidden(name: string): boolean {\n return name.startsWith('.');\n}\n\nexport class GuardedFileSystem {\n readonly pathGuard: PathGuard;\n\n constructor(pathGuard: PathGuard) {\n this.pathGuard = pathGuard;\n }\n\n async stat(\n filePath: string,\n options?: { signal?: AbortSignal },\n ): Promise<{ stats: Stats; validPath: string }> {\n const validPath = await this.pathGuard.validateExistingPath(filePath);\n const stats = await withAbort(fsStat(validPath), options?.signal);\n return { stats, validPath };\n }\n\n async lstat(\n filePath: string,\n options?: { signal?: AbortSignal },\n ): Promise<{ stats: Stats; validPath: string }> {\n const validPath = await this.pathGuard.validatePathForDelete(filePath);\n const stats = await withAbort(fsLstat(validPath), options?.signal);\n return { stats, validPath };\n }\n\n async readlink(\n filePath: string,\n options?: Parameters<typeof fsReadlink>[1],\n ): Promise<{ linkString: string; validPath: string }> {\n // validateExistingPath resolves through the symlink, so readlink would always\n // be handed the final target — a regular file — and fail EINVAL. This guard\n // keeps the link itself while still enforcing containment and the denylist.\n const validPath = await this.pathGuard.validatePathForDelete(filePath);\n const raw = await fsReadlink(validPath, options);\n const linkString = Buffer.isBuffer(raw) ? raw.toString('utf-8') : raw;\n return { linkString, validPath };\n }\n\n async mkdir(\n filePath: string,\n options?: Parameters<typeof fsMkdir>[1],\n ): Promise<{ validPath: string; result: string | undefined }> {\n const validPath = await this.pathGuard.validatePathForWrite(filePath);\n const result = await fsMkdir(validPath, options);\n return { validPath, result };\n }\n\n async rename(oldPath: string, newPath: string): Promise<{ validOld: string; validNew: string }> {\n // Not validateExistingPath: that resolves through a symlink, so renaming a\n // link would rename its target and leave the link dangling.\n const validOld = await this.pathGuard.validatePathForDelete(oldPath);\n const validNew = await this.pathGuard.validatePathForWrite(newPath);\n await fsRename(validOld, validNew);\n return { validOld, validNew };\n }\n\n async writeFile(\n filePath: string,\n content: string,\n options: { encoding?: BufferEncoding; signal?: AbortSignal | undefined } = {},\n ): Promise<{ validPath: string }> {\n return atomicWriteFile(filePath, content, this.pathGuard, options);\n }\n\n async rm(filePath: string, options?: Parameters<typeof fsRm>[1]): Promise<{ validPath: string }> {\n const validPath = await this.pathGuard.validatePathForDelete(filePath);\n await fsRm(validPath, options);\n return { validPath };\n }\n\n async rmdir(\n filePath: string,\n options?: Parameters<typeof fsRmdir>[1],\n ): Promise<{ validPath: string }> {\n const validPath = await this.pathGuard.validatePathForDelete(filePath);\n await fsRmdir(validPath, options);\n return { validPath };\n }\n\n async cp(\n source: string,\n destination: string,\n options?: Parameters<typeof fsCp>[2],\n ): Promise<{ validSource: string; validDest: string }> {\n // As in rename: keep the link itself so callers passing verbatimSymlinks\n // actually copy the link rather than a dereferenced target.\n const validSource = await this.pathGuard.validatePathForDelete(source);\n const validDest = await this.pathGuard.validatePathForWrite(destination);\n await fsCp(validSource, validDest, options);\n return { validSource, validDest };\n }\n\n async hash(filePath: string, signal?: AbortSignal): Promise<string> {\n // For hashing, we require the path to exist and be a file, so we use the stricter existing-path guard.\n const validPath = await this.pathGuard.validateExistingPath(filePath);\n return calculateFileContentHash(validPath, signal);\n }\n\n async readFile(filePath: string, spec: ReadSpec): Promise<ReadFileResult> {\n const normalized = normalizeSpec(spec);\n const validPath = await this.pathGuard.validateExistingPath(filePath);\n normalized.signal?.throwIfAborted();\n const stats = await withAbort(fsStat(validPath), normalized.signal);\n return readNormalized(filePath, validPath, stats, normalized);\n }\n\n async readEditableText(\n filePath: string,\n options?: { signal?: AbortSignal; tool?: string },\n ): Promise<{ validPath: string; content: string; stats: Stats }> {\n const { stats, validPath } = await this.stat(filePath, options);\n const maxSize = getMaxTextFileSize();\n if (stats.size > maxSize) {\n // `tool` labels the TOO_LARGE message so the client sees which tool refused.\n throw new FsError(\n ErrorCode.TOO_LARGE,\n `File too large for ${options?.tool ?? 'edit'} (${stats.size} bytes > ${maxSize} bytes)`,\n filePath,\n { size: stats.size, maxFileSize: maxSize },\n );\n }\n const { content } = await readFileWithStats(filePath, validPath, stats, {\n kind: 'full',\n encoding: 'utf-8',\n maxSize,\n skipBinary: true,\n ...(options?.signal ? { signal: options.signal } : {}),\n });\n return { validPath, content, stats };\n }\n\n async readRaw(\n filePath: string,\n options?: { signal?: AbortSignal },\n ): Promise<{ content: Buffer; mimeType: string; isBinary: boolean }> {\n const validPath = await this.pathGuard.validateExistingPath(filePath);\n const stats = await withAbort(fsStat(validPath), options?.signal);\n assertFileStats(filePath, stats);\n // Enforce size limit before reading to avoid loading large files into memory.\n // Binary detection is best-effort, but this is a hard limit.\n const maxTextFileSize = getMaxTextFileSize();\n if (stats.size > maxTextFileSize) {\n throw createTooLargeError(stats.size, maxTextFileSize, filePath);\n }\n const content = await withAbort(fsReadFile(validPath), options?.signal);\n const mimeInfo = detectMimeFromContent(validPath, content);\n return {\n content,\n mimeType: mimeInfo.mimeType,\n isBinary: mimeInfo.kind !== 'text',\n };\n }\n\n async open(\n filePath: string,\n flags: string | number,\n mode?: string | number,\n ): Promise<FileHandle> {\n // Only a plain read-only open ('r' / O_RDONLY) uses the existing-path guard.\n // Every other flag (write, append, read-write, sync, numeric) is treated as\n // write-capable and routed through the stricter write guard.\n const isReadOnly = flags === 'r' || flags === fsConstants.O_RDONLY;\n const validPath = isReadOnly\n ? await this.pathGuard.validateExistingPath(filePath)\n : await this.pathGuard.validatePathForWrite(filePath);\n return fsOpen(validPath, flags, mode);\n }\n\n async createReadStream(\n filePath: string,\n options?: Parameters<typeof createReadStream>[1],\n ): Promise<ReadStream> {\n const validPath = await this.pathGuard.validateExistingPath(filePath);\n return createReadStream(validPath, options);\n }\n\n // Single resolution + stat: validateExistingPathDetailed resolves the real\n // path (following symlinks, re-checking sensitivity) once, then we stat the\n // resolved target. Replaces the tool-side validateExistingPathDetailed +\n // fs.stat pair that re-validated through the free stat() guard.\n async statDetailed(\n filePath: string,\n options?: { signal?: AbortSignal },\n ): Promise<{ requestedPath: string; isSymlink: boolean; stats: Stats }> {\n const { requestedPath, resolvedPath, isSymlink } =\n await this.pathGuard.validateExistingPathDetailed(filePath);\n const stats = await withAbort(fsStat(resolvedPath), options?.signal);\n return { requestedPath, isSymlink, stats };\n }\n\n async hasChildrenUnchecked(dirPath: string): Promise<boolean> {\n const dir = await fsOpendir(dirPath);\n try {\n const entry = await dir.read();\n return entry !== null;\n } finally {\n await dir.close().catch((closeErr: unknown) => {\n Logger.warn(\n `Failed to close dir handle for ${dirPath}: ${formatUnknownErrorMessage(closeErr)}`,\n );\n });\n }\n }\n}\n\nexport interface StatPath {\n stat(filePath: string, options?: { signal?: AbortSignal }): Promise<unknown>;\n}\n\n/**\n * Returns whether `path` exists, treating \"not found\" as absent and logging any\n * other stat failure. Used for TOCTOU re-checks between plan and execute phases.\n */\nexport async function destExists(fs: StatPath, path: string, label: string): Promise<boolean> {\n try {\n await fs.stat(path);\n return true;\n } catch (err) {\n const missing =\n (isNodeError(err) && err.code === 'ENOENT') ||\n (isFsError(err) && err.code === ErrorCode.NOT_FOUND);\n if (!missing) {\n Logger.warn(`${label}: dest stat failed unexpectedly for \"${path}\": ${String(err)}`);\n }\n return false;\n }\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Ignore } from 'ignore';
|
|
2
|
+
import type { EntryType } from './primitives.js';
|
|
3
|
+
export type { EntryType };
|
|
4
|
+
export interface DirentLike {
|
|
5
|
+
isDirectory(): boolean;
|
|
6
|
+
isFile(): boolean;
|
|
7
|
+
isSymbolicLink(): boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveEntryType(dirent: DirentLike): EntryType;
|
|
10
|
+
export declare function isSafeGlobSyntax(pattern: string): boolean;
|
|
11
|
+
export declare class GitignoreManager {
|
|
12
|
+
private matchers;
|
|
13
|
+
addMatcher(dir: string, matcher: Ignore): void;
|
|
14
|
+
static load(root: string, signal?: AbortSignal): Promise<GitignoreManager>;
|
|
15
|
+
size(): number;
|
|
16
|
+
isIgnored(relativePath: string, isDirectory: boolean): boolean;
|
|
17
|
+
private checkPath;
|
|
18
|
+
}
|
|
19
|
+
export declare function loadRootGitignore(root: string, signal?: AbortSignal): Promise<GitignoreManager | null>;
|
|
20
|
+
export declare function isIgnoredByGitignore(matcher: GitignoreManager, root: string, absolutePath: string, options?: {
|
|
21
|
+
isDirectory?: boolean;
|
|
22
|
+
relativePath?: string;
|
|
23
|
+
}): boolean;
|
|
24
|
+
export interface GlobEntry {
|
|
25
|
+
path: string;
|
|
26
|
+
dirent: DirentLike;
|
|
27
|
+
}
|
|
28
|
+
export interface GlobEntriesOptions {
|
|
29
|
+
cwd: string;
|
|
30
|
+
pattern: string;
|
|
31
|
+
excludePatterns?: readonly string[];
|
|
32
|
+
includeHidden?: boolean;
|
|
33
|
+
baseNameMatch?: boolean;
|
|
34
|
+
maxDepth?: number;
|
|
35
|
+
onlyFiles?: boolean;
|
|
36
|
+
suppressErrors?: boolean;
|
|
37
|
+
respectGitignore?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function globEntries(options: GlobEntriesOptions): AsyncGenerator<GlobEntry>;
|
|
40
|
+
export declare const DEFAULT_EXCLUDE_PATTERNS: string[];
|
|
41
|
+
//# sourceMappingURL=glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/core/glob.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAQrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,MAAM,WAAW,UAAU;IACzB,WAAW,IAAI,OAAO,CAAC;IACvB,MAAM,IAAI,OAAO,CAAC;IAClB,cAAc,IAAI,OAAO,CAAC;CAC3B;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAK9D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAsBzD;AA4BD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAA6B;IAE7C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;WAIjC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6BhF,IAAI,IAAI,MAAM;IAId,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO;IAqB9D,OAAO,CAAC,SAAS;CA2ClB;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAMlC;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7D,OAAO,CAKT;AAOD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAkOD,wBAAuB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc,CAAC,SAAS,CAAC,CAczF;AAED,eAAO,MAAM,wBAAwB,UA0CpC,CAAC"}
|