@j0hanz/filesystem-context-mcp 1.0.10 → 1.2.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.
Files changed (288) hide show
  1. package/README.md +112 -22
  2. package/dist/__tests__/lib/errors.test.js +3 -23
  3. package/dist/__tests__/lib/errors.test.js.map +1 -1
  4. package/dist/__tests__/lib/file-operations.test.js +34 -0
  5. package/dist/__tests__/lib/file-operations.test.js.map +1 -1
  6. package/dist/__tests__/lib/path-validation.test.js +8 -0
  7. package/dist/__tests__/lib/path-validation.test.js.map +1 -1
  8. package/dist/__tests__/schemas/validators.test.js +130 -124
  9. package/dist/__tests__/schemas/validators.test.js.map +1 -1
  10. package/dist/__tests__/security/filesystem-boundary.test.js +1 -1
  11. package/dist/__tests__/security/filesystem-boundary.test.js.map +1 -1
  12. package/dist/config/types.d.ts +1 -58
  13. package/dist/config/types.d.ts.map +1 -1
  14. package/dist/config/types.js +0 -2
  15. package/dist/config/types.js.map +1 -1
  16. package/dist/index.js +3 -5
  17. package/dist/index.js.map +1 -1
  18. package/dist/instructions.md +1 -2
  19. package/dist/lib/constants.d.ts +9 -7
  20. package/dist/lib/constants.d.ts.map +1 -1
  21. package/dist/lib/constants.js +89 -298
  22. package/dist/lib/constants.js.map +1 -1
  23. package/dist/lib/errors.d.ts +25 -1
  24. package/dist/lib/errors.d.ts.map +1 -1
  25. package/dist/lib/errors.js +4 -112
  26. package/dist/lib/errors.js.map +1 -1
  27. package/dist/lib/file-operations/analyze-directory.d.ts +8 -0
  28. package/dist/lib/file-operations/analyze-directory.d.ts.map +1 -0
  29. package/dist/lib/file-operations/analyze-directory.js +117 -0
  30. package/dist/lib/file-operations/analyze-directory.js.map +1 -0
  31. package/dist/lib/file-operations/directory-items.d.ts +20 -0
  32. package/dist/lib/file-operations/directory-items.d.ts.map +1 -0
  33. package/dist/lib/file-operations/directory-items.js +85 -0
  34. package/dist/lib/file-operations/directory-items.js.map +1 -0
  35. package/dist/lib/file-operations/directory-iteration.d.ts +17 -0
  36. package/dist/lib/file-operations/directory-iteration.d.ts.map +1 -0
  37. package/dist/lib/file-operations/directory-iteration.js +55 -0
  38. package/dist/lib/file-operations/directory-iteration.js.map +1 -0
  39. package/dist/lib/file-operations/directory-tree.d.ts +9 -0
  40. package/dist/lib/file-operations/directory-tree.d.ts.map +1 -0
  41. package/dist/lib/file-operations/directory-tree.js +175 -0
  42. package/dist/lib/file-operations/directory-tree.js.map +1 -0
  43. package/dist/lib/file-operations/file-info.d.ts +3 -0
  44. package/dist/lib/file-operations/file-info.d.ts.map +1 -0
  45. package/dist/lib/file-operations/file-info.js +56 -0
  46. package/dist/lib/file-operations/file-info.js.map +1 -0
  47. package/dist/lib/file-operations/list-directory.d.ts +10 -0
  48. package/dist/lib/file-operations/list-directory.d.ts.map +1 -0
  49. package/dist/lib/file-operations/list-directory.js +189 -0
  50. package/dist/lib/file-operations/list-directory.js.map +1 -0
  51. package/dist/lib/file-operations/read-media-file.d.ts +5 -0
  52. package/dist/lib/file-operations/read-media-file.d.ts.map +1 -0
  53. package/dist/lib/file-operations/read-media-file.js +31 -0
  54. package/dist/lib/file-operations/read-media-file.js.map +1 -0
  55. package/dist/lib/file-operations/read-multiple-files.d.ts +16 -0
  56. package/dist/lib/file-operations/read-multiple-files.d.ts.map +1 -0
  57. package/dist/lib/file-operations/read-multiple-files.js +98 -0
  58. package/dist/lib/file-operations/read-multiple-files.js.map +1 -0
  59. package/dist/lib/file-operations/search-content.d.ts +16 -0
  60. package/dist/lib/file-operations/search-content.d.ts.map +1 -0
  61. package/dist/lib/file-operations/search-content.js +431 -0
  62. package/dist/lib/file-operations/search-content.js.map +1 -0
  63. package/dist/lib/file-operations/search-files.d.ts +9 -0
  64. package/dist/lib/file-operations/search-files.d.ts.map +1 -0
  65. package/dist/lib/file-operations/search-files.js +139 -0
  66. package/dist/lib/file-operations/search-files.js.map +1 -0
  67. package/dist/lib/file-operations/sorting.d.ts +12 -0
  68. package/dist/lib/file-operations/sorting.d.ts.map +1 -0
  69. package/dist/lib/file-operations/sorting.js +24 -0
  70. package/dist/lib/file-operations/sorting.js.map +1 -0
  71. package/dist/lib/file-operations.d.ts +9 -57
  72. package/dist/lib/file-operations.d.ts.map +1 -1
  73. package/dist/lib/file-operations.js +9 -733
  74. package/dist/lib/file-operations.js.map +1 -1
  75. package/dist/lib/fs-helpers/binary-detect.d.ts +3 -0
  76. package/dist/lib/fs-helpers/binary-detect.d.ts.map +1 -0
  77. package/dist/lib/fs-helpers/binary-detect.js +54 -0
  78. package/dist/lib/fs-helpers/binary-detect.js.map +1 -0
  79. package/dist/lib/fs-helpers/concurrency.d.ts +11 -0
  80. package/dist/lib/fs-helpers/concurrency.d.ts.map +1 -0
  81. package/dist/lib/fs-helpers/concurrency.js +95 -0
  82. package/dist/lib/fs-helpers/concurrency.js.map +1 -0
  83. package/dist/lib/fs-helpers/fs-utils.d.ts +5 -0
  84. package/dist/lib/fs-helpers/fs-utils.d.ts.map +1 -0
  85. package/dist/lib/fs-helpers/fs-utils.js +13 -0
  86. package/dist/lib/fs-helpers/fs-utils.js.map +1 -0
  87. package/dist/lib/fs-helpers/readers/head-file.d.ts +2 -0
  88. package/dist/lib/fs-helpers/readers/head-file.d.ts.map +1 -0
  89. package/dist/lib/fs-helpers/readers/head-file.js +73 -0
  90. package/dist/lib/fs-helpers/readers/head-file.js.map +1 -0
  91. package/dist/lib/fs-helpers/readers/line-range.d.ts +7 -0
  92. package/dist/lib/fs-helpers/readers/line-range.d.ts.map +1 -0
  93. package/dist/lib/fs-helpers/readers/line-range.js +46 -0
  94. package/dist/lib/fs-helpers/readers/line-range.js.map +1 -0
  95. package/dist/lib/fs-helpers/readers/read-file.d.ts +16 -0
  96. package/dist/lib/fs-helpers/readers/read-file.d.ts.map +1 -0
  97. package/dist/lib/fs-helpers/readers/read-file.js +87 -0
  98. package/dist/lib/fs-helpers/readers/read-file.js.map +1 -0
  99. package/dist/lib/fs-helpers/readers/tail-file.d.ts +2 -0
  100. package/dist/lib/fs-helpers/readers/tail-file.d.ts.map +1 -0
  101. package/dist/lib/fs-helpers/readers/tail-file.js +98 -0
  102. package/dist/lib/fs-helpers/readers/tail-file.js.map +1 -0
  103. package/dist/lib/fs-helpers/readers/utf8.d.ts +3 -0
  104. package/dist/lib/fs-helpers/readers/utf8.d.ts.map +1 -0
  105. package/dist/lib/fs-helpers/readers/utf8.js +22 -0
  106. package/dist/lib/fs-helpers/readers/utf8.js.map +1 -0
  107. package/dist/lib/fs-helpers/readers.d.ts +4 -0
  108. package/dist/lib/fs-helpers/readers.d.ts.map +1 -0
  109. package/dist/lib/fs-helpers/readers.js +4 -0
  110. package/dist/lib/fs-helpers/readers.js.map +1 -0
  111. package/dist/lib/fs-helpers.d.ts +4 -25
  112. package/dist/lib/fs-helpers.d.ts.map +1 -1
  113. package/dist/lib/fs-helpers.js +4 -350
  114. package/dist/lib/fs-helpers.js.map +1 -1
  115. package/dist/lib/path-utils.d.ts.map +1 -1
  116. package/dist/lib/path-utils.js +0 -2
  117. package/dist/lib/path-utils.js.map +1 -1
  118. package/dist/lib/path-validation/allowed-directories.d.ts +9 -0
  119. package/dist/lib/path-validation/allowed-directories.d.ts.map +1 -0
  120. package/dist/lib/path-validation/allowed-directories.js +94 -0
  121. package/dist/lib/path-validation/allowed-directories.js.map +1 -0
  122. package/dist/lib/path-validation/errors.d.ts +5 -0
  123. package/dist/lib/path-validation/errors.d.ts.map +1 -0
  124. package/dist/lib/path-validation/errors.js +33 -0
  125. package/dist/lib/path-validation/errors.js.map +1 -0
  126. package/dist/lib/path-validation/roots.d.ts +3 -0
  127. package/dist/lib/path-validation/roots.d.ts.map +1 -0
  128. package/dist/lib/path-validation/roots.js +49 -0
  129. package/dist/lib/path-validation/roots.js.map +1 -0
  130. package/dist/lib/path-validation/validators.d.ts +9 -0
  131. package/dist/lib/path-validation/validators.d.ts.map +1 -0
  132. package/dist/lib/path-validation/validators.js +70 -0
  133. package/dist/lib/path-validation/validators.js.map +1 -0
  134. package/dist/lib/path-validation.d.ts +3 -7
  135. package/dist/lib/path-validation.d.ts.map +1 -1
  136. package/dist/lib/path-validation.js +3 -124
  137. package/dist/lib/path-validation.js.map +1 -1
  138. package/dist/schemas/input-helpers.d.ts +8 -0
  139. package/dist/schemas/input-helpers.d.ts.map +1 -0
  140. package/dist/schemas/input-helpers.js +44 -0
  141. package/dist/schemas/input-helpers.js.map +1 -0
  142. package/dist/schemas/inputs.d.ts +8 -5
  143. package/dist/schemas/inputs.d.ts.map +1 -1
  144. package/dist/schemas/inputs.js +41 -64
  145. package/dist/schemas/inputs.js.map +1 -1
  146. package/dist/schemas/output-helpers.d.ts +24 -0
  147. package/dist/schemas/output-helpers.d.ts.map +1 -0
  148. package/dist/schemas/output-helpers.js +13 -0
  149. package/dist/schemas/output-helpers.js.map +1 -0
  150. package/dist/schemas/outputs.d.ts +480 -46
  151. package/dist/schemas/outputs.d.ts.map +1 -1
  152. package/dist/schemas/outputs.js +26 -41
  153. package/dist/schemas/outputs.js.map +1 -1
  154. package/dist/server.d.ts +9 -1
  155. package/dist/server.d.ts.map +1 -1
  156. package/dist/server.js +29 -57
  157. package/dist/server.js.map +1 -1
  158. package/dist/tools/analyze-directory.d.ts.map +1 -1
  159. package/dist/tools/analyze-directory.js +116 -54
  160. package/dist/tools/analyze-directory.js.map +1 -1
  161. package/dist/tools/directory-tree.d.ts.map +1 -1
  162. package/dist/tools/directory-tree.js +86 -49
  163. package/dist/tools/directory-tree.js.map +1 -1
  164. package/dist/tools/get-file-info.d.ts.map +1 -1
  165. package/dist/tools/get-file-info.js +71 -37
  166. package/dist/tools/get-file-info.js.map +1 -1
  167. package/dist/tools/list-allowed-dirs.d.ts.map +1 -1
  168. package/dist/tools/list-allowed-dirs.js +48 -35
  169. package/dist/tools/list-allowed-dirs.js.map +1 -1
  170. package/dist/tools/list-directory.d.ts.map +1 -1
  171. package/dist/tools/list-directory.js +131 -60
  172. package/dist/tools/list-directory.js.map +1 -1
  173. package/dist/tools/read-file.d.ts.map +1 -1
  174. package/dist/tools/read-file.js +70 -56
  175. package/dist/tools/read-file.js.map +1 -1
  176. package/dist/tools/read-media-file.d.ts.map +1 -1
  177. package/dist/tools/read-media-file.js +39 -41
  178. package/dist/tools/read-media-file.js.map +1 -1
  179. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  180. package/dist/tools/read-multiple-files.js +57 -50
  181. package/dist/tools/read-multiple-files.js.map +1 -1
  182. package/dist/tools/search-content.d.ts.map +1 -1
  183. package/dist/tools/search-content.js +147 -95
  184. package/dist/tools/search-content.js.map +1 -1
  185. package/dist/tools/search-files.d.ts.map +1 -1
  186. package/dist/tools/search-files.js +122 -51
  187. package/dist/tools/search-files.js.map +1 -1
  188. package/dist/tools/tool-response.d.ts +9 -0
  189. package/dist/tools/tool-response.d.ts.map +1 -0
  190. package/dist/tools/tool-response.js +7 -0
  191. package/dist/tools/tool-response.js.map +1 -0
  192. package/package.json +2 -1
  193. package/dist/__tests__/errors.test.d.ts +0 -2
  194. package/dist/__tests__/errors.test.d.ts.map +0 -1
  195. package/dist/__tests__/errors.test.js +0 -88
  196. package/dist/__tests__/errors.test.js.map +0 -1
  197. package/dist/__tests__/file-operations.test.d.ts +0 -2
  198. package/dist/__tests__/file-operations.test.d.ts.map +0 -1
  199. package/dist/__tests__/file-operations.test.js +0 -230
  200. package/dist/__tests__/file-operations.test.js.map +0 -1
  201. package/dist/__tests__/lib/formatters.test.d.ts +0 -2
  202. package/dist/__tests__/lib/formatters.test.d.ts.map +0 -1
  203. package/dist/__tests__/lib/formatters.test.js +0 -248
  204. package/dist/__tests__/lib/formatters.test.js.map +0 -1
  205. package/dist/__tests__/lib/image-parsing.test.d.ts +0 -2
  206. package/dist/__tests__/lib/image-parsing.test.d.ts.map +0 -1
  207. package/dist/__tests__/lib/image-parsing.test.js +0 -262
  208. package/dist/__tests__/lib/image-parsing.test.js.map +0 -1
  209. package/dist/__tests__/path-validation.test.d.ts +0 -2
  210. package/dist/__tests__/path-validation.test.d.ts.map +0 -1
  211. package/dist/__tests__/path-validation.test.js +0 -92
  212. package/dist/__tests__/path-validation.test.js.map +0 -1
  213. package/dist/lib/directory-helpers.d.ts +0 -4
  214. package/dist/lib/directory-helpers.d.ts.map +0 -1
  215. package/dist/lib/directory-helpers.js +0 -36
  216. package/dist/lib/directory-helpers.js.map +0 -1
  217. package/dist/lib/formatters.d.ts +0 -21
  218. package/dist/lib/formatters.d.ts.map +0 -1
  219. package/dist/lib/formatters.js +0 -206
  220. package/dist/lib/formatters.js.map +0 -1
  221. package/dist/lib/image-parsing.d.ts +0 -4
  222. package/dist/lib/image-parsing.d.ts.map +0 -1
  223. package/dist/lib/image-parsing.js +0 -130
  224. package/dist/lib/image-parsing.js.map +0 -1
  225. package/dist/lib/mcp-logger.d.ts +0 -11
  226. package/dist/lib/mcp-logger.d.ts.map +0 -1
  227. package/dist/lib/mcp-logger.js +0 -49
  228. package/dist/lib/mcp-logger.js.map +0 -1
  229. package/dist/lib/roots-utils.d.ts +0 -7
  230. package/dist/lib/roots-utils.d.ts.map +0 -1
  231. package/dist/lib/roots-utils.js +0 -39
  232. package/dist/lib/roots-utils.js.map +0 -1
  233. package/dist/lib/search-helpers.d.ts +0 -13
  234. package/dist/lib/search-helpers.d.ts.map +0 -1
  235. package/dist/lib/search-helpers.js +0 -205
  236. package/dist/lib/search-helpers.js.map +0 -1
  237. package/dist/lib/sorting.d.ts +0 -12
  238. package/dist/lib/sorting.d.ts.map +0 -1
  239. package/dist/lib/sorting.js +0 -41
  240. package/dist/lib/sorting.js.map +0 -1
  241. package/dist/lib/types.d.ts +0 -6
  242. package/dist/lib/types.d.ts.map +0 -1
  243. package/dist/lib/types.js +0 -2
  244. package/dist/lib/types.js.map +0 -1
  245. package/dist/prompts/analyze-codebase.d.ts +0 -3
  246. package/dist/prompts/analyze-codebase.d.ts.map +0 -1
  247. package/dist/prompts/analyze-codebase.js +0 -144
  248. package/dist/prompts/analyze-codebase.js.map +0 -1
  249. package/dist/prompts/filesystem-query.d.ts +0 -3
  250. package/dist/prompts/filesystem-query.d.ts.map +0 -1
  251. package/dist/prompts/filesystem-query.js +0 -168
  252. package/dist/prompts/filesystem-query.js.map +0 -1
  253. package/dist/prompts/find-duplicates.d.ts +0 -3
  254. package/dist/prompts/find-duplicates.d.ts.map +0 -1
  255. package/dist/prompts/find-duplicates.js +0 -77
  256. package/dist/prompts/find-duplicates.js.map +0 -1
  257. package/dist/prompts/index.d.ts +0 -3
  258. package/dist/prompts/index.d.ts.map +0 -1
  259. package/dist/prompts/index.js +0 -13
  260. package/dist/prompts/index.js.map +0 -1
  261. package/dist/prompts/project-overview.d.ts +0 -3
  262. package/dist/prompts/project-overview.d.ts.map +0 -1
  263. package/dist/prompts/project-overview.js +0 -122
  264. package/dist/prompts/project-overview.js.map +0 -1
  265. package/dist/prompts/search-and-replace.d.ts +0 -3
  266. package/dist/prompts/search-and-replace.d.ts.map +0 -1
  267. package/dist/prompts/search-and-replace.js +0 -130
  268. package/dist/prompts/search-and-replace.js.map +0 -1
  269. package/dist/prompts/shared.d.ts +0 -11
  270. package/dist/prompts/shared.d.ts.map +0 -1
  271. package/dist/prompts/shared.js +0 -32
  272. package/dist/prompts/shared.js.map +0 -1
  273. package/dist/resources/index.d.ts +0 -3
  274. package/dist/resources/index.d.ts.map +0 -1
  275. package/dist/resources/index.js +0 -54
  276. package/dist/resources/index.js.map +0 -1
  277. package/dist/schemas/validators.d.ts +0 -12
  278. package/dist/schemas/validators.d.ts.map +0 -1
  279. package/dist/schemas/validators.js +0 -35
  280. package/dist/schemas/validators.js.map +0 -1
  281. package/dist/utils/index.d.ts +0 -2
  282. package/dist/utils/index.d.ts.map +0 -1
  283. package/dist/utils/index.js +0 -2
  284. package/dist/utils/index.js.map +0 -1
  285. package/dist/utils/response-helpers.d.ts +0 -22
  286. package/dist/utils/response-helpers.d.ts.map +0 -1
  287. package/dist/utils/response-helpers.js +0 -24
  288. package/dist/utils/response-helpers.js.map +0 -1
