@j0hanz/filesystem-context-mcp 1.0.4 → 1.0.7
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 +27 -26
- package/dist/config/types.d.ts +1 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/instructions.md +209 -0
- package/dist/lib/directory-helpers.d.ts +5 -0
- package/dist/lib/directory-helpers.d.ts.map +1 -0
- package/dist/lib/directory-helpers.js +39 -0
- package/dist/lib/directory-helpers.js.map +1 -0
- package/dist/lib/file-operations.d.ts.map +1 -1
- package/dist/lib/file-operations.js +9 -74
- package/dist/lib/file-operations.js.map +1 -1
- package/dist/lib/fs-helpers.d.ts.map +1 -1
- package/dist/lib/fs-helpers.js +0 -5
- package/dist/lib/fs-helpers.js.map +1 -1
- package/dist/lib/mcp-logger.d.ts +11 -0
- package/dist/lib/mcp-logger.d.ts.map +1 -0
- package/dist/lib/mcp-logger.js +45 -0
- package/dist/lib/mcp-logger.js.map +1 -0
- package/dist/lib/sorting.d.ts +12 -0
- package/dist/lib/sorting.d.ts.map +1 -0
- package/dist/lib/sorting.js +41 -0
- package/dist/lib/sorting.js.map +1 -0
- package/dist/prompts/analyze-codebase.d.ts +3 -0
- package/dist/prompts/analyze-codebase.d.ts.map +1 -0
- package/dist/prompts/analyze-codebase.js +144 -0
- package/dist/prompts/analyze-codebase.js.map +1 -0
- package/dist/prompts/filesystem-query.d.ts +3 -0
- package/dist/prompts/filesystem-query.d.ts.map +1 -0
- package/dist/prompts/filesystem-query.js +168 -0
- package/dist/prompts/filesystem-query.js.map +1 -0
- package/dist/prompts/find-duplicates.d.ts +3 -0
- package/dist/prompts/find-duplicates.d.ts.map +1 -0
- package/dist/prompts/find-duplicates.js +77 -0
- package/dist/prompts/find-duplicates.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +13 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/project-overview.d.ts +3 -0
- package/dist/prompts/project-overview.d.ts.map +1 -0
- package/dist/prompts/project-overview.js +122 -0
- package/dist/prompts/project-overview.js.map +1 -0
- package/dist/prompts/search-and-replace.d.ts +3 -0
- package/dist/prompts/search-and-replace.d.ts.map +1 -0
- package/dist/prompts/search-and-replace.js +130 -0
- package/dist/prompts/search-and-replace.js.map +1 -0
- package/dist/prompts/shared.d.ts +3 -0
- package/dist/prompts/shared.d.ts.map +1 -0
- package/dist/prompts/shared.js +17 -0
- package/dist/prompts/shared.js.map +1 -0
- package/dist/resources/index.d.ts +3 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +54 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/schemas/inputs.d.ts.map +1 -1
- package/dist/schemas/inputs.js +11 -7
- package/dist/schemas/inputs.js.map +1 -1
- package/dist/schemas/outputs.d.ts +10 -8
- package/dist/schemas/outputs.d.ts.map +1 -1
- package/dist/schemas/outputs.js +2 -0
- package/dist/schemas/outputs.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +37 -15
- package/dist/server.js.map +1 -1
- package/dist/tools/analyze-directory.d.ts.map +1 -1
- package/dist/tools/analyze-directory.js +14 -4
- package/dist/tools/analyze-directory.js.map +1 -1
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +19 -2
- package/dist/tools/directory-tree.js.map +1 -1
- package/dist/tools/get-file-info.d.ts.map +1 -1
- package/dist/tools/get-file-info.js +5 -1
- package/dist/tools/get-file-info.js.map +1 -1
- package/dist/tools/list-allowed-dirs.d.ts.map +1 -1
- package/dist/tools/list-allowed-dirs.js +16 -2
- package/dist/tools/list-allowed-dirs.js.map +1 -1
- package/dist/tools/list-directory.d.ts.map +1 -1
- package/dist/tools/list-directory.js +19 -7
- package/dist/tools/list-directory.js.map +1 -1
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +6 -1
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/read-media-file.d.ts.map +1 -1
- package/dist/tools/read-media-file.js +5 -1
- package/dist/tools/read-media-file.js.map +1 -1
- package/dist/tools/read-multiple-files.d.ts.map +1 -1
- package/dist/tools/read-multiple-files.js +5 -1
- package/dist/tools/read-multiple-files.js.map +1 -1
- package/dist/tools/search-content.d.ts.map +1 -1
- package/dist/tools/search-content.js +44 -4
- package/dist/tools/search-content.js.map +1 -1
- package/dist/tools/search-files.d.ts.map +1 -1
- package/dist/tools/search-files.js +19 -4
- package/dist/tools/search-files.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ A secure, read-only MCP server for filesystem scanning, searching, and analysis
|
|
|
5
5
|
[](https://www.npmjs.com/package/@j0hanz/filesystem-context-mcp)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://nodejs.org)
|
|
8
|
-
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
9
|
[](https://modelcontextprotocol.io)
|
|
10
10
|
|
|
11
11
|
## One-Click Install
|
|
@@ -196,7 +196,7 @@ Search for files using glob patterns.
|
|
|
196
196
|
| `path` | string | ✅ | - | Base directory to search from |
|
|
197
197
|
| `pattern` | string | ✅ | - | Glob pattern (e.g., `**/*.ts`, `src/**/*.js`) |
|
|
198
198
|
| `excludePatterns` | string[] | ❌ | `[]` | Patterns to exclude |
|
|
199
|
-
| `maxResults` | number | ❌ | - | Maximum matches to return (
|
|
199
|
+
| `maxResults` | number | ❌ | - | Maximum matches to return (max 10,000) |
|
|
200
200
|
| `sortBy` | string | ❌ | `path` | Sort by: `name`, `size`, `modified`, `path` |
|
|
201
201
|
| `maxDepth` | number | ❌ | - | Maximum directory depth to search (1-100) |
|
|
202
202
|
|
|
@@ -218,15 +218,15 @@ Search for files using glob patterns.
|
|
|
218
218
|
|
|
219
219
|
Read the contents of a text file.
|
|
220
220
|
|
|
221
|
-
| Parameter | Type | Required | Default | Description
|
|
222
|
-
| ----------- | ------ | -------- | ------- |
|
|
223
|
-
| `path` | string | ✅ | - | File path to read
|
|
224
|
-
| `encoding` | string | ❌ | `utf-8` | File encoding (`utf-8`, `ascii`, `base64`, etc.)
|
|
225
|
-
| `maxSize` | number | ❌ | 10MB | Maximum file size in bytes
|
|
226
|
-
| `lineStart` | number | ❌ | - | Start line (1-indexed) for reading a range
|
|
227
|
-
| `lineEnd` | number | ❌ | - | End line (inclusive) for reading a range
|
|
228
|
-
| `head` | number | ❌ | - | Read only first N lines
|
|
229
|
-
| `tail` | number | ❌ | - | Read only last N lines
|
|
221
|
+
| Parameter | Type | Required | Default | Description |
|
|
222
|
+
| ----------- | ------ | -------- | ------- | ---------------------------------------------------------- |
|
|
223
|
+
| `path` | string | ✅ | - | File path to read |
|
|
224
|
+
| `encoding` | string | ❌ | `utf-8` | File encoding (`utf-8`, `ascii`, `base64`, etc.) |
|
|
225
|
+
| `maxSize` | number | ❌ | 10MB | Maximum file size in bytes |
|
|
226
|
+
| `lineStart` | number | ❌ | - | Start line (1-indexed, min 1) for reading a range |
|
|
227
|
+
| `lineEnd` | number | ❌ | - | End line (1-indexed, inclusive, min 1) for reading a range |
|
|
228
|
+
| `head` | number | ❌ | - | Read only first N lines |
|
|
229
|
+
| `tail` | number | ❌ | - | Read only last N lines |
|
|
230
230
|
|
|
231
231
|
> **Note:** Cannot specify both `head` and `tail` simultaneously. Use `lineStart`/`lineEnd` for range reading.
|
|
232
232
|
|
|
@@ -301,13 +301,13 @@ Search for text content within files using regular expressions.
|
|
|
301
301
|
|
|
302
302
|
Analyze a directory structure and return statistics.
|
|
303
303
|
|
|
304
|
-
| Parameter | Type | Required | Default | Description
|
|
305
|
-
| ----------------- | -------- | -------- | ------- |
|
|
306
|
-
| `path` | string | ✅ | - | Directory to analyze
|
|
307
|
-
| `maxDepth` | number | ❌ | `10` | Maximum depth to analyze (0-100)
|
|
308
|
-
| `topN` | number | ❌ | `10` | Number of top items to return (
|
|
309
|
-
| `excludePatterns` | string[] | ❌ | `[]` | Glob patterns to exclude
|
|
310
|
-
| `includeHidden` | boolean | ❌ | `false` | Include hidden files and directories
|
|
304
|
+
| Parameter | Type | Required | Default | Description |
|
|
305
|
+
| ----------------- | -------- | -------- | ------- | ---------------------------------------- |
|
|
306
|
+
| `path` | string | ✅ | - | Directory to analyze |
|
|
307
|
+
| `maxDepth` | number | ❌ | `10` | Maximum depth to analyze (0-100) |
|
|
308
|
+
| `topN` | number | ❌ | `10` | Number of top items to return (max 1000) |
|
|
309
|
+
| `excludePatterns` | string[] | ❌ | `[]` | Glob patterns to exclude |
|
|
310
|
+
| `includeHidden` | boolean | ❌ | `false` | Include hidden files and directories |
|
|
311
311
|
|
|
312
312
|
**Returns:** Statistics including total files/directories, total size, file type distribution, largest files, and recently modified files.
|
|
313
313
|
|
|
@@ -317,14 +317,14 @@ Analyze a directory structure and return statistics.
|
|
|
317
317
|
|
|
318
318
|
Get a JSON tree structure of a directory, optimized for AI parsing.
|
|
319
319
|
|
|
320
|
-
| Parameter | Type | Required | Default | Description
|
|
321
|
-
| ----------------- | -------- | -------- | ------- |
|
|
322
|
-
| `path` | string | ✅ | - | Directory path to build tree from
|
|
323
|
-
| `maxDepth` | number | ❌ | `5` | Maximum depth to traverse (0-50)
|
|
324
|
-
| `excludePatterns` | string[] | ❌ | `[]` | Glob patterns to exclude
|
|
325
|
-
| `includeHidden` | boolean | ❌ | `false` | Include hidden files and directories
|
|
326
|
-
| `includeSize` | boolean | ❌ | `false` | Include file sizes in the tree
|
|
327
|
-
| `maxFiles` | number | ❌ | - | Maximum total files to include (
|
|
320
|
+
| Parameter | Type | Required | Default | Description |
|
|
321
|
+
| ----------------- | -------- | -------- | ------- | -------------------------------------------- |
|
|
322
|
+
| `path` | string | ✅ | - | Directory path to build tree from |
|
|
323
|
+
| `maxDepth` | number | ❌ | `5` | Maximum depth to traverse (0-50) |
|
|
324
|
+
| `excludePatterns` | string[] | ❌ | `[]` | Glob patterns to exclude |
|
|
325
|
+
| `includeHidden` | boolean | ❌ | `false` | Include hidden files and directories |
|
|
326
|
+
| `includeSize` | boolean | ❌ | `false` | Include file sizes in the tree |
|
|
327
|
+
| `maxFiles` | number | ❌ | - | Maximum total files to include (max 100,000) |
|
|
328
328
|
|
|
329
329
|
**Returns:** Hierarchical tree structure with file/directory nodes.
|
|
330
330
|
|
|
@@ -500,6 +500,7 @@ This server implements multiple layers of security:
|
|
|
500
500
|
src/
|
|
501
501
|
├── index.ts # Entry point, CLI argument parsing
|
|
502
502
|
├── server.ts # MCP server setup, roots protocol handling
|
|
503
|
+
├── instructions.md # AI instructions for tool usage (bundled with dist)
|
|
503
504
|
├── config/
|
|
504
505
|
│ └── types.ts # Shared TypeScript types
|
|
505
506
|
├── lib/
|
package/dist/config/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,IAAI,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE;QACP,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,OAAO,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,EAAE;QACP,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,6BAA6B,EAAE,MAAM,CAAC;QACtC,aAAa,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;KACvD,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/C,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;IACrD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,EAAE;QACP,SAAS,EAAE,OAAO,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,OAAO,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,SAAS;;;;;;;;;;;;;;CAcZ,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Filesystem Context MCP Server
|
|
2
|
+
|
|
3
|
+
> **Read-only** tools for exploring directories, searching files, and analyzing codebases via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/).
|
|
4
|
+
|
|
5
|
+
This server enables AI assistants to safely explore and analyze filesystem contents without modification capabilities. All operations are sandboxed to explicitly allowed directories.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Goal | Tool | Key Parameters |
|
|
12
|
+
| ------------------- | -------------------------- | ----------------------------------- |
|
|
13
|
+
| Check access | `list_allowed_directories` | — |
|
|
14
|
+
| Project structure | `directory_tree` | `maxDepth`, `excludePatterns` |
|
|
15
|
+
| List contents | `list_directory` | `recursive`, `sortBy` |
|
|
16
|
+
| Directory stats | `analyze_directory` | `topN`, `excludePatterns` |
|
|
17
|
+
| Find files | `search_files` | `pattern` (glob), `maxResults` |
|
|
18
|
+
| Search in files | `search_content` | `pattern` (regex), `contextLines` |
|
|
19
|
+
| Read file | `read_file` | `head`, `tail`, `lineStart/lineEnd` |
|
|
20
|
+
| Read multiple files | `read_multiple_files` | `paths[]` — **preferred for 2+** |
|
|
21
|
+
| File metadata | `get_file_info` | `path` |
|
|
22
|
+
| Binary/media files | `read_media_file` | `maxSize` |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Workflows
|
|
27
|
+
|
|
28
|
+
### Project Discovery
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
list_allowed_directories → directory_tree(maxDepth=3) → analyze_directory → read_multiple_files([package.json, README.md])
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Find & Read Code
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
search_files(pattern="**/*.ts") → read_multiple_files([...results])
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Search Patterns
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
search_content(pattern="TODO|FIXME", filePattern="**/*.ts", contextLines=2)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Common Glob Patterns
|
|
47
|
+
|
|
48
|
+
| Pattern | Matches |
|
|
49
|
+
| --------------------- | ----------------------------------------- |
|
|
50
|
+
| `**/*.ts` | All TypeScript files |
|
|
51
|
+
| `src/**/*.{js,jsx}` | JS/JSX files under `src/` |
|
|
52
|
+
| `**/test/**` | All files in any `test/` directory |
|
|
53
|
+
| `**/*.test.ts` | Test files by naming convention |
|
|
54
|
+
| `!**/node_modules/**` | Exclude `node_modules/` (use in excludes) |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Best Practices
|
|
59
|
+
|
|
60
|
+
**Do:**
|
|
61
|
+
|
|
62
|
+
- Use `read_multiple_files` for 2+ files (parallel, resilient)
|
|
63
|
+
- Set `maxResults`, `maxDepth`, `maxEntries` limits
|
|
64
|
+
- Use `excludePatterns=["node_modules", ".git", "dist"]`
|
|
65
|
+
- Preview with `head=50` before full reads
|
|
66
|
+
|
|
67
|
+
**Don't:**
|
|
68
|
+
|
|
69
|
+
- Loop `read_file` — batch with `read_multiple_files`
|
|
70
|
+
- Recursive search without `maxDepth`
|
|
71
|
+
- Search without `maxResults` on large codebases
|
|
72
|
+
|
|
73
|
+
## Tool Details
|
|
74
|
+
|
|
75
|
+
### `directory_tree`
|
|
76
|
+
|
|
77
|
+
JSON tree structure for AI parsing.
|
|
78
|
+
|
|
79
|
+
| Parameter | Default | Description |
|
|
80
|
+
| ----------------- | ------- | --------------------- |
|
|
81
|
+
| `path` | — | Directory path |
|
|
82
|
+
| `maxDepth` | 5 | Depth limit (0-50) |
|
|
83
|
+
| `excludePatterns` | [] | Glob patterns to skip |
|
|
84
|
+
| `includeHidden` | false | Include dotfiles |
|
|
85
|
+
| `includeSize` | false | Show file sizes |
|
|
86
|
+
| `maxFiles` | — | Limit total files |
|
|
87
|
+
|
|
88
|
+
### `search_files`
|
|
89
|
+
|
|
90
|
+
Find files by glob pattern.
|
|
91
|
+
|
|
92
|
+
| Parameter | Default | Description |
|
|
93
|
+
| ----------------- | ------- | ------------------------- |
|
|
94
|
+
| `path` | — | Base directory |
|
|
95
|
+
| `pattern` | — | Glob: `**/*.ts`, `src/**` |
|
|
96
|
+
| `excludePatterns` | [] | Patterns to skip |
|
|
97
|
+
| `maxResults` | — | Limit (up to 10,000) |
|
|
98
|
+
| `sortBy` | "path" | `name/size/modified/path` |
|
|
99
|
+
|
|
100
|
+
### `search_content`
|
|
101
|
+
|
|
102
|
+
Grep-like regex search in files.
|
|
103
|
+
|
|
104
|
+
| Parameter | Default | Description |
|
|
105
|
+
| --------------- | ------- | ------------------------- |
|
|
106
|
+
| `path` | — | Base directory |
|
|
107
|
+
| `pattern` | — | Regex: `TODO\|FIXME` |
|
|
108
|
+
| `filePattern` | `**/*` | Glob filter |
|
|
109
|
+
| `contextLines` | 0 | Lines before/after (0-10) |
|
|
110
|
+
| `caseSensitive` | false | Case matching |
|
|
111
|
+
| `wholeWord` | false | Word boundaries |
|
|
112
|
+
| `isLiteral` | false | Escape regex |
|
|
113
|
+
| `maxResults` | 100 | Limit matches |
|
|
114
|
+
| `skipBinary` | true | Skip binary files |
|
|
115
|
+
|
|
116
|
+
### `read_file`
|
|
117
|
+
|
|
118
|
+
Read single file with line selection.
|
|
119
|
+
|
|
120
|
+
| Parameter | Default | Description |
|
|
121
|
+
| ----------- | ------- | ------------------------------- |
|
|
122
|
+
| `path` | — | File path |
|
|
123
|
+
| `encoding` | utf-8 | `utf-8/ascii/base64/hex/latin1` |
|
|
124
|
+
| `maxSize` | 10MB | Size limit |
|
|
125
|
+
| `head` | — | First N lines |
|
|
126
|
+
| `tail` | — | Last N lines |
|
|
127
|
+
| `lineStart` | — | Start line (1-indexed) |
|
|
128
|
+
| `lineEnd` | — | End line (inclusive) |
|
|
129
|
+
|
|
130
|
+
> ⚠️ Cannot combine `head/tail` with `lineStart/lineEnd`
|
|
131
|
+
|
|
132
|
+
### `read_multiple_files`
|
|
133
|
+
|
|
134
|
+
Parallel batch reads — failures don't block others.
|
|
135
|
+
|
|
136
|
+
| Parameter | Default | Description |
|
|
137
|
+
| ---------- | ------- | ------------------ |
|
|
138
|
+
| `paths` | — | Array (max 100) |
|
|
139
|
+
| `encoding` | utf-8 | Encoding for all |
|
|
140
|
+
| `maxSize` | 10MB | Per-file limit |
|
|
141
|
+
| `head` | — | First N lines each |
|
|
142
|
+
| `tail` | — | Last N lines each |
|
|
143
|
+
|
|
144
|
+
### `list_directory`
|
|
145
|
+
|
|
146
|
+
Flat listing with metadata.
|
|
147
|
+
|
|
148
|
+
| Parameter | Default | Description |
|
|
149
|
+
| ------------ | ------- | ------------------------- |
|
|
150
|
+
| `path` | — | Directory path |
|
|
151
|
+
| `recursive` | false | Include subdirs |
|
|
152
|
+
| `sortBy` | "name" | `name/size/modified/type` |
|
|
153
|
+
| `maxDepth` | 10 | Depth when recursive |
|
|
154
|
+
| `maxEntries` | — | Limit (up to 100,000) |
|
|
155
|
+
|
|
156
|
+
### `analyze_directory`
|
|
157
|
+
|
|
158
|
+
Statistics: counts, sizes, types, largest/recent files.
|
|
159
|
+
|
|
160
|
+
| Parameter | Default | Description |
|
|
161
|
+
| ----------------- | ------- | ------------------ |
|
|
162
|
+
| `path` | — | Directory path |
|
|
163
|
+
| `maxDepth` | 10 | Analysis depth |
|
|
164
|
+
| `topN` | 10 | Top largest/recent |
|
|
165
|
+
| `excludePatterns` | [] | Patterns to skip |
|
|
166
|
+
|
|
167
|
+
### `read_media_file`
|
|
168
|
+
|
|
169
|
+
Binary files as base64 with MIME type and dimensions.
|
|
170
|
+
|
|
171
|
+
| Parameter | Default | Description |
|
|
172
|
+
| --------- | ------- | --------------- |
|
|
173
|
+
| `path` | — | Media file path |
|
|
174
|
+
| `maxSize` | 50MB | Size limit |
|
|
175
|
+
|
|
176
|
+
### `get_file_info`
|
|
177
|
+
|
|
178
|
+
Detailed metadata about a file or directory.
|
|
179
|
+
|
|
180
|
+
| Parameter | Default | Description |
|
|
181
|
+
| --------- | ------- | ------------------------- |
|
|
182
|
+
| `path` | — | Path to file or directory |
|
|
183
|
+
|
|
184
|
+
**Returns:** name, path, type, size, created, modified, accessed, permissions, isHidden, mimeType, symlinkTarget (if applicable).
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Error Codes
|
|
189
|
+
|
|
190
|
+
| Code | Cause | Solution |
|
|
191
|
+
| --------------------- | ---------------------------- | ------------------------------------- |
|
|
192
|
+
| `E_ACCESS_DENIED` | Path outside allowed dirs | Check `list_allowed_directories` |
|
|
193
|
+
| `E_NOT_FOUND` | Path doesn't exist | Verify path with `list_directory` |
|
|
194
|
+
| `E_NOT_FILE` | Expected file, got directory | Use `list_directory` instead |
|
|
195
|
+
| `E_NOT_DIRECTORY` | Expected directory, got file | Use `read_file` instead |
|
|
196
|
+
| `E_TOO_LARGE` | File exceeds size limit | Use `head/tail` or increase `maxSize` |
|
|
197
|
+
| `E_BINARY_FILE` | Binary in text operation | Use `read_media_file` |
|
|
198
|
+
| `E_TIMEOUT` | Operation took too long | Reduce limits |
|
|
199
|
+
| `E_INVALID_PATTERN` | Malformed glob/regex | Check glob/regex syntax |
|
|
200
|
+
| `E_PERMISSION_DENIED` | OS-level access denied | Check file permissions |
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Security
|
|
205
|
+
|
|
206
|
+
- **Read-only** — no writes, deletes, or modifications
|
|
207
|
+
- **Path validation** — symlinks cannot escape allowed directories
|
|
208
|
+
- **Binary detection** — prevents accidental base64 bloat
|
|
209
|
+
- **Input sanitization** — patterns validated for ReDoS protection
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function createExcludeMatcher(excludePatterns: string[]): (name: string, relativePath: string) => boolean;
|
|
2
|
+
export declare function handleDirectoryError(error: unknown): void;
|
|
3
|
+
export declare function classifyAccessError(error: unknown): 'symlink' | 'inaccessible';
|
|
4
|
+
export declare function insertSorted<T>(arr: T[], item: T, compare: (a: T, b: T) => boolean, maxLen: number): void;
|
|
5
|
+
//# sourceMappingURL=directory-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/directory-helpers.ts"],"names":[],"mappings":"AAKA,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,EAAE,GACxB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAOjD;AAGD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEzD;AAGD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,GACb,SAAS,GAAG,cAAc,CAS5B;AAGD,wBAAgB,YAAY,CAAC,CAAC,EAC5B,GAAG,EAAE,CAAC,EAAE,EACR,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,EAChC,MAAM,EAAE,MAAM,GACb,IAAI,CASN"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Minimatch } from 'minimatch';
|
|
2
|
+
import { ErrorCode, McpError } from './errors.js';
|
|
3
|
+
// Create matcher from exclude patterns
|
|
4
|
+
export function createExcludeMatcher(excludePatterns) {
|
|
5
|
+
if (excludePatterns.length === 0) {
|
|
6
|
+
return () => false;
|
|
7
|
+
}
|
|
8
|
+
const matchers = excludePatterns.map((pattern) => new Minimatch(pattern));
|
|
9
|
+
return (name, relativePath) => matchers.some((m) => m.match(name) || m.match(relativePath));
|
|
10
|
+
}
|
|
11
|
+
// Handle directory traversal errors (silently ignored to avoid log noise)
|
|
12
|
+
export function handleDirectoryError(error) {
|
|
13
|
+
void error.code;
|
|
14
|
+
}
|
|
15
|
+
// Classify symlink/access errors for summary tracking
|
|
16
|
+
export function classifyAccessError(error) {
|
|
17
|
+
if (error instanceof McpError &&
|
|
18
|
+
(error.code === ErrorCode.E_ACCESS_DENIED ||
|
|
19
|
+
error.code === ErrorCode.E_SYMLINK_NOT_ALLOWED)) {
|
|
20
|
+
return 'symlink';
|
|
21
|
+
}
|
|
22
|
+
return 'inaccessible';
|
|
23
|
+
}
|
|
24
|
+
// Insert item into sorted array maintaining sort order (descending by comparator)
|
|
25
|
+
export function insertSorted(arr, item, compare, maxLen) {
|
|
26
|
+
if (maxLen <= 0)
|
|
27
|
+
return;
|
|
28
|
+
const idx = arr.findIndex((el) => compare(item, el));
|
|
29
|
+
if (idx === -1) {
|
|
30
|
+
if (arr.length < maxLen)
|
|
31
|
+
arr.push(item);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
arr.splice(idx, 0, item);
|
|
35
|
+
if (arr.length > maxLen)
|
|
36
|
+
arr.pop();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=directory-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-helpers.js","sourceRoot":"","sources":["../../src/lib/directory-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAElD,uCAAuC;AACvC,MAAM,UAAU,oBAAoB,CAClC,eAAyB;IAEzB,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC;IACrB,CAAC;IACD,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1E,OAAO,CAAC,IAAY,EAAE,YAAoB,EAAW,EAAE,CACrD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,KAAM,KAA+B,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,mBAAmB,CACjC,KAAc;IAEd,IACE,KAAK,YAAY,QAAQ;QACzB,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,eAAe;YACvC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,qBAAqB,CAAC,EACjD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAC1B,GAAQ,EACR,IAAO,EACP,OAAgC,EAChC,MAAc;IAEd,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO;IACxB,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACrD,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,IAAI,GAAG,CAAC,MAAM,GAAG,MAAM;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACzB,IAAI,GAAG,CAAC,MAAM,GAAG,MAAM;YAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IACrC,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-operations.d.ts","sourceRoot":"","sources":["../../src/lib/file-operations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-operations.d.ts","sourceRoot":"","sources":["../../src/lib/file-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,21 +3,14 @@ import * as path from 'node:path';
|
|
|
3
3
|
import * as readline from 'node:readline';
|
|
4
4
|
import { createReadStream } from 'node:fs';
|
|
5
5
|
import fg from 'fast-glob';
|
|
6
|
-
import { Minimatch } from 'minimatch';
|
|
7
6
|
import safeRegex from 'safe-regex2';
|
|
8
7
|
import { DEFAULT_MAX_DEPTH, DEFAULT_MAX_RESULTS, DEFAULT_TOP_N, DIR_TRAVERSAL_CONCURRENCY, getMimeType, MAX_LINE_CONTENT_LENGTH, MAX_MEDIA_FILE_SIZE, MAX_SEARCHABLE_FILE_SIZE, MAX_TEXT_FILE_SIZE, PARALLEL_CONCURRENCY, REGEX_MATCH_TIMEOUT_MS, } from './constants.js';
|
|
8
|
+
import { classifyAccessError, createExcludeMatcher, handleDirectoryError, insertSorted, } from './directory-helpers.js';
|
|
9
9
|
import { ErrorCode, McpError } from './errors.js';
|
|
10
10
|
import { getFileType, isHidden, isProbablyBinary, readFile, runWorkQueue, } from './fs-helpers.js';
|
|
11
11
|
import { parseImageDimensions } from './image-parsing.js';
|
|
12
12
|
import { validateExistingPath, validateExistingPathDetailed, } from './path-validation.js';
|
|
13
|
-
|
|
14
|
-
function createExcludeMatcher(excludePatterns) {
|
|
15
|
-
if (excludePatterns.length === 0) {
|
|
16
|
-
return () => false;
|
|
17
|
-
}
|
|
18
|
-
const matchers = excludePatterns.map((pattern) => new Minimatch(pattern));
|
|
19
|
-
return (name, relativePath) => matchers.some((m) => m.match(name) || m.match(relativePath));
|
|
20
|
-
}
|
|
13
|
+
import { createSearchResultSorter, createSorter } from './sorting.js';
|
|
21
14
|
// Process items in parallel with controlled concurrency
|
|
22
15
|
async function processInParallel(items, processor, concurrency = PARALLEL_CONCURRENCY) {
|
|
23
16
|
const results = [];
|
|
@@ -64,12 +57,10 @@ function countRegexMatches(line, regex, timeoutMs = REGEX_MATCH_TIMEOUT_MS) {
|
|
|
64
57
|
}
|
|
65
58
|
// Check timeout periodically
|
|
66
59
|
if (count % 100 === 0 && Date.now() > deadline) {
|
|
67
|
-
console.error(`[countRegexMatches] Regex matching timed out after ${timeoutMs}ms on line (length: ${line.length})`);
|
|
68
60
|
return -1; // Signal timeout
|
|
69
61
|
}
|
|
70
62
|
// Safety check for runaway regex
|
|
71
63
|
if (iterations > maxIterations) {
|
|
72
|
-
console.error(`[countRegexMatches] Max iterations exceeded (${maxIterations}) on line (length: ${line.length})`);
|
|
73
64
|
return -1; // Signal runaway regex
|
|
74
65
|
}
|
|
75
66
|
}
|
|
@@ -181,10 +172,7 @@ export async function listDirectory(dirPath, options = {}) {
|
|
|
181
172
|
}
|
|
182
173
|
catch (error) {
|
|
183
174
|
skippedInaccessible++;
|
|
184
|
-
|
|
185
|
-
if (code !== 'ENOENT' && code !== 'EACCES' && code !== 'EPERM') {
|
|
186
|
-
console.error(`[listDirectory] Error reading directory ${currentPath}:`, error);
|
|
187
|
-
}
|
|
175
|
+
handleDirectoryError(error);
|
|
188
176
|
return;
|
|
189
177
|
}
|
|
190
178
|
const visibleItems = includeHidden
|
|
@@ -268,22 +256,7 @@ export async function listDirectory(dirPath, options = {}) {
|
|
|
268
256
|
enqueue(enqueueDir);
|
|
269
257
|
}
|
|
270
258
|
}, DIR_TRAVERSAL_CONCURRENCY);
|
|
271
|
-
entries.sort((
|
|
272
|
-
switch (sortBy) {
|
|
273
|
-
case 'size':
|
|
274
|
-
return (b.size ?? 0) - (a.size ?? 0);
|
|
275
|
-
case 'modified':
|
|
276
|
-
return (b.modified?.getTime() ?? 0) - (a.modified?.getTime() ?? 0);
|
|
277
|
-
case 'type':
|
|
278
|
-
if (a.type !== b.type) {
|
|
279
|
-
return a.type === 'directory' ? -1 : 1;
|
|
280
|
-
}
|
|
281
|
-
return a.name.localeCompare(b.name);
|
|
282
|
-
case 'name':
|
|
283
|
-
default:
|
|
284
|
-
return a.name.localeCompare(b.name);
|
|
285
|
-
}
|
|
286
|
-
});
|
|
259
|
+
entries.sort(createSorter(sortBy));
|
|
287
260
|
return {
|
|
288
261
|
path: validPath,
|
|
289
262
|
entries,
|
|
@@ -359,19 +332,7 @@ export async function searchFiles(basePath, pattern, excludePatterns = [], optio
|
|
|
359
332
|
}
|
|
360
333
|
}
|
|
361
334
|
await flushBatch();
|
|
362
|
-
results.sort((
|
|
363
|
-
switch (sortBy) {
|
|
364
|
-
case 'size':
|
|
365
|
-
return (b.size ?? 0) - (a.size ?? 0);
|
|
366
|
-
case 'modified':
|
|
367
|
-
return (b.modified?.getTime() ?? 0) - (a.modified?.getTime() ?? 0);
|
|
368
|
-
case 'name':
|
|
369
|
-
return path.basename(a.path).localeCompare(path.basename(b.path));
|
|
370
|
-
case 'path':
|
|
371
|
-
default:
|
|
372
|
-
return a.path.localeCompare(b.path);
|
|
373
|
-
}
|
|
374
|
-
});
|
|
335
|
+
results.sort(createSearchResultSorter(sortBy));
|
|
375
336
|
return {
|
|
376
337
|
basePath: validPath,
|
|
377
338
|
pattern,
|
|
@@ -427,11 +388,7 @@ export async function searchContent(basePath, searchPattern, options = {}) {
|
|
|
427
388
|
const needsReDoSCheck = !isLiteral && !isSimpleSafePattern(finalPattern);
|
|
428
389
|
if (needsReDoSCheck && !safeRegex(finalPattern)) {
|
|
429
390
|
throw new McpError(ErrorCode.E_INVALID_PATTERN, `Potentially unsafe regular expression (ReDoS risk): ${searchPattern}. ` +
|
|
430
|
-
'Avoid patterns with nested quantifiers, overlapping alternations, or exponential backtracking.', basePath, {
|
|
431
|
-
searchPattern,
|
|
432
|
-
finalPattern,
|
|
433
|
-
reason: 'ReDoS risk detected by safe-regex2',
|
|
434
|
-
});
|
|
391
|
+
'Avoid patterns with nested quantifiers, overlapping alternations, or exponential backtracking.', basePath, { reason: 'ReDoS risk detected' });
|
|
435
392
|
}
|
|
436
393
|
let regex;
|
|
437
394
|
try {
|
|
@@ -568,7 +525,6 @@ export async function searchContent(basePath, searchPattern, options = {}) {
|
|
|
568
525
|
const matchCount = countRegexMatches(line, regex);
|
|
569
526
|
if (matchCount < 0) {
|
|
570
527
|
linesSkippedDueToRegexTimeout++;
|
|
571
|
-
console.error(`[searchContent] Skipping line ${lineNumber} in ${validFile} due to regex timeout`);
|
|
572
528
|
if (lineBuffer) {
|
|
573
529
|
lineBuffer.push(trimmedLine);
|
|
574
530
|
}
|
|
@@ -646,20 +602,6 @@ export async function analyzeDirectory(dirPath, options = {}) {
|
|
|
646
602
|
const largestFiles = [];
|
|
647
603
|
const recentlyModified = [];
|
|
648
604
|
const shouldExclude = createExcludeMatcher(excludePatterns);
|
|
649
|
-
const insertSorted = (arr, item, compare, maxLen) => {
|
|
650
|
-
if (maxLen <= 0)
|
|
651
|
-
return;
|
|
652
|
-
const idx = arr.findIndex((el) => compare(item, el));
|
|
653
|
-
if (idx === -1) {
|
|
654
|
-
if (arr.length < maxLen)
|
|
655
|
-
arr.push(item);
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
arr.splice(idx, 0, item);
|
|
659
|
-
if (arr.length > maxLen)
|
|
660
|
-
arr.pop();
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
605
|
await runWorkQueue([{ currentPath: validPath, depth: 0 }], async ({ currentPath, depth }, enqueue) => {
|
|
664
606
|
if (depth > maxDepth)
|
|
665
607
|
return;
|
|
@@ -670,10 +612,7 @@ export async function analyzeDirectory(dirPath, options = {}) {
|
|
|
670
612
|
}
|
|
671
613
|
catch (error) {
|
|
672
614
|
skippedInaccessible++;
|
|
673
|
-
|
|
674
|
-
if (code !== 'ENOENT' && code !== 'EACCES' && code !== 'EPERM') {
|
|
675
|
-
console.error(`[analyzeDirectory] Error reading directory ${currentPath}:`, error);
|
|
676
|
-
}
|
|
615
|
+
handleDirectoryError(error);
|
|
677
616
|
return;
|
|
678
617
|
}
|
|
679
618
|
for (const item of items) {
|
|
@@ -711,9 +650,7 @@ export async function analyzeDirectory(dirPath, options = {}) {
|
|
|
711
650
|
}
|
|
712
651
|
}
|
|
713
652
|
catch (error) {
|
|
714
|
-
if (error
|
|
715
|
-
(error.code === ErrorCode.E_ACCESS_DENIED ||
|
|
716
|
-
error.code === ErrorCode.E_SYMLINK_NOT_ALLOWED)) {
|
|
653
|
+
if (classifyAccessError(error) === 'symlink') {
|
|
717
654
|
symlinksNotFollowed++;
|
|
718
655
|
}
|
|
719
656
|
else {
|
|
@@ -770,9 +707,7 @@ export async function getDirectoryTree(dirPath, options = {}) {
|
|
|
770
707
|
await validateExistingPathDetailed(currentPath));
|
|
771
708
|
}
|
|
772
709
|
catch (error) {
|
|
773
|
-
if (error
|
|
774
|
-
(error.code === ErrorCode.E_ACCESS_DENIED ||
|
|
775
|
-
error.code === ErrorCode.E_SYMLINK_NOT_ALLOWED)) {
|
|
710
|
+
if (classifyAccessError(error) === 'symlink') {
|
|
776
711
|
symlinksNotFollowed++;
|
|
777
712
|
}
|
|
778
713
|
else {
|