@j0hanz/filesystem-mcp 2.8.1 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -26
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +10 -1
- package/dist/cli-help.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +10 -3
- package/dist/cli.js.map +1 -1
- package/dist/core/concurrency.d.ts +4 -4
- package/dist/core/concurrency.d.ts.map +1 -1
- package/dist/core/concurrency.js +1 -1
- package/dist/core/concurrency.js.map +1 -1
- package/dist/core/config.d.ts +2 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/file-uri.d.ts +12 -3
- package/dist/core/file-uri.d.ts.map +1 -1
- package/dist/core/file-uri.js +35 -7
- package/dist/core/file-uri.js.map +1 -1
- package/dist/core/fmt.d.ts +2 -0
- package/dist/core/fmt.d.ts.map +1 -1
- package/dist/core/fmt.js +16 -0
- package/dist/core/fmt.js.map +1 -1
- package/dist/core/fs.d.ts +16 -1
- package/dist/core/fs.d.ts.map +1 -1
- package/dist/core/fs.js +127 -32
- package/dist/core/fs.js.map +1 -1
- package/dist/core/glob.d.ts +8 -0
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/glob.js +84 -11
- package/dist/core/glob.js.map +1 -1
- package/dist/core/path-completer.d.ts.map +1 -1
- package/dist/core/path-completer.js +5 -3
- package/dist/core/path-completer.js.map +1 -1
- package/dist/core/path-utils.d.ts +42 -6
- package/dist/core/path-utils.d.ts.map +1 -1
- package/dist/core/path-utils.js +56 -10
- package/dist/core/path-utils.js.map +1 -1
- package/dist/core/path.d.ts +111 -7
- package/dist/core/path.d.ts.map +1 -1
- package/dist/core/path.js +453 -65
- package/dist/core/path.js.map +1 -1
- package/dist/core/read.d.ts +6 -0
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +26 -3
- package/dist/core/read.js.map +1 -1
- package/dist/core/schema.d.ts +9 -6
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +22 -19
- package/dist/core/schema.js.map +1 -1
- package/dist/core/search.d.ts +6 -0
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +159 -33
- package/dist/core/search.js.map +1 -1
- package/dist/core/sensitive.d.ts.map +1 -1
- package/dist/core/sensitive.js +64 -15
- package/dist/core/sensitive.js.map +1 -1
- package/dist/core/store.d.ts +1 -0
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +3 -0
- package/dist/core/store.js.map +1 -1
- package/dist/core/util.d.ts +6 -1
- package/dist/core/util.d.ts.map +1 -1
- package/dist/core/util.js +8 -1
- package/dist/core/util.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +18 -9
- package/dist/resources.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/create.d.ts.map +1 -1
- package/dist/tools/create.js +121 -43
- package/dist/tools/create.js.map +1 -1
- package/dist/tools/define.d.ts +8 -4
- package/dist/tools/define.d.ts.map +1 -1
- package/dist/tools/define.js +36 -9
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/delete.d.ts.map +1 -1
- package/dist/tools/delete.js +50 -11
- package/dist/tools/delete.js.map +1 -1
- package/dist/tools/diff.js +1 -1
- package/dist/tools/diff.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +14 -12
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +15 -9
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/list.d.ts.map +1 -1
- package/dist/tools/list.js +138 -86
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/move.d.ts.map +1 -1
- package/dist/tools/move.js +72 -26
- package/dist/tools/move.js.map +1 -1
- package/dist/tools/patch.js +13 -6
- package/dist/tools/patch.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +114 -45
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/replace-text.d.ts.map +1 -1
- package/dist/tools/replace-text.js +49 -35
- package/dist/tools/replace-text.js.map +1 -1
- package/dist/tools/search-text.d.ts.map +1 -1
- package/dist/tools/search-text.js +15 -33
- package/dist/tools/search-text.js.map +1 -1
- package/dist/tools/stat.d.ts.map +1 -1
- package/dist/tools/stat.js +26 -8
- package/dist/tools/stat.js.map +1 -1
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +1 -0
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/stdio.js +1 -1
- package/dist/transport/stdio.js.map +1 -1
- package/package.json +5 -5
package/dist/core/path.d.ts
CHANGED
|
@@ -3,6 +3,19 @@ export interface ValidatedPathDetails {
|
|
|
3
3
|
resolvedPath: string;
|
|
4
4
|
isSymlink: boolean;
|
|
5
5
|
}
|
|
6
|
+
/** How one walk prints the paths it found; see `PathGuard.resultPaths`. */
|
|
7
|
+
export interface ResultPaths {
|
|
8
|
+
/** The root the relative paths are relative to, as configured; the walked directory when there is none. */
|
|
9
|
+
readonly root: string;
|
|
10
|
+
/** The walked directory is that root itself. */
|
|
11
|
+
readonly atRoot: boolean;
|
|
12
|
+
show(absolutePath: string): string;
|
|
13
|
+
}
|
|
14
|
+
/** A root and every spelling that names it: as configured, and its realpath when that differs. */
|
|
15
|
+
interface RootSpellings {
|
|
16
|
+
readonly root: string;
|
|
17
|
+
readonly spellings: readonly string[];
|
|
18
|
+
}
|
|
6
19
|
export interface ServerOptions {
|
|
7
20
|
allowCwd?: boolean;
|
|
8
21
|
cliAllowedDirs?: string[];
|
|
@@ -13,11 +26,16 @@ export declare function resolveAllowedDirectoriesState(dirs: readonly string[],
|
|
|
13
26
|
/**
|
|
14
27
|
* TOCTOU note: validation returns a plain string and the fs operation is a
|
|
15
28
|
* later syscall, so a symlink swapped in between could redirect it. Reads and
|
|
16
|
-
* appends in core/fs.ts open with O_NOFOLLOW (final component)
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
29
|
+
* appends in core/fs.ts open with O_NOFOLLOW (final component) and re-check the
|
|
30
|
+
* fd's real path on Linux (ancestor swap). stat's directory count opens and
|
|
31
|
+
* re-checks the directory, and reads entries through that descriptor, only on
|
|
32
|
+
* Linux with procfs; elsewhere it reads the directory by path, so the swap
|
|
33
|
+
* window stays there, like the read path's non-Linux residual. Residuals: the
|
|
34
|
+
* directory walker behind list and the search tools (core/glob.ts) still
|
|
35
|
+
* resolves each entry by path, as the count does for a symlinked entry;
|
|
36
|
+
* write paths that resolve a parent by name
|
|
37
|
+
* (`rename`, `mkdir`, `rm`, `cp`) would need openat()-relative-to-dirfd, which
|
|
38
|
+
* Node lacks; non-Linux skips the fd re-check.
|
|
21
39
|
*/
|
|
22
40
|
export declare class PathGuard {
|
|
23
41
|
private allowedDirectoriesState;
|
|
@@ -39,14 +57,28 @@ export declare class PathGuard {
|
|
|
39
57
|
* field — so the recompute can rebuild from it without re-filtering.
|
|
40
58
|
*/
|
|
41
59
|
private grantedDirectories;
|
|
60
|
+
/**
|
|
61
|
+
* The grants a user approved for a path a tool asked about, as opposed to
|
|
62
|
+
* the workspace roots a client declared. Relative paths never resolve
|
|
63
|
+
* against these: one approval must not change what a relative path names,
|
|
64
|
+
* neither in a later round of the same call nor in a later call.
|
|
65
|
+
*/
|
|
66
|
+
private accessGrants;
|
|
67
|
+
/**
|
|
68
|
+
* Where relative paths resolve: the roots minus `accessGrants`, each with
|
|
69
|
+
* its spellings, plus every spelling flattened for containment.
|
|
70
|
+
*/
|
|
71
|
+
private relativeBases;
|
|
42
72
|
private rootBoundaries;
|
|
43
73
|
private readonly options;
|
|
44
74
|
constructor(options?: ServerOptions);
|
|
45
75
|
/**
|
|
46
76
|
* `expanded` is the containment set (each root plus its realpath alias);
|
|
47
77
|
* `roots` is what a caller choosing "the root" sees, one entry per root.
|
|
78
|
+
* `relativeBases` lists the roots relative paths resolve against, with
|
|
79
|
+
* their spellings; without it, every root, each spelled only as given.
|
|
48
80
|
*/
|
|
49
|
-
initialize(expanded: readonly string[], roots?: readonly string[]): void;
|
|
81
|
+
initialize(expanded: readonly string[], roots?: readonly string[], relativeBases?: readonly RootSpellings[]): void;
|
|
50
82
|
isInitialized(): boolean;
|
|
51
83
|
getAllowedDirectories(): string[];
|
|
52
84
|
/**
|
|
@@ -63,6 +95,16 @@ export declare class PathGuard {
|
|
|
63
95
|
*/
|
|
64
96
|
getRoots(): string[];
|
|
65
97
|
isSensitive(filePath: string): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* True when a walked entry is inside the allowed directories and not sensitive,
|
|
100
|
+
* on both its requested and resolved paths. Every entry is realpath-resolved: a
|
|
101
|
+
* symlinked ancestor pointing outside the sandbox would otherwise pass the
|
|
102
|
+
* lexical check (fs.glob follows symlinks and yields external entries as
|
|
103
|
+
* non-symlink dirents). Escapes and sensitive targets throw ACCESS_DENIED and
|
|
104
|
+
* skippable errors filter the entry; anything else is fatal. The accepted
|
|
105
|
+
* TOCTOU window is documented on this class.
|
|
106
|
+
*/
|
|
107
|
+
isEntryAccessible(entryPath: string): Promise<boolean>;
|
|
66
108
|
validateExistingPath(requestedPath: string): Promise<string>;
|
|
67
109
|
/**
|
|
68
110
|
* True when a grant must never admit `targetDir` — an unsafe path (home,
|
|
@@ -98,20 +140,82 @@ export declare class PathGuard {
|
|
|
98
140
|
* pre-checks passed. The caller leaves a refused path to fail with
|
|
99
141
|
* ACCESS_DENIED during the operation. Idempotent: re-granting an already
|
|
100
142
|
* allowed directory is a no-op via the dedup in `initialize`.
|
|
143
|
+
*
|
|
144
|
+
* `kind` says where the grant came from: `access` for a path the user
|
|
145
|
+
* approved when a tool asked, `workspace` for a root the client declared.
|
|
146
|
+
* Only a workspace root becomes a place relative paths resolve.
|
|
101
147
|
*/
|
|
102
|
-
applyGrant(targetDir: string): Promise<boolean>;
|
|
148
|
+
applyGrant(targetDir: string, kind?: 'access' | 'workspace'): Promise<boolean>;
|
|
103
149
|
private isWithinBoundary;
|
|
104
150
|
private validateAccess;
|
|
105
151
|
private handleRealpathError;
|
|
106
152
|
validateExistingPathDetailed(requestedPath: string): Promise<ValidatedPathDetails>;
|
|
107
153
|
validateExistingDirectory(requestedPath: string): Promise<string>;
|
|
108
154
|
resolvePathOrRoot(pathValue: string | undefined): string;
|
|
155
|
+
/**
|
|
156
|
+
* Where the relative paths a caller sent should point, keyed by the spelling
|
|
157
|
+
* sent; a path that keeps its meaning is absent. A relative path resolves
|
|
158
|
+
* against the working directory, as it always has, while that lands inside
|
|
159
|
+
* a root. When it does not — a desktop host starts the server outside the
|
|
160
|
+
* project, and an HTTP client never shares its working directory — it
|
|
161
|
+
* resolves against the roots: the one root, or with several, the one it
|
|
162
|
+
* exists under. Searches print paths relative to the root (`resultPaths`),
|
|
163
|
+
* so this is what lets one tool's output feed the next.
|
|
164
|
+
*
|
|
165
|
+
* "Roots" here are the configured ones and those a client declared, never an
|
|
166
|
+
* access grant (see `accessGrants`). Absolute, `~` and drive paths keep their
|
|
167
|
+
* meaning, as does every path when there is no such root; validation judges
|
|
168
|
+
* them as before. A Windows drive path on POSIX is left for validation to
|
|
169
|
+
* refuse: joined to a root, `C:\x` would be an absolute path that passes. A
|
|
170
|
+
* relative path that exists under several roots, or under none of several,
|
|
171
|
+
* is refused rather than guessed.
|
|
172
|
+
*/
|
|
173
|
+
resolveRelativePaths(paths: readonly string[]): Promise<Map<string, string>>;
|
|
174
|
+
private resolveAgainstRoots;
|
|
175
|
+
/**
|
|
176
|
+
* How a tool prints the paths a walk of `walkedDir` found, so the caller can
|
|
177
|
+
* pass each one straight back: relative to the root holding `walkedDir`
|
|
178
|
+
* when `resolveRelativePaths` maps that spelling back to the same path,
|
|
179
|
+
* absolute otherwise. A scoped search of `src` prints `src/a.ts`, not
|
|
180
|
+
* `a.ts`, which would name `<root>/a.ts`. `root` is the root as configured,
|
|
181
|
+
* as `list_roots` shows it, even when the walk went through its realpath.
|
|
182
|
+
*
|
|
183
|
+
* The absolute fallback covers a working directory in a subfolder of a root
|
|
184
|
+
* (relative paths resolve there), a directory under an access grant only
|
|
185
|
+
* (relative paths never resolve there), several roots with the working
|
|
186
|
+
* directory outside them (a name two roots share would read back as
|
|
187
|
+
* ambiguous, and which names are shared can change between the print and
|
|
188
|
+
* the read), and a name that would not read back as given: `~`, blank, or a
|
|
189
|
+
* POSIX name holding a backslash or starting with a drive (`C:`).
|
|
190
|
+
*/
|
|
191
|
+
resultPaths(walkedDir: string): ResultPaths;
|
|
109
192
|
isAllowedRoot(normalizedPath: string): boolean;
|
|
110
193
|
private assertNotSensitiveFile;
|
|
111
194
|
private throwAccessDenied;
|
|
112
195
|
private resolveNearestExistingAncestor;
|
|
196
|
+
/**
|
|
197
|
+
* `normalized` re-spelled with the on-disk names of the components that are
|
|
198
|
+
* missing as typed but present under another Unicode spelling (#101), or
|
|
199
|
+
* `undefined` when no component changed. Only names below a root are
|
|
200
|
+
* matched, never the root's own. Each directory is scanned only after its
|
|
201
|
+
* real path is checked to be inside the roots, and each matched entry is
|
|
202
|
+
* realpathed and checked again, so a link found this way cannot lead out
|
|
203
|
+
* (`resolveLast: false` leaves the last one unresolved, for delete). The
|
|
204
|
+
* first component with no match ends the walk; it and the rest stay as
|
|
205
|
+
* typed, so a write still creates them. The result is a spelling only:
|
|
206
|
+
* the caller runs its own containment and denylist checks on it.
|
|
207
|
+
*/
|
|
208
|
+
private respellMissing;
|
|
209
|
+
/**
|
|
210
|
+
* The entry of `realDir` that `name` names: `name` itself when it is
|
|
211
|
+
* there, else the one entry with the same `unicodeMatchKey`. Two or more
|
|
212
|
+
* such entries are refused, never chosen between. `undefined` when none
|
|
213
|
+
* matches or the directory cannot be read.
|
|
214
|
+
*/
|
|
215
|
+
private findEquivalentEntry;
|
|
113
216
|
validatePathForWrite(requestedPath: string): Promise<string>;
|
|
114
217
|
validatePathForDelete(requestedPath: string): Promise<string>;
|
|
115
218
|
recomputeAllowedDirectories(): Promise<void>;
|
|
116
219
|
}
|
|
220
|
+
export {};
|
|
117
221
|
//# sourceMappingURL=path.d.ts.map
|
package/dist/core/path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/core/path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/core/path.ts"],"names":[],"mappings":"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"}
|