@@ -0,0 +1,94 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { normalizePath } from '../path-utils.js';
4
+ const PATH_SEPARATOR = process.platform === 'win32' ? '\\' : '/';
5
+ let allowedDirectories = [];
6
+ export const RESERVED_DEVICE_NAMES = new Set([
7
+ 'CON',
8
+ 'PRN',
9
+ 'AUX',
10
+ 'NUL',
11
+ 'COM1',
12
+ 'COM2',
13
+ 'COM3',
14
+ 'COM4',
15
+ 'COM5',
16
+ 'COM6',
17
+ 'COM7',
18
+ 'COM8',
19
+ 'COM9',
20
+ 'LPT1',
21
+ 'LPT2',
22
+ 'LPT3',
23
+ 'LPT4',
24
+ 'LPT5',
25
+ 'LPT6',
26
+ 'LPT7',
27
+ 'LPT8',
28
+ 'LPT9',
29
+ ]);
30
+ export function normalizeForComparison(p) {
31
+ return process.platform === 'win32' ? p.toLowerCase() : p;
32
+ }
33
+ function stripTrailingSeparator(normalized) {
34
+ return normalized.endsWith(PATH_SEPARATOR)
35
+ ? normalized.slice(0, -1)
36
+ : normalized;
37
+ }
38
+ export function normalizeAllowedDirectory(dir) {
39
+ const normalized = normalizePath(dir);
40
+ if (normalized.length === 0)
41
+ return '';
42
+ const { root } = path.parse(normalized);
43
+ const isRoot = normalizeForComparison(root) === normalizeForComparison(normalized);
44
+ if (isRoot)
45
+ return root;
46
+ return stripTrailingSeparator(normalized);
47
+ }
48
+ export function setAllowedDirectories(dirs) {
49
+ const normalized = dirs
50
+ .map(normalizeAllowedDirectory)
51
+ .filter((d) => d.length > 0);
52
+ allowedDirectories = [...new Set(normalized)];
53
+ }
54
+ export function getAllowedDirectories() {
55
+ return [...allowedDirectories];
56
+ }
57
+ export function isPathWithinAllowedDirectories(normalizedPath) {
58
+ const candidate = normalizeForComparison(normalizedPath);
59
+ return allowedDirectories.some((allowedDir) => {
60
+ const allowed = normalizeForComparison(allowedDir);
61
+ const root = normalizeForComparison(path.parse(allowedDir).root);
62
+ if (allowed === root) {
63
+ return candidate.startsWith(allowed);
64
+ }
65
+ return (candidate === allowed || candidate.startsWith(allowed + PATH_SEPARATOR));
66
+ });
67
+ }
68
+ export async function expandAllowedDirectories(dirs) {
69
+ const expanded = [];
70
+ for (const dir of dirs) {
71
+ const normalized = normalizeAllowedDirectory(dir);
72
+ if (!normalized)
73
+ continue;
74
+ expanded.push(normalized);
75
+ try {
76
+ const realPath = await fs.realpath(normalized);
77
+ const normalizedReal = normalizeAllowedDirectory(realPath);
78
+ if (normalizedReal &&
79
+ normalizeForComparison(normalizedReal) !==
80
+ normalizeForComparison(normalized)) {
81
+ expanded.push(normalizedReal);
82
+ }
83
+ }
84
+ catch {
85
+ // Keep normalized path if realpath fails
86
+ }
87
+ }
88
+ return [...new Set(expanded)];
89
+ }
90
+ export async function setAllowedDirectoriesResolved(dirs) {
91
+ const expanded = await expandAllowedDirectories(dirs);
92
+ setAllowedDirectories(expanded);
93
+ }
94
+ //# sourceMappingURL=allowed-directories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowed-directories.js","sourceRoot":"","sources":["../../../src/lib/path-validation/allowed-directories.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { McpError } from '../errors.js';
2
+ export declare function buildAllowedDirectoriesHint(): string;
3
+ export declare function toMcpError(requestedPath: string, error: unknown): McpError;
4
+ export declare function toAccessDeniedWithHint(requestedPath: string, resolvedPath: string, normalizedResolved: string): McpError;
5
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/path-validation/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,QAAQ,EAAE,MAAM,cAAc,CAAC;AAanD,wBAAgB,2BAA2B,IAAI,MAAM,CAKpD;AAED,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAmD1E;AAED,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,GACzB,QAAQ,CAQV"}
@@ -0,0 +1,33 @@
1
+ import { ErrorCode, McpError } from '../errors.js';
2
+ import { getAllowedDirectories } from './allowed-directories.js';
3
+ function createMcpError(code, message, requestedPath, details, cause) {
4
+ return new McpError(code, message, requestedPath, details, cause);
5
+ }
6
+ export function buildAllowedDirectoriesHint() {
7
+ const allowedDirs = getAllowedDirectories();
8
+ return allowedDirs.length > 0
9
+ ? `Allowed directories:\n${allowedDirs.map((d) => ` - ${d}`).join('\n')}`
10
+ : 'No allowed directories configured. Use CLI arguments or MCP roots protocol.';
11
+ }
12
+ export function toMcpError(requestedPath, error) {
13
+ const nodeError = error;
14
+ const { code } = nodeError;
15
+ if (code === 'ENOENT') {
16
+ return createMcpError(ErrorCode.E_NOT_FOUND, `Path does not exist: ${requestedPath}`, requestedPath, { originalCode: code }, error);
17
+ }
18
+ if (code === 'EACCES' || code === 'EPERM') {
19
+ return createMcpError(ErrorCode.E_PERMISSION_DENIED, `Permission denied accessing path: ${requestedPath}`, requestedPath, { originalCode: code }, error);
20
+ }
21
+ if (code === 'ELOOP') {
22
+ return createMcpError(ErrorCode.E_SYMLINK_NOT_ALLOWED, `Too many symbolic links in path (possible circular reference): ${requestedPath}`, requestedPath, { originalCode: code }, error);
23
+ }
24
+ if (code === 'ENAMETOOLONG') {
25
+ return createMcpError(ErrorCode.E_INVALID_INPUT, `Path name too long: ${requestedPath}`, requestedPath, { originalCode: code }, error);
26
+ }
27
+ return createMcpError(ErrorCode.E_NOT_FOUND, `Path is not accessible: ${requestedPath}`, requestedPath, { originalCode: code, originalMessage: nodeError.message }, error);
28
+ }
29
+ export function toAccessDeniedWithHint(requestedPath, resolvedPath, normalizedResolved) {
30
+ const suggestion = buildAllowedDirectoriesHint();
31
+ return new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories.\n\n${suggestion}`, requestedPath, { resolvedPath, normalizedResolvedPath: normalizedResolved });
32
+ }
33
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/lib/path-validation/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,SAAS,cAAc,CACrB,IAAe,EACf,OAAe,EACf,aAAqB,EACrB,OAAgC,EAChC,KAAc;IAEd,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC;QAC3B,CAAC,CAAC,yBAAyB,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC1E,CAAC,CAAC,6EAA6E,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,aAAqB,EAAE,KAAc;IAC9D,MAAM,SAAS,GAAG,KAA8B,CAAC;IACjD,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAE3B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,cAAc,CACnB,SAAS,CAAC,WAAW,EACrB,wBAAwB,aAAa,EAAE,EACvC,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1C,OAAO,cAAc,CACnB,SAAS,CAAC,mBAAmB,EAC7B,qCAAqC,aAAa,EAAE,EACpD,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,cAAc,CACnB,SAAS,CAAC,qBAAqB,EAC/B,kEAAkE,aAAa,EAAE,EACjF,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;QAC5B,OAAO,cAAc,CACnB,SAAS,CAAC,eAAe,EACzB,uBAAuB,aAAa,EAAE,EACtC,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,OAAO,cAAc,CACnB,SAAS,CAAC,WAAW,EACrB,2BAA2B,aAAa,EAAE,EAC1C,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,CAAC,OAAO,EAAE,EAC1D,KAAK,CACN,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,aAAqB,EACrB,YAAoB,EACpB,kBAA0B;IAE1B,MAAM,UAAU,GAAG,2BAA2B,EAAE,CAAC;IACjD,OAAO,IAAI,QAAQ,CACjB,SAAS,CAAC,eAAe,EACzB,wBAAwB,aAAa,wCAAwC,UAAU,EAAE,EACzF,aAAa,EACb,EAAE,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,CAC7D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Root } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare function getValidRootDirectories(roots: Root[]): Promise<string[]>;
3
+ //# sourceMappingURL=roots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roots.d.ts","sourceRoot":"","sources":["../../../src/lib/path-validation/roots.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AA2C/D,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAcnB"}
@@ -0,0 +1,49 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { normalizePath } from '../path-utils.js';
4
+ import { normalizeForComparison } from './allowed-directories.js';
5
+ function isFileRoot(root) {
6
+ return root.uri.startsWith('file://');
7
+ }
8
+ async function maybeAddRealPath(normalizedPath, validDirs) {
9
+ try {
10
+ const realPath = await fs.realpath(normalizedPath);
11
+ const normalizedReal = normalizePath(realPath);
12
+ if (normalizeForComparison(normalizedReal) !==
13
+ normalizeForComparison(normalizedPath)) {
14
+ validDirs.push(normalizedReal);
15
+ }
16
+ }
17
+ catch {
18
+ // If realpath fails, use the normalized path only
19
+ }
20
+ }
21
+ async function resolveRootDirectory(root) {
22
+ try {
23
+ const dirPath = fileURLToPath(root.uri);
24
+ const normalizedPath = normalizePath(dirPath);
25
+ const stats = await fs.stat(normalizedPath);
26
+ if (!stats.isDirectory()) {
27
+ console.error(`Skipping root (not a directory): ${normalizedPath}`);
28
+ return null;
29
+ }
30
+ return normalizedPath;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ export async function getValidRootDirectories(roots) {
37
+ const validDirs = [];
38
+ for (const root of roots) {
39
+ if (!isFileRoot(root))
40
+ continue;
41
+ const normalizedPath = await resolveRootDirectory(root);
42
+ if (!normalizedPath)
43
+ continue;
44
+ validDirs.push(normalizedPath);
45
+ await maybeAddRealPath(normalizedPath, validDirs);
46
+ }
47
+ return validDirs;
48
+ }
49
+ //# sourceMappingURL=roots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roots.js","sourceRoot":"","sources":["../../../src/lib/path-validation/roots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,SAAS,UAAU,CAAC,IAAU;IAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,cAAsB,EACtB,SAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC/C,IACE,sBAAsB,CAAC,cAAc,CAAC;YACtC,sBAAsB,CAAC,cAAc,CAAC,EACtC,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,IAAU;IAC5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,oCAAoC,cAAc,EAAE,CAAC,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,cAAc,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa;IAEb,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAEhC,MAAM,cAAc,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,cAAc;YAAE,SAAS;QAE9B,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/B,MAAM,gBAAgB,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,9 @@
1
+ interface ValidatedPathDetails {
2
+ requestedPath: string;
3
+ resolvedPath: string;
4
+ isSymlink: boolean;
5
+ }
6
+ export declare function validateExistingPathDetailed(requestedPath: string): Promise<ValidatedPathDetails>;
7
+ export declare function validateExistingPath(requestedPath: string): Promise<string>;
8
+ export {};
9
+ //# sourceMappingURL=validators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../../src/lib/path-validation/validators.ts"],"names":[],"mappings":"AAWA,UAAU,oBAAoB;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAgGD,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB"}
@@ -0,0 +1,70 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import { ErrorCode, McpError } from '../errors.js';
3
+ import { normalizePath } from '../path-utils.js';
4
+ import { isPathWithinAllowedDirectories, normalizeForComparison, RESERVED_DEVICE_NAMES, } from './allowed-directories.js';
5
+ import { toAccessDeniedWithHint, toMcpError } from './errors.js';
6
+ function ensureNonEmptyPath(requestedPath) {
7
+ if (!requestedPath || requestedPath.trim().length === 0) {
8
+ throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path cannot be empty or whitespace', requestedPath);
9
+ }
10
+ }
11
+ function ensureNoNullBytes(requestedPath) {
12
+ if (requestedPath.includes('\0')) {
13
+ throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path contains null bytes', requestedPath);
14
+ }
15
+ }
16
+ function ensureNoReservedWindowsNames(requestedPath) {
17
+ if (process.platform !== 'win32')
18
+ return;
19
+ const segments = requestedPath.split(/[\\/]/);
20
+ for (const segment of segments) {
21
+ const baseName = segment.split('.')[0]?.toUpperCase();
22
+ if (baseName && RESERVED_DEVICE_NAMES.has(baseName)) {
23
+ throw new McpError(ErrorCode.E_INVALID_INPUT, `Windows reserved device name not allowed: ${baseName}`, requestedPath);
24
+ }
25
+ }
26
+ }
27
+ function ensureWithinAllowedDirectories(normalizedPath, requestedPath, details) {
28
+ if (isPathWithinAllowedDirectories(normalizedPath))
29
+ return;
30
+ throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories`, requestedPath, details);
31
+ }
32
+ function validateRequestedPath(requestedPath) {
33
+ ensureNonEmptyPath(requestedPath);
34
+ ensureNoNullBytes(requestedPath);
35
+ ensureNoReservedWindowsNames(requestedPath);
36
+ return normalizePath(requestedPath);
37
+ }
38
+ async function resolveRealPath(requestedPath, normalizedRequested) {
39
+ try {
40
+ return await fs.realpath(normalizedRequested);
41
+ }
42
+ catch (error) {
43
+ throw toMcpError(requestedPath, error);
44
+ }
45
+ }
46
+ async function validateExistingPathDetailsInternal(requestedPath) {
47
+ const normalizedRequested = validateRequestedPath(requestedPath);
48
+ ensureWithinAllowedDirectories(normalizedRequested, requestedPath, {
49
+ normalizedPath: normalizedRequested,
50
+ });
51
+ const realPath = await resolveRealPath(requestedPath, normalizedRequested);
52
+ const normalizedReal = normalizePath(realPath);
53
+ if (!isPathWithinAllowedDirectories(normalizedReal)) {
54
+ throw toAccessDeniedWithHint(requestedPath, realPath, normalizedReal);
55
+ }
56
+ return {
57
+ requestedPath: normalizedRequested,
58
+ resolvedPath: normalizedReal,
59
+ isSymlink: normalizeForComparison(normalizedRequested) !==
60
+ normalizeForComparison(normalizedReal),
61
+ };
62
+ }
63
+ export async function validateExistingPathDetailed(requestedPath) {
64
+ return validateExistingPathDetailsInternal(requestedPath);
65
+ }
66
+ export async function validateExistingPath(requestedPath) {
67
+ const details = await validateExistingPathDetailsInternal(requestedPath);
68
+ return details.resolvedPath;
69
+ }
70
+ //# sourceMappingURL=validators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../../src/lib/path-validation/validators.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,4 @@
1
- import type { Root } from '@modelcontextprotocol/sdk/types.js';
2
- import type { ValidatedPathDetails } from '../config/types.js';
3
- export declare function setAllowedDirectories(dirs: string[]): void;
4
- export declare function getAllowedDirectories(): string[];
5
- export declare function validateExistingPathDetailed(requestedPath: string): Promise<ValidatedPathDetails>;
6
- export declare function validateExistingPath(requestedPath: string): Promise<string>;
7
- export declare function getValidRootDirectories(roots: Root[]): Promise<string[]>;
1
+ export { getAllowedDirectories, setAllowedDirectories, setAllowedDirectoriesResolved, expandAllowedDirectories, RESERVED_DEVICE_NAMES, } from './path-validation/allowed-directories.js';
2
+ export { validateExistingPath, validateExistingPathDetailed, } from './path-validation/validators.js';
3
+ export { getValidRootDirectories } from './path-validation/roots.js';
8
4
  //# sourceMappingURL=path-validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-validation.d.ts","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAM/D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAG1D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAiID,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAGD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAiCnB"}
