@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":"cli-help.d.ts","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAgJA,wBAAgB,gBAAgB,IAAI,KAAK,CAkCxC;AAED,wBAAgB,mBAAmB,IAAI,KAAK,CAG3C"}
|
package/dist/cli-help.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import packageJson from '../package.json' with { type: 'json' };
|
|
2
|
+
import { cliFmt, padEndVisible } from './core/fmt.js';
|
|
3
|
+
import { MUTATING_TOOL_NAMES } from './tools/index.js';
|
|
4
|
+
// Help text and its rendering. Split out of cli.ts so that module holds only
|
|
5
|
+
// argument parsing and directory validation: this file is static copy plus a
|
|
6
|
+
// formatter, and shares no state with the parser.
|
|
7
|
+
const { version: SERVER_VERSION } = packageJson;
|
|
8
|
+
const OPTIONS_HELP = [
|
|
9
|
+
{ flags: '-h, --help', desc: 'Show this help message' },
|
|
10
|
+
{ flags: '-v, --version', desc: 'Show the server version' },
|
|
11
|
+
{ flags: '--allow-cwd', desc: 'Add the current working directory as an allowed root' },
|
|
12
|
+
{
|
|
13
|
+
flags: '--port <number>',
|
|
14
|
+
desc: 'Start HTTP transport on this port (env: FS_PORT)',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
flags: '--read-only',
|
|
18
|
+
desc: `Disable write tools: ${[...MUTATING_TOOL_NAMES].sort().join(', ')}`,
|
|
19
|
+
},
|
|
20
|
+
{ flags: '--safe', desc: 'Alias for --read-only' },
|
|
21
|
+
{
|
|
22
|
+
flags: '--print-config',
|
|
23
|
+
desc: 'Print the active configuration and exit (use with --json for machine output)',
|
|
24
|
+
},
|
|
25
|
+
{ flags: '--json', desc: 'Output --print-config as JSON' },
|
|
26
|
+
{
|
|
27
|
+
flags: '--log-level <level>',
|
|
28
|
+
desc: 'Log level, RFC 5424: debug|info|notice|warn|error|critical|alert|emergency (env: FS_LOG_LEVEL)',
|
|
29
|
+
},
|
|
30
|
+
{ flags: '--http-host <host>', desc: 'HTTP server bind address (env: FS_HTTP_HOST)' },
|
|
31
|
+
{
|
|
32
|
+
flags: '--api-key <key>',
|
|
33
|
+
desc: 'Require this API key on HTTP requests; prefer FS_API_KEY (argv is world-readable)',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
flags: '--allow-sensitive',
|
|
37
|
+
desc: 'Allow access to sensitive system paths (env: FS_ALLOW_SENSITIVE)',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
flags: '--root-boundary <path>',
|
|
41
|
+
desc: 'Require all allowed roots to fall under this path (env: FS_ROOT_BOUNDARY)',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
flags: '--max-file-size <bytes>',
|
|
45
|
+
desc: 'Maximum file size for reads in bytes (env: FS_MAX_FILE_SIZE)',
|
|
46
|
+
},
|
|
47
|
+
{ flags: '--walk-cwd', desc: 'Walk up from CWD to find a project root; implies --allow-cwd' },
|
|
48
|
+
{ flags: '--deny <pattern>', desc: 'Block paths matching this pattern; repeatable' },
|
|
49
|
+
{
|
|
50
|
+
flags: '--allow-missing-roots',
|
|
51
|
+
desc: 'Start even if configured allowed directories do not exist',
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
const ENV_HELP = [
|
|
55
|
+
{
|
|
56
|
+
flags: 'FS_LOG_LEVEL',
|
|
57
|
+
desc: 'Log level, RFC 5424: debug|info|notice|warn|error|critical|alert|emergency',
|
|
58
|
+
},
|
|
59
|
+
{ flags: 'FS_PORT', desc: 'Start HTTP transport on this port (unset = stdio)' },
|
|
60
|
+
{ flags: 'FS_HTTP_HOST', desc: 'HTTP bind address' },
|
|
61
|
+
{ flags: 'FS_API_KEY', desc: 'HTTP API key' },
|
|
62
|
+
{
|
|
63
|
+
flags: 'FS_TRUST_PROXY',
|
|
64
|
+
desc: 'Express trust-proxy setting: hop count or expression (unset = do not trust X-Forwarded-*)',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
flags: 'FS_ALLOW_SENSITIVE',
|
|
68
|
+
desc: 'Allow sensitive system paths ("true" or "1" enables this)',
|
|
69
|
+
},
|
|
70
|
+
{ flags: 'FS_ROOT_BOUNDARY', desc: 'Path prefix all allowed roots must fall under' },
|
|
71
|
+
{ flags: 'FS_MAX_FILE_SIZE', desc: 'Maximum file size for reads in bytes' },
|
|
72
|
+
{
|
|
73
|
+
flags: 'FS_ALLOWED_DIRS',
|
|
74
|
+
desc: 'Allowed dirs: colon-separated (Unix), semicolon-separated (Windows)',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
flags: 'FS_ALLOW_CWD_WALK',
|
|
78
|
+
desc: 'Walk up from CWD to find a project root ("true" or "1" enables this)',
|
|
79
|
+
},
|
|
80
|
+
{ flags: 'FS_DENYLIST', desc: 'Paths/patterns to block, comma-separated' },
|
|
81
|
+
{
|
|
82
|
+
flags: 'FS_ALLOW_MISSING_ROOTS',
|
|
83
|
+
desc: 'Start even if configured allowed directories do not exist ("true" or "1" enables this)',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
flags: 'FS_ALLOWED_HOSTS',
|
|
87
|
+
desc: 'Comma-separated Host header values to accept (HTTP transport)',
|
|
88
|
+
},
|
|
89
|
+
{ flags: 'FS_ALLOWED_ORIGINS', desc: 'Comma-separated origin hostnames for CORS' },
|
|
90
|
+
{
|
|
91
|
+
flags: 'FS_ALLOW_UNRESTRICTED_HOSTS',
|
|
92
|
+
desc: 'Bind a wildcard host with no Host validation, accepts the risk ("true" or "1" enables this)',
|
|
93
|
+
},
|
|
94
|
+
{ flags: 'FS_PUBLIC_URL', desc: 'Resource identifier URL for RFC 9728 discovery' },
|
|
95
|
+
{
|
|
96
|
+
flags: 'FS_RATE_LIMIT_RPM',
|
|
97
|
+
desc: 'Per-client-IP requests/min (default 120 authenticated, 6000 keyless loopback; 1–100000)',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
flags: 'FS_MAX_REQUEST_BYTES',
|
|
101
|
+
desc: 'Max HTTP request body bytes (default 4194304, 1024–268435456)',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
flags: 'FS_KEEPALIVE_TIMEOUT_MS',
|
|
105
|
+
desc: 'HTTP keep-alive timeout; set above any fronting proxy idle timeout (default 5000, 1000–600000)',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
flags: 'FS_MAX_WATCHERS',
|
|
109
|
+
desc: 'Max concurrent file watchers (default 256, 1–4096)',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
flags: 'FS_MAX_INLINE_MATCHES',
|
|
113
|
+
desc: 'Max inline content matches per search (default 50, 1–10000)',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
flags: 'FS_MAX_READ_MANY_BYTES',
|
|
117
|
+
desc: 'Max total bytes across one batch read (default 524288, 10240–104857600)',
|
|
118
|
+
},
|
|
119
|
+
{ flags: 'FS_SEARCH_TIMEOUT_MS', desc: 'Search timeout in ms (default 5000, 100–60000)' },
|
|
120
|
+
{ flags: 'NO_COLOR', desc: 'Any value disables ANSI color output' },
|
|
121
|
+
{
|
|
122
|
+
flags: 'FS_REQUEST_STATE_KEY',
|
|
123
|
+
desc: 'HMAC key for input_required state; optional outside fleet mode, shared and >=32 bytes in fleet mode',
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
const EXAMPLES_HELP = [
|
|
127
|
+
'$ filesystem-mcp /path/to/allowed/dir',
|
|
128
|
+
'$ filesystem-mcp --allow-cwd',
|
|
129
|
+
'$ filesystem-mcp /project/src /project/tests --allow-cwd',
|
|
130
|
+
'$ filesystem-mcp --port 3000 /path/to/allowed/dir',
|
|
131
|
+
'$ filesystem-mcp --read-only /data/readonly',
|
|
132
|
+
'$ filesystem-mcp --print-config --json /project',
|
|
133
|
+
];
|
|
134
|
+
export function printHelpAndExit() {
|
|
135
|
+
const { bold, dim, section, flag, placeholder, cyan } = cliFmt;
|
|
136
|
+
const COL = 27;
|
|
137
|
+
const optRow = (flags, desc) => {
|
|
138
|
+
const colored = flags
|
|
139
|
+
.replace(/<[^>]+>/g, (m) => placeholder(m))
|
|
140
|
+
.replace(/-{1,2}[\w-]+/g, (m) => flag(m));
|
|
141
|
+
return ` ${padEndVisible(colored, COL)}${desc}`;
|
|
142
|
+
};
|
|
143
|
+
const envRow = (name, desc) => {
|
|
144
|
+
return ` ${padEndVisible(cyan(name), COL - 1)} ${desc}`;
|
|
145
|
+
};
|
|
146
|
+
const lines = [
|
|
147
|
+
'',
|
|
148
|
+
`${bold('Filesystem MCP')} ${dim(`v${SERVER_VERSION}`)}`,
|
|
149
|
+
'',
|
|
150
|
+
dim('Pass one or more directories to set the allowed access roots.'),
|
|
151
|
+
'',
|
|
152
|
+
section('Options:'),
|
|
153
|
+
...OPTIONS_HELP.map(({ flags, desc }) => optRow(flags, desc)),
|
|
154
|
+
'',
|
|
155
|
+
`${section('Environment variables:')} ${dim('(flags take precedence when both are set)')}`,
|
|
156
|
+
...ENV_HELP.map(({ flags, desc }) => envRow(flags, desc)),
|
|
157
|
+
'',
|
|
158
|
+
section('Examples:'),
|
|
159
|
+
...EXAMPLES_HELP.map((ex) => ` ${dim(ex)}`),
|
|
160
|
+
'',
|
|
161
|
+
];
|
|
162
|
+
process.stdout.write(lines.join('\n'));
|
|
163
|
+
process.exit(0);
|
|
164
|
+
}
|
|
165
|
+
export function printVersionAndExit() {
|
|
166
|
+
process.stdout.write(`${cliFmt.cyan(SERVER_VERSION)}\n`);
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=cli-help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"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","sourcesContent":["import packageJson from '../package.json' with { type: 'json' };\nimport { cliFmt, padEndVisible } from './core/fmt.js';\nimport { MUTATING_TOOL_NAMES } from './tools/index.js';\n\n// Help text and its rendering. Split out of cli.ts so that module holds only\n// argument parsing and directory validation: this file is static copy plus a\n// formatter, and shares no state with the parser.\n\nconst { version: SERVER_VERSION } = packageJson;\n\ninterface HelpRow {\n flags: string;\n desc: string;\n}\n\nconst OPTIONS_HELP: HelpRow[] = [\n { flags: '-h, --help', desc: 'Show this help message' },\n { flags: '-v, --version', desc: 'Show the server version' },\n { flags: '--allow-cwd', desc: 'Add the current working directory as an allowed root' },\n {\n flags: '--port <number>',\n desc: 'Start HTTP transport on this port (env: FS_PORT)',\n },\n {\n flags: '--read-only',\n desc: `Disable write tools: ${[...MUTATING_TOOL_NAMES].sort().join(', ')}`,\n },\n { flags: '--safe', desc: 'Alias for --read-only' },\n {\n flags: '--print-config',\n desc: 'Print the active configuration and exit (use with --json for machine output)',\n },\n { flags: '--json', desc: 'Output --print-config as JSON' },\n {\n flags: '--log-level <level>',\n desc: 'Log level, RFC 5424: debug|info|notice|warn|error|critical|alert|emergency (env: FS_LOG_LEVEL)',\n },\n { flags: '--http-host <host>', desc: 'HTTP server bind address (env: FS_HTTP_HOST)' },\n {\n flags: '--api-key <key>',\n desc: 'Require this API key on HTTP requests; prefer FS_API_KEY (argv is world-readable)',\n },\n {\n flags: '--allow-sensitive',\n desc: 'Allow access to sensitive system paths (env: FS_ALLOW_SENSITIVE)',\n },\n {\n flags: '--root-boundary <path>',\n desc: 'Require all allowed roots to fall under this path (env: FS_ROOT_BOUNDARY)',\n },\n {\n flags: '--max-file-size <bytes>',\n desc: 'Maximum file size for reads in bytes (env: FS_MAX_FILE_SIZE)',\n },\n { flags: '--walk-cwd', desc: 'Walk up from CWD to find a project root; implies --allow-cwd' },\n { flags: '--deny <pattern>', desc: 'Block paths matching this pattern; repeatable' },\n {\n flags: '--allow-missing-roots',\n desc: 'Start even if configured allowed directories do not exist',\n },\n];\n\nconst ENV_HELP: HelpRow[] = [\n {\n flags: 'FS_LOG_LEVEL',\n desc: 'Log level, RFC 5424: debug|info|notice|warn|error|critical|alert|emergency',\n },\n { flags: 'FS_PORT', desc: 'Start HTTP transport on this port (unset = stdio)' },\n { flags: 'FS_HTTP_HOST', desc: 'HTTP bind address' },\n { flags: 'FS_API_KEY', desc: 'HTTP API key' },\n {\n flags: 'FS_TRUST_PROXY',\n desc: 'Express trust-proxy setting: hop count or expression (unset = do not trust X-Forwarded-*)',\n },\n {\n flags: 'FS_ALLOW_SENSITIVE',\n desc: 'Allow sensitive system paths (\"true\" or \"1\" enables this)',\n },\n { flags: 'FS_ROOT_BOUNDARY', desc: 'Path prefix all allowed roots must fall under' },\n { flags: 'FS_MAX_FILE_SIZE', desc: 'Maximum file size for reads in bytes' },\n {\n flags: 'FS_ALLOWED_DIRS',\n desc: 'Allowed dirs: colon-separated (Unix), semicolon-separated (Windows)',\n },\n {\n flags: 'FS_ALLOW_CWD_WALK',\n desc: 'Walk up from CWD to find a project root (\"true\" or \"1\" enables this)',\n },\n { flags: 'FS_DENYLIST', desc: 'Paths/patterns to block, comma-separated' },\n {\n flags: 'FS_ALLOW_MISSING_ROOTS',\n desc: 'Start even if configured allowed directories do not exist (\"true\" or \"1\" enables this)',\n },\n {\n flags: 'FS_ALLOWED_HOSTS',\n desc: 'Comma-separated Host header values to accept (HTTP transport)',\n },\n { flags: 'FS_ALLOWED_ORIGINS', desc: 'Comma-separated origin hostnames for CORS' },\n {\n flags: 'FS_ALLOW_UNRESTRICTED_HOSTS',\n desc: 'Bind a wildcard host with no Host validation, accepts the risk (\"true\" or \"1\" enables this)',\n },\n { flags: 'FS_PUBLIC_URL', desc: 'Resource identifier URL for RFC 9728 discovery' },\n {\n flags: 'FS_RATE_LIMIT_RPM',\n desc: 'Per-client-IP requests/min (default 120 authenticated, 6000 keyless loopback; 1–100000)',\n },\n {\n flags: 'FS_MAX_REQUEST_BYTES',\n desc: 'Max HTTP request body bytes (default 4194304, 1024–268435456)',\n },\n {\n flags: 'FS_KEEPALIVE_TIMEOUT_MS',\n desc: 'HTTP keep-alive timeout; set above any fronting proxy idle timeout (default 5000, 1000–600000)',\n },\n {\n flags: 'FS_MAX_WATCHERS',\n desc: 'Max concurrent file watchers (default 256, 1–4096)',\n },\n {\n flags: 'FS_MAX_INLINE_MATCHES',\n desc: 'Max inline content matches per search (default 50, 1–10000)',\n },\n {\n flags: 'FS_MAX_READ_MANY_BYTES',\n desc: 'Max total bytes across one batch read (default 524288, 10240–104857600)',\n },\n { flags: 'FS_SEARCH_TIMEOUT_MS', desc: 'Search timeout in ms (default 5000, 100–60000)' },\n { flags: 'NO_COLOR', desc: 'Any value disables ANSI color output' },\n {\n flags: 'FS_REQUEST_STATE_KEY',\n desc: 'HMAC key for input_required state; optional outside fleet mode, shared and >=32 bytes in fleet mode',\n },\n];\n\nconst EXAMPLES_HELP = [\n '$ filesystem-mcp /path/to/allowed/dir',\n '$ filesystem-mcp --allow-cwd',\n '$ filesystem-mcp /project/src /project/tests --allow-cwd',\n '$ filesystem-mcp --port 3000 /path/to/allowed/dir',\n '$ filesystem-mcp --read-only /data/readonly',\n '$ filesystem-mcp --print-config --json /project',\n];\n\nexport function printHelpAndExit(): never {\n const { bold, dim, section, flag, placeholder, cyan } = cliFmt;\n const COL = 27;\n\n const optRow = (flags: string, desc: string): string => {\n const colored = flags\n .replace(/<[^>]+>/g, (m) => placeholder(m))\n .replace(/-{1,2}[\\w-]+/g, (m) => flag(m));\n return ` ${padEndVisible(colored, COL)}${desc}`;\n };\n\n const envRow = (name: string, desc: string): string => {\n return ` ${padEndVisible(cyan(name), COL - 1)} ${desc}`;\n };\n\n const lines = [\n '',\n `${bold('Filesystem MCP')} ${dim(`v${SERVER_VERSION}`)}`,\n '',\n dim('Pass one or more directories to set the allowed access roots.'),\n '',\n section('Options:'),\n ...OPTIONS_HELP.map(({ flags, desc }) => optRow(flags, desc)),\n '',\n `${section('Environment variables:')} ${dim('(flags take precedence when both are set)')}`,\n ...ENV_HELP.map(({ flags, desc }) => envRow(flags, desc)),\n '',\n section('Examples:'),\n ...EXAMPLES_HELP.map((ex) => ` ${dim(ex)}`),\n '',\n ];\n\n process.stdout.write(lines.join('\\n'));\n process.exit(0);\n}\n\nexport function printVersionAndExit(): never {\n process.stdout.write(`${cliFmt.cyan(SERVER_VERSION)}\\n`);\n process.exit(0);\n}\n"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -6,4 +6,32 @@ export declare function parseArgs(): Promise<{
|
|
|
6
6
|
allowedDirs: string[];
|
|
7
7
|
allowCwd: boolean;
|
|
8
8
|
port: number | undefined;
|
|
9
|
+
readOnly: boolean;
|
|
10
|
+
printConfig: boolean;
|
|
11
|
+
json: boolean;
|
|
12
|
+
httpHost: string | undefined;
|
|
13
|
+
apiKey: string | undefined;
|
|
9
14
|
}>;
|
|
15
|
+
export interface EffectiveConfig {
|
|
16
|
+
transport: string;
|
|
17
|
+
readOnly: boolean;
|
|
18
|
+
allowedRoots: string[];
|
|
19
|
+
tools: string[];
|
|
20
|
+
apiKey: string | null;
|
|
21
|
+
limits: {
|
|
22
|
+
maxFileSizeBytes: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface PrintConfigOptions {
|
|
26
|
+
allowedDirs: string[];
|
|
27
|
+
allowCwd: boolean;
|
|
28
|
+
readOnly: boolean;
|
|
29
|
+
json: boolean;
|
|
30
|
+
/** Resolved `--port`. Present means the launch this reports on is an HTTP bind. */
|
|
31
|
+
port?: number;
|
|
32
|
+
httpHost?: string;
|
|
33
|
+
apiKey?: string;
|
|
34
|
+
stdout?: (chunk: string) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function runPrintConfig(options: PrintConfigOptions): Promise<EffectiveConfig>;
|
|
37
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAyBA,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAK9C;AAkJD,wBAAsB,SAAS,IAAI,OAAO,CAAC;IACzC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,CAAC,CAgFD;AAMD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAuC1F"}
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { getSystemErrorMessage, getSystemErrorName } from 'node:util';
|
|
3
|
-
import {
|
|
4
|
-
import { processInParallel } from './
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import { getSystemErrorMessage, getSystemErrorName, parseArgs as utilParseArgs } from 'node:util';
|
|
3
|
+
import { printHelpAndExit, printVersionAndExit } from './cli-help.js';
|
|
4
|
+
import { processInParallel } from './core/concurrency.js';
|
|
5
|
+
import { cli } from './core/config.js';
|
|
6
|
+
import { formatUnknownErrorMessage } from './core/errors.js';
|
|
7
|
+
import { cliFmt, padEndVisible } from './core/fmt.js';
|
|
8
|
+
import { getReservedDeviceNameForPath, isWindowsDriveRelativePath, normalizePath, } from './core/path-utils.js';
|
|
9
|
+
import { PathGuard } from './core/path.js';
|
|
10
|
+
import { IS_WINDOWS, isRecord, parseTrueEnvFlag } from './core/primitives.js';
|
|
11
|
+
import { getMaxTextFileSize } from './core/util.js';
|
|
12
|
+
import { registeredTools } from './tools/index.js';
|
|
10
13
|
const CLI_VALIDATE_CONCURRENCY = 8;
|
|
14
|
+
// ════════════════════════════════════════════════════════════
|
|
15
|
+
// Path & Config Utilities — pure functions and error types
|
|
16
|
+
// ════════════════════════════════════════════════════════════
|
|
11
17
|
export class CliExitError extends Error {
|
|
12
18
|
exitCode;
|
|
13
19
|
constructor(message, exitCode) {
|
|
@@ -18,45 +24,25 @@ export class CliExitError extends Error {
|
|
|
18
24
|
}
|
|
19
25
|
function validateCliPath(inputPath) {
|
|
20
26
|
if (inputPath.includes('\0')) {
|
|
21
|
-
throw new
|
|
27
|
+
throw new CliExitError('Path contains null bytes.', 1);
|
|
22
28
|
}
|
|
23
29
|
if (isWindowsDriveRelativePath(inputPath)) {
|
|
24
|
-
throw new
|
|
30
|
+
throw new CliExitError('Windows drive-relative paths are not allowed. Use C:\\path or C:/path instead of C:path.', 1);
|
|
25
31
|
}
|
|
26
32
|
const reserved = getReservedDeviceNameForPath(inputPath);
|
|
27
33
|
if (reserved) {
|
|
28
|
-
throw new
|
|
34
|
+
throw new CliExitError(`Windows reserved device name not allowed: ${reserved}.`, 1);
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
|
-
function
|
|
37
|
+
function getSystemErrorDetails(error) {
|
|
32
38
|
if (!isRecord(error))
|
|
33
|
-
return undefined;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
function collectStringValues(values) {
|
|
41
|
-
const result = [];
|
|
42
|
-
for (const value of values) {
|
|
43
|
-
if (typeof value === 'string') {
|
|
44
|
-
result.push(value);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
function getNodeErrorCode(error) {
|
|
50
|
-
const code = getNodeErrorProperty(error, 'code');
|
|
51
|
-
return typeof code === 'string' ? code : undefined;
|
|
52
|
-
}
|
|
53
|
-
function getNodeErrorErrno(error) {
|
|
54
|
-
const errno = getNodeErrorProperty(error, 'errno');
|
|
55
|
-
return typeof errno === 'number' ? errno : undefined;
|
|
39
|
+
return { code: undefined, errno: undefined };
|
|
40
|
+
const code = typeof error['code'] === 'string' ? error['code'] : undefined;
|
|
41
|
+
const errno = typeof error['errno'] === 'number' ? error['errno'] : undefined;
|
|
42
|
+
return { code, errno };
|
|
56
43
|
}
|
|
57
44
|
function normalizeDirectoryError(error, inputPath) {
|
|
58
|
-
const code =
|
|
59
|
-
const errno = getNodeErrorErrno(error);
|
|
45
|
+
const { code, errno } = getSystemErrorDetails(error);
|
|
60
46
|
if (error instanceof Error && code === undefined && errno === undefined) {
|
|
61
47
|
return error;
|
|
62
48
|
}
|
|
@@ -67,8 +53,9 @@ function normalizeDirectoryError(error, inputPath) {
|
|
|
67
53
|
return new Error(`Cannot access directory ${inputPath} (${name}: ${message})`);
|
|
68
54
|
}
|
|
69
55
|
catch {
|
|
70
|
-
// Fall through
|
|
56
|
+
// Fall through, but preserve raw errno value
|
|
71
57
|
}
|
|
58
|
+
return new Error(`Cannot access directory ${inputPath} (errno ${errno})`);
|
|
72
59
|
}
|
|
73
60
|
if (code) {
|
|
74
61
|
return new Error(`Cannot access directory ${inputPath} (${code})`);
|
|
@@ -80,7 +67,7 @@ function assertDirectory(stats, inputPath) {
|
|
|
80
67
|
return;
|
|
81
68
|
throw new Error(`${inputPath} is not a directory`);
|
|
82
69
|
}
|
|
83
|
-
async function validateDirectoryPath(inputPath) {
|
|
70
|
+
async function validateDirectoryPath(inputPath, allowMissing = false) {
|
|
84
71
|
const normalized = normalizePath(inputPath);
|
|
85
72
|
try {
|
|
86
73
|
const stats = await stat(normalized);
|
|
@@ -88,77 +75,25 @@ async function validateDirectoryPath(inputPath) {
|
|
|
88
75
|
return normalized;
|
|
89
76
|
}
|
|
90
77
|
catch (error) {
|
|
78
|
+
if (allowMissing) {
|
|
79
|
+
if (error instanceof Error && error.message.includes('is not a directory')) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
return normalized;
|
|
83
|
+
}
|
|
91
84
|
throw normalizeDirectoryError(error, inputPath);
|
|
92
85
|
}
|
|
93
86
|
}
|
|
94
|
-
async function
|
|
95
|
-
const { results, errors } = await processInParallel([...
|
|
87
|
+
async function normalizeAndValidateDirs(paths, allowMissing = false) {
|
|
88
|
+
const { results, errors } = await processInParallel([...paths], (p) => validateDirectoryPath(p, allowMissing), CLI_VALIDATE_CONCURRENCY);
|
|
96
89
|
if (errors.length === 0) {
|
|
97
|
-
return results;
|
|
98
|
-
}
|
|
99
|
-
let first = errors[0];
|
|
100
|
-
for (const failure of errors) {
|
|
101
|
-
if (first && failure.index < first.index) {
|
|
102
|
-
first = failure;
|
|
103
|
-
}
|
|
90
|
+
return deduplicateAllowedDirectories(results.map((r) => r.value));
|
|
104
91
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
function parseAllowedDirArgument(value, previous) {
|
|
108
|
-
validateCliPath(value);
|
|
109
|
-
const values = Array.isArray(previous) ? collectStringValues(previous) : [];
|
|
110
|
-
return [...values, value];
|
|
111
|
-
}
|
|
112
|
-
function getParsedAllowedDirs(cli) {
|
|
113
|
-
const [allowedDirs] = cli.processedArgs;
|
|
114
|
-
if (!Array.isArray(allowedDirs))
|
|
115
|
-
return [];
|
|
116
|
-
return collectStringValues(allowedDirs);
|
|
117
|
-
}
|
|
118
|
-
function createCliProgram(output) {
|
|
119
|
-
const cli = new Command();
|
|
120
|
-
cli
|
|
121
|
-
.name('filesystem-mcp')
|
|
122
|
-
.usage('[options] [allowedDirs...]')
|
|
123
|
-
.description('MCP filesystem server. Positional directories define allowed access roots.')
|
|
124
|
-
.argument('[allowedDirs...]', 'Directories the MCP server can access on disk', parseAllowedDirArgument)
|
|
125
|
-
.option('--allow_cwd, --allow-cwd', 'Allow the current working directory as an additional root')
|
|
126
|
-
.option('--port <number>', 'Enable HTTP transport on the given port (Node Streamable HTTP)')
|
|
127
|
-
.helpOption('-h, --help', 'Display command help')
|
|
128
|
-
.version(SERVER_VERSION, '-v, --version', 'Display server version')
|
|
129
|
-
.addHelpText('after', `
|
|
130
|
-
Examples:
|
|
131
|
-
$ filesystem-mcp /path/to/allowed/dir
|
|
132
|
-
$ filesystem-mcp --allow-cwd
|
|
133
|
-
$ filesystem-mcp /project/src /project/tests --allow-cwd
|
|
134
|
-
$ filesystem-mcp --port 3000 /path/to/allowed/dir
|
|
135
|
-
`);
|
|
136
|
-
cli.allowUnknownOption(false);
|
|
137
|
-
cli.allowExcessArguments(false);
|
|
138
|
-
cli.showHelpAfterError('(run with --help for usage)');
|
|
139
|
-
cli.showSuggestionAfterError(true);
|
|
140
|
-
cli.exitOverride();
|
|
141
|
-
cli.configureOutput({
|
|
142
|
-
writeOut(text) {
|
|
143
|
-
output.push(text);
|
|
144
|
-
},
|
|
145
|
-
writeErr(text) {
|
|
146
|
-
output.push(text);
|
|
147
|
-
},
|
|
148
|
-
outputError(text, write) {
|
|
149
|
-
write(text);
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
return cli;
|
|
153
|
-
}
|
|
154
|
-
function formatCliOutput(output, fallback) {
|
|
155
|
-
const joined = output.join('').trimEnd();
|
|
156
|
-
if (joined.length > 0)
|
|
157
|
-
return joined;
|
|
158
|
-
return fallback.trimEnd();
|
|
92
|
+
const first = errors.reduce((prev, curr) => (curr.index < prev.index ? curr : prev));
|
|
93
|
+
throw first.error;
|
|
159
94
|
}
|
|
160
95
|
function normalizeCliExitMessage(error) {
|
|
161
|
-
const rawMessage =
|
|
96
|
+
const rawMessage = formatUnknownErrorMessage(error);
|
|
162
97
|
return rawMessage.startsWith('Error:') ? rawMessage : `Error: ${rawMessage}`;
|
|
163
98
|
}
|
|
164
99
|
function deduplicateAllowedDirectories(dirs) {
|
|
@@ -174,38 +109,148 @@ function deduplicateAllowedDirectories(dirs) {
|
|
|
174
109
|
return deduplicated;
|
|
175
110
|
}
|
|
176
111
|
function parsePortOption(raw) {
|
|
177
|
-
|
|
112
|
+
// '' reads as unset: FS_PORT set-but-empty (compose templating) means stdio.
|
|
113
|
+
if (raw === undefined || raw === '')
|
|
178
114
|
return undefined;
|
|
179
115
|
const n = Number(raw);
|
|
180
116
|
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
181
|
-
throw new CliExitError(`Error: --port must be an integer between 1 and 65535`, 1);
|
|
117
|
+
throw new CliExitError(`Error: --port / FS_PORT must be an integer between 1 and 65535`, 1);
|
|
182
118
|
}
|
|
183
119
|
return n;
|
|
184
120
|
}
|
|
121
|
+
const CLI_PARSER_CONFIG = {
|
|
122
|
+
options: {
|
|
123
|
+
'allow-cwd': { type: 'boolean', default: false },
|
|
124
|
+
'read-only': { type: 'boolean', default: false },
|
|
125
|
+
safe: { type: 'boolean', default: false },
|
|
126
|
+
'print-config': { type: 'boolean', default: false },
|
|
127
|
+
json: { type: 'boolean', default: false },
|
|
128
|
+
port: { type: 'string' },
|
|
129
|
+
help: { type: 'boolean', short: 'h' },
|
|
130
|
+
version: { type: 'boolean', short: 'v' },
|
|
131
|
+
'log-level': { type: 'string' },
|
|
132
|
+
'http-host': { type: 'string' },
|
|
133
|
+
'api-key': { type: 'string' },
|
|
134
|
+
'allow-sensitive': { type: 'boolean', default: false },
|
|
135
|
+
'root-boundary': { type: 'string' },
|
|
136
|
+
'max-file-size': { type: 'string' },
|
|
137
|
+
'walk-cwd': { type: 'boolean', default: false },
|
|
138
|
+
deny: { type: 'string', multiple: true },
|
|
139
|
+
'allow-missing-roots': { type: 'boolean', default: false },
|
|
140
|
+
},
|
|
141
|
+
strict: true,
|
|
142
|
+
allowPositionals: true,
|
|
143
|
+
};
|
|
185
144
|
export async function parseArgs() {
|
|
186
|
-
const output = [];
|
|
187
|
-
const cli = createCliProgram(output);
|
|
188
145
|
try {
|
|
189
|
-
|
|
146
|
+
const parsed = utilParseArgs(CLI_PARSER_CONFIG);
|
|
147
|
+
if (parsed.values.help) {
|
|
148
|
+
printHelpAndExit();
|
|
149
|
+
}
|
|
150
|
+
if (parsed.values.version) {
|
|
151
|
+
printVersionAndExit();
|
|
152
|
+
}
|
|
153
|
+
for (const positional of parsed.positionals) {
|
|
154
|
+
validateCliPath(positional);
|
|
155
|
+
}
|
|
156
|
+
const vals = parsed.values;
|
|
157
|
+
// `--http-host` and `--api-key` are returned to the caller and handed to
|
|
158
|
+
// the server as config. Every other flag lands in the CLI-override store
|
|
159
|
+
// (core/config.ts) — the one owner of the flag-beats-env rule — which deep
|
|
160
|
+
// core readers (path, sensitive, observability, util) consult before
|
|
161
|
+
// falling back to the operator's environment. Nothing writes process.env.
|
|
162
|
+
const httpHost = typeof vals['http-host'] === 'string' ? vals['http-host'] : process.env['FS_HTTP_HOST'];
|
|
163
|
+
const apiKey = typeof vals['api-key'] === 'string' ? vals['api-key'] : process.env['FS_API_KEY'];
|
|
164
|
+
if (typeof vals['log-level'] === 'string')
|
|
165
|
+
cli.logLevel = vals['log-level'];
|
|
166
|
+
if (typeof vals['max-file-size'] === 'string')
|
|
167
|
+
cli.maxFileSize = vals['max-file-size'];
|
|
168
|
+
if (typeof vals['root-boundary'] === 'string')
|
|
169
|
+
cli.rootBoundary = vals['root-boundary'];
|
|
170
|
+
if (vals['allow-sensitive'] === true)
|
|
171
|
+
cli.allowSensitive = true;
|
|
172
|
+
if (vals['walk-cwd'] === true)
|
|
173
|
+
cli.allowCwdWalk = true;
|
|
174
|
+
if (vals['allow-missing-roots'] === true)
|
|
175
|
+
cli.allowMissingRoots = true;
|
|
176
|
+
if (Array.isArray(vals['deny'])) {
|
|
177
|
+
const denyPatterns = vals['deny']
|
|
178
|
+
.filter((entry) => typeof entry === 'string')
|
|
179
|
+
.map((entry) => entry.trim())
|
|
180
|
+
.filter(Boolean);
|
|
181
|
+
if (denyPatterns.length > 0)
|
|
182
|
+
cli.denyPatterns = [...new Set(denyPatterns)];
|
|
183
|
+
}
|
|
184
|
+
const allowCwd = vals['allow-cwd'] ||
|
|
185
|
+
vals['walk-cwd'] ||
|
|
186
|
+
parseTrueEnvFlag(process.env['FS_ALLOW_CWD_WALK'], 'FS_ALLOW_CWD_WALK');
|
|
187
|
+
const readOnly = vals['read-only'] || vals['safe'];
|
|
188
|
+
const printConfig = vals['print-config'];
|
|
189
|
+
const json = vals['json'];
|
|
190
|
+
const port = parsePortOption(parsed.values.port ?? process.env['FS_PORT']);
|
|
191
|
+
const allowMissingRoots = vals['allow-missing-roots'] ||
|
|
192
|
+
parseTrueEnvFlag(process.env['FS_ALLOW_MISSING_ROOTS'], 'FS_ALLOW_MISSING_ROOTS');
|
|
193
|
+
let allowedDirs = [];
|
|
194
|
+
try {
|
|
195
|
+
allowedDirs =
|
|
196
|
+
parsed.positionals.length > 0
|
|
197
|
+
? await normalizeAndValidateDirs(parsed.positionals, allowMissingRoots)
|
|
198
|
+
: [];
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
throw new CliExitError(normalizeCliExitMessage(error), 1);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
allowedDirs,
|
|
205
|
+
allowCwd,
|
|
206
|
+
port,
|
|
207
|
+
readOnly,
|
|
208
|
+
printConfig,
|
|
209
|
+
json,
|
|
210
|
+
httpHost,
|
|
211
|
+
apiKey,
|
|
212
|
+
};
|
|
190
213
|
}
|
|
191
214
|
catch (error) {
|
|
192
|
-
if (error instanceof
|
|
193
|
-
throw
|
|
215
|
+
if (error instanceof CliExitError) {
|
|
216
|
+
throw error;
|
|
194
217
|
}
|
|
195
|
-
throw error;
|
|
218
|
+
throw new CliExitError(normalizeCliExitMessage(error), 1);
|
|
196
219
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
220
|
+
}
|
|
221
|
+
export async function runPrintConfig(options) {
|
|
222
|
+
const write = options.stdout ?? ((s) => process.stdout.write(s));
|
|
223
|
+
const pathGuard = new PathGuard({
|
|
224
|
+
allowCwd: options.allowCwd,
|
|
225
|
+
cliAllowedDirs: options.allowedDirs,
|
|
226
|
+
});
|
|
227
|
+
await pathGuard.recomputeAllowedDirectories();
|
|
228
|
+
const allowedRoots = pathGuard.getAllowedDirectories();
|
|
229
|
+
const tools = registeredTools(options.readOnly).map((t) => t.name);
|
|
230
|
+
// Derived, never assumed: `--print-config --port 3000` reports the HTTP bind
|
|
231
|
+
// that `--port` would actually have started, not the stdio default.
|
|
232
|
+
const config = {
|
|
233
|
+
transport: options.port !== undefined
|
|
234
|
+
? `http://${options.httpHost ?? '127.0.0.1'}:${String(options.port)}`
|
|
235
|
+
: 'stdio',
|
|
236
|
+
readOnly: options.readOnly,
|
|
237
|
+
allowedRoots,
|
|
238
|
+
tools,
|
|
239
|
+
apiKey: options.apiKey ? '***' : null,
|
|
240
|
+
limits: { maxFileSizeBytes: getMaxTextFileSize() },
|
|
241
|
+
};
|
|
242
|
+
if (options.json) {
|
|
243
|
+
write(JSON.stringify(config, null, 2));
|
|
205
244
|
}
|
|
206
|
-
|
|
207
|
-
|
|
245
|
+
else {
|
|
246
|
+
const key = (k) => padEndVisible(cliFmt.cyan(k), 14);
|
|
247
|
+
write(`${key('transport:')}${config.transport}\n`);
|
|
248
|
+
write(`${key('readOnly:')}${cliFmt.bool(config.readOnly)}\n`);
|
|
249
|
+
write(`${key('apiKey:')}${cliFmt.dim(config.apiKey ?? 'none')}\n`);
|
|
250
|
+
write(`${key('allowedRoots:')}${config.allowedRoots.join(', ') || cliFmt.dim('(none)')}\n`);
|
|
251
|
+
write(`${key('tools:')}${cliFmt.dim(config.tools.join(', '))}\n`);
|
|
252
|
+
write(`${key('maxFileSize:')}${cliFmt.yellow(String(config.limits.maxFileSizeBytes))}\n`);
|
|
208
253
|
}
|
|
209
|
-
|
|
210
|
-
return { allowedDirs: deduplicatedDirs, allowCwd, port };
|
|
254
|
+
return config;
|
|
211
255
|
}
|
|
256
|
+
//# sourceMappingURL=cli.js.map
|