1
+ {"version":3,"file":"path-validation.d.ts","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -1,125 +1,4 @@
1
- // Path validation and security module - the SECURITY BOUNDARY of this server.
2
- // All filesystem operations MUST call validateExistingPath() before accessing any path.
3
- import * as fs from 'node:fs/promises';
4
- import { fileURLToPath } from 'node:url';
5
- import { ErrorCode, McpError } from './errors.js';
6
- import { normalizePath } from './path-utils.js';
7
- let allowedDirectories = [];
8
- export function setAllowedDirectories(dirs) {
9
- const normalized = dirs.map(normalizePath).filter((d) => d.length > 0);
10
- allowedDirectories = [...new Set(normalized)];
11
- }
12
- export function getAllowedDirectories() {
13
- return [...allowedDirectories];
14
- }
15
- const PATH_SEPARATOR = process.platform === 'win32' ? '\\' : '/';
16
- function normalizeForComparison(p) {
17
- return process.platform === 'win32' ? p.toLowerCase() : p;
18
- }
19
- function isPathWithinAllowedDirectories(normalizedPath) {
20
- const candidate = normalizeForComparison(normalizedPath);
21
- return allowedDirectories.some((allowedDir) => {
22
- const allowed = normalizeForComparison(allowedDir);
23
- // Exact match or is a child path
24
- return (candidate === allowed || candidate.startsWith(allowed + PATH_SEPARATOR));
25
- });
26
- }
27
- async function validateExistingPathDetailsInternal(requestedPath) {
28
- // Validate input is not empty or only whitespace
29
- if (!requestedPath || requestedPath.trim().length === 0) {
30
- throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path cannot be empty or whitespace', requestedPath);
31
- }
32
- const normalizedRequested = normalizePath(requestedPath);
33
- if (!isPathWithinAllowedDirectories(normalizedRequested)) {
34
- throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories`, requestedPath, { normalizedPath: normalizedRequested });
35
- }
36
- let realPath;
37
- try {
38
- realPath = await fs.realpath(normalizedRequested);
39
- }
40
- catch (error) {
41
- // Distinguish between different error types for better error messages
42
- const nodeError = error;
43
- if (nodeError.code === 'ENOENT') {
44
- throw new McpError(ErrorCode.E_NOT_FOUND, `Path does not exist: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
45
- }
46
- if (nodeError.code === 'EACCES' || nodeError.code === 'EPERM') {
47
- throw new McpError(ErrorCode.E_PERMISSION_DENIED, `Permission denied accessing path: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
48
- }
49
- if (nodeError.code === 'ELOOP') {
50
- throw new McpError(ErrorCode.E_SYMLINK_NOT_ALLOWED, `Too many symbolic links in path (possible circular reference): ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
51
- }
52
- if (nodeError.code === 'ENAMETOOLONG') {
53
- throw new McpError(ErrorCode.E_INVALID_INPUT, `Path name too long: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
54
- }
55
- // Generic fallback for other errors
56
- throw new McpError(ErrorCode.E_NOT_FOUND, `Path is not accessible: ${requestedPath}`, requestedPath, { originalCode: nodeError.code, originalMessage: nodeError.message }, error);
57
- }
58
- const normalizedReal = normalizePath(realPath);
59
- if (!isPathWithinAllowedDirectories(normalizedReal)) {
60
- const allowedDirs = getAllowedDirectories();
61
- const suggestion = allowedDirs.length > 0
62
- ? `Allowed directories:\n${allowedDirs.map((d) => ` - ${d}`).join('\n')}`
63
- : 'No allowed directories configured. Use CLI arguments or MCP roots protocol.';
64
- throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories.\n\n${suggestion}`, requestedPath, { resolvedPath: realPath, normalizedResolvedPath: normalizedReal });
65
- }
66
- // Detect if the *requested* path is a symlink without following it.
67
- // Note: lstat runs after the allowed-directory string check above.
68
- let isSymlink = false;
69
- try {
70
- const lstats = await fs.lstat(normalizedRequested);
71
- isSymlink = lstats.isSymbolicLink();
72
- }
73
- catch {
74
- // If lstat fails but realpath succeeded, treat as non-symlink.
75
- // This can happen on some platforms/filesystems; safe default.
76
- isSymlink = false;
77
- }
78
- return {
79
- requestedPath: normalizedRequested,
80
- resolvedPath: normalizedReal,
81
- isSymlink,
82
- };
83
- }
84
- export async function validateExistingPathDetailed(requestedPath) {
85
- return validateExistingPathDetailsInternal(requestedPath);
86
- }
87
- export async function validateExistingPath(requestedPath) {
88
- const details = await validateExistingPathDetailsInternal(requestedPath);
89
- return details.resolvedPath;
90
- }
91
- // Extract valid directory paths from MCP Root objects (file:// URIs only)
92
- export async function getValidRootDirectories(roots) {
93
- const validDirs = [];
94
- for (const root of roots) {
95
- // Only accept file:// URIs
96
- if (!root.uri.startsWith('file://')) {
97
- continue;
98
- }
99
- try {
100
- const dirPath = fileURLToPath(root.uri);
101
- const normalizedPath = normalizePath(dirPath);
102
- // Verify the directory exists and is accessible
103
- const stats = await fs.stat(normalizedPath);
104
- if (stats.isDirectory()) {
105
- // Resolve symlinks to get the real path
106
- try {
107
- const realPath = await fs.realpath(normalizedPath);
108
- validDirs.push(normalizePath(realPath));
109
- }
110
- catch {
111
- // If realpath fails, use the normalized path
112
- validDirs.push(normalizedPath);
113
- }
114
- }
115
- else {
116
- console.error(`Skipping root (not a directory): ${normalizedPath}`);
117
- }
118
- }
119
- catch {
120
- continue;
121
- }
122
- }
123
- return validDirs;
124
- }
1
+ export { getAllowedDirectories, setAllowedDirectories, setAllowedDirectoriesResolved, expandAllowedDirectories, RESERVED_DEVICE_NAMES, } from './path-validation/allowed-directories.js';
2
+ export { validateExistingPath, validateExistingPathDetailed, } from './path-validation/validators.js';
3
+ export { getValidRootDirectories } from './path-validation/roots.js';
125
4
  //# sourceMappingURL=path-validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wFAAwF;AACxF,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAKzC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,IAAI,kBAAkB,GAAa,EAAE,CAAC;AAEtC,MAAM,UAAU,qBAAqB,CAAC,IAAc;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,kBAAkB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,CAAC,GAAG,kBAAkB,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AAEjE,SAAS,sBAAsB,CAAC,CAAS;IACvC,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,8BAA8B,CAAC,cAAsB;IAC5D,MAAM,SAAS,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC;IACzD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;QACnD,iCAAiC;QACjC,OAAO,CACL,SAAS,KAAK,OAAO,IAAI,SAAS,CAAC,UAAU,CAAC,OAAO,GAAG,cAAc,CAAC,CACxE,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,mCAAmC,CAChD,aAAqB;IAErB,iDAAiD;IACjD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,eAAe,EACzB,oCAAoC,EACpC,aAAa,CACd,CAAC;IACJ,CAAC;IAED,MAAM,mBAAmB,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAEzD,IAAI,CAAC,8BAA8B,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,eAAe,EACzB,wBAAwB,aAAa,kCAAkC,EACvE,aAAa,EACb,EAAE,cAAc,EAAE,mBAAmB,EAAE,CACxC,CAAC;IACJ,CAAC;IAED,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sEAAsE;QACtE,MAAM,SAAS,GAAG,KAA8B,CAAC;QACjD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChC,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,WAAW,EACrB,wBAAwB,aAAa,EAAE,EACvC,aAAa,EACb,EAAE,YAAY,EAAE,SAAS,CAAC,IAAI,EAAE,EAChC,KAAK,CACN,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC9D,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,mBAAmB,EAC7B,qCAAqC,aAAa,EAAE,EACpD,aAAa,EACb,EAAE,YAAY,EAAE,SAAS,CAAC,IAAI,EAAE,EAChC,KAAK,CACN,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC/B,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,qBAAqB,EAC/B,kEAAkE,aAAa,EAAE,EACjF,aAAa,EACb,EAAE,YAAY,EAAE,SAAS,CAAC,IAAI,EAAE,EAChC,KAAK,CACN,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACtC,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,eAAe,EACzB,uBAAuB,aAAa,EAAE,EACtC,aAAa,EACb,EAAE,YAAY,EAAE,SAAS,CAAC,IAAI,EAAE,EAChC,KAAK,CACN,CAAC;QACJ,CAAC;QACD,oCAAoC;QACpC,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,WAAW,EACrB,2BAA2B,aAAa,EAAE,EAC1C,aAAa,EACb,EAAE,YAAY,EAAE,SAAS,CAAC,IAAI,EAAE,eAAe,EAAE,SAAS,CAAC,OAAO,EAAE,EACpE,KAAK,CACN,CAAC;IACJ,CAAC;IACD,MAAM,cAAc,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE/C,IAAI,CAAC,8BAA8B,CAAC,cAAc,CAAC,EAAE,CAAC;QACpD,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;QAC5C,MAAM,UAAU,GACd,WAAW,CAAC,MAAM,GAAG,CAAC;YACpB,CAAC,CAAC,yBAAyB,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC1E,CAAC,CAAC,6EAA6E,CAAC;QAEpF,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,eAAe,EACzB,wBAAwB,aAAa,wCAAwC,UAAU,EAAE,EACzF,aAAa,EACb,EAAE,YAAY,EAAE,QAAQ,EAAE,sBAAsB,EAAE,cAAc,EAAE,CACnE,CAAC;IACJ,CAAC;IAED,oEAAoE;IACpE,mEAAmE;IACnE,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACnD,SAAS,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,+DAA+D;QAC/D,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,OAAO;QACL,aAAa,EAAE,mBAAmB;QAClC,YAAY,EAAE,cAAc;QAC5B,SAAS;KACV,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,aAAqB;IAErB,OAAO,mCAAmC,CAAC,aAAa,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,aAAqB;IAErB,MAAM,OAAO,GAAG,MAAM,mCAAmC,CAAC,aAAa,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC,YAAY,CAAC;AAC9B,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa;IAEb,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,2BAA2B;QAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACpC,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YAE9C,gDAAgD;YAChD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,wCAAwC;gBACxC,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;oBACnD,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC1C,CAAC;gBAAC,MAAM,CAAC;oBACP,6CAA6C;oBAC7C,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACjC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,oCAAoC,cAAc,EAAE,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ export declare function isSafeGlobPattern(value: string): boolean;
3
+ export declare const EncodingSchema: z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "utf8", "ascii", "base64", "hex", "latin1"]>>>;
4
+ export declare const ReadFileMaxSizeSchema: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
5
+ export declare const ReadMultipleFilesMaxSizeSchema: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
6
+ export declare const ExcludePatternsSchema: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
7
+ export declare const BasicExcludePatternsSchema: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
8
+ //# sourceMappingURL=input-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-helpers.d.ts","sourceRoot":"","sources":["../../src/schemas/input-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAaxD;AAED,eAAO,MAAM,cAAc,+FAIC,CAAC;AAU7B,eAAO,MAAM,qBAAqB,0CAEjC,CAAC;AAEF,eAAO,MAAM,8BAA8B,0CAE1C,CAAC;AAEF,eAAO,MAAM,qBAAqB,4FAWpB,CAAC;AAEf,eAAO,MAAM,0BAA0B,8DAIzB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ import { MAX_TEXT_FILE_SIZE } from '../lib/constants.js';
3
+ export function isSafeGlobPattern(value) {
4
+ if (value.length === 0)
5
+ return false;
6
+ const absolutePattern = /^([/\\]|[A-Za-z]:[/\\]|\\\\)/u;
7
+ if (absolutePattern.test(value)) {
8
+ return false;
9
+ }
10
+ if (/[\\/]\.\.(?:[/\\]|$)/u.test(value) || value.startsWith('..')) {
11
+ return false;
12
+ }
13
+ return true;
14
+ }
15
+ export const EncodingSchema = z
16
+ .enum(['utf-8', 'utf8', 'ascii', 'base64', 'hex', 'latin1'])
17
+ .optional()
18
+ .default('utf-8')
19
+ .describe('File encoding');
20
+ const MaxTextFileSizeSchema = z
21
+ .number()
22
+ .int('maxSize must be an integer')
23
+ .min(1, 'maxSize must be at least 1 byte')
24
+ .max(100 * 1024 * 1024, 'maxSize cannot exceed 100MB')
25
+ .optional()
26
+ .default(MAX_TEXT_FILE_SIZE);
27
+ export const ReadFileMaxSizeSchema = MaxTextFileSizeSchema.describe('Maximum file size in bytes (default 10MB)');
28
+ export const ReadMultipleFilesMaxSizeSchema = MaxTextFileSizeSchema.describe('Maximum file size in bytes per file (default 10MB)');
29
+ export const ExcludePatternsSchema = z
30
+ .array(z
31
+ .string()
32
+ .max(500, 'Individual exclude pattern is too long')
33
+ .refine((val) => !val.includes('**/**/**'), {
34
+ message: 'Pattern too deeply nested (max 2 levels of **)',
35
+ }))
36
+ .max(100, 'Too many exclude patterns (max 100)')
37
+ .optional()
38
+ .default([]);
39
+ export const BasicExcludePatternsSchema = z
40
+ .array(z.string().max(500, 'Individual exclude pattern is too long'))
41
+ .max(100, 'Too many exclude patterns (max 100)')
42
+ .optional()
43
+ .default([]);
44
+ //# sourceMappingURL=input-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-helpers.js","sourceRoot":"","sources":["../../src/schemas/input-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAErC,MAAM,eAAe,GAAG,+BAA+B,CAAC;IACxD,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;KAC3D,QAAQ,EAAE;KACV,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,eAAe,CAAC,CAAC;AAE7B,MAAM,qBAAqB,GAAG,CAAC;KAC5B,MAAM,EAAE;KACR,GAAG,CAAC,4BAA4B,CAAC;KACjC,GAAG,CAAC,CAAC,EAAE,iCAAiC,CAAC;KACzC,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,6BAA6B,CAAC;KACrD,QAAQ,EAAE;KACV,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE/B,MAAM,CAAC,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,QAAQ,CACjE,2CAA2C,CAC5C,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAAqB,CAAC,QAAQ,CAC1E,oDAAoD,CACrD,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,KAAK,CACJ,CAAC;KACE,MAAM,EAAE;KACR,GAAG,CAAC,GAAG,EAAE,wCAAwC,CAAC;KAClD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;IAC1C,OAAO,EAAE,gDAAgD;CAC1D,CAAC,CACL;KACA,GAAG,CAAC,GAAG,EAAE,qCAAqC,CAAC;KAC/C,QAAQ,EAAE;KACV,OAAO,CAAC,EAAE,CAAC,CAAC;AAEf,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC;KACxC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;KACpE,GAAG,CAAC,GAAG,EAAE,qCAAqC,CAAC;KAC/C,QAAQ,EAAE;KACV,OAAO,CAAC,EAAE,CAAC,CAAC"}
@@ -12,13 +12,15 @@ export declare const SearchFilesInputSchema: {
12
12
  path: z.ZodString;
13
13
  pattern: z.ZodEffects<z.ZodString, string, string>;
14
14
  excludePatterns: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
15
- maxResults: z.ZodOptional<z.ZodNumber>;
15
+ maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
16
16
  sortBy: z.ZodDefault<z.ZodOptional<z.ZodEnum<["name", "size", "modified", "path"]>>>;
17
17
  maxDepth: z.ZodOptional<z.ZodNumber>;
18
+ maxFilesScanned: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
19
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
18
20
  };
19
21
  export declare const ReadFileInputSchema: {
20
22
  path: z.ZodString;
21
- encoding: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "utf8", "ascii", "base64", "hex", "latin1"]>>>, "base64" | "ascii" | "utf8" | "utf-8" | "latin1" | "hex", "base64" | "ascii" | "utf8" | "utf-8" | "latin1" | "hex" | undefined>;
23
+ encoding: z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "utf8", "ascii", "base64", "hex", "latin1"]>>>;
22
24
  maxSize: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
23
25
  lineStart: z.ZodOptional<z.ZodNumber>;
24
26
  lineEnd: z.ZodOptional<z.ZodNumber>;
@@ -39,14 +41,15 @@ export declare const GetFileInfoInputSchema: {
39
41
  export declare const SearchContentInputSchema: {
40
42
  path: z.ZodString;
41
43
  pattern: z.ZodString;
42
- filePattern: z.ZodDefault<z.ZodOptional<z.ZodString>>;
44
+ filePattern: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, string | undefined>;
43
45
  excludePatterns: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
44
46
  caseSensitive: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
45
47
  maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
46
48
  maxFileSize: z.ZodOptional<z.ZodNumber>;
47
- maxFilesScanned: z.ZodOptional<z.ZodNumber>;
48
- timeoutMs: z.ZodOptional<z.ZodNumber>;
49
+ maxFilesScanned: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
50
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
49
51
  skipBinary: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
52
+ includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
50
53
  contextLines: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
51
54
  wholeWord: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
52
55
  isLiteral: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -1 +1 @@
1
- {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/schemas/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,eAAO,MAAM,wBAAwB;;;;;;;;CA4CpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;CA6DlC,CAAC;AA2DF,eAAO,MAAM,mBAAmB;;;;;;;;CAA2B,CAAC;AAgD5D,eAAO,MAAM,4BAA4B;;;;;;;CAAoC,CAAC;AAE9E,eAAO,MAAM,sBAAsB;;CAKlC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CA+FpC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;CAgCvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;CAoCpC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAapC,CAAC"}
1
+ {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/schemas/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoBxB,eAAO,MAAM,wBAAwB;;;;;;;;CA4CpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;CAqElC,CAAC;AA2CF,eAAO,MAAM,mBAAmB;;;;;;;;CAA2B,CAAC;AAqC5D,eAAO,MAAM,4BAA4B;;;;;;;CAAoC,CAAC;AAE9E,eAAO,MAAM,sBAAsB;;CAKlC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;CAgGpC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;CA6BvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;CAiCpC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAapC,CAAC"}