@j0hanz/filesystem-context-mcp 1.2.5 → 1.2.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.
Files changed (291) hide show
  1. package/README.md +19 -16
  2. package/dist/__tests__/lib/errors-classify.test.d.ts +2 -0
  3. package/dist/__tests__/lib/errors-classify.test.d.ts.map +1 -0
  4. package/dist/__tests__/lib/errors-classify.test.js +53 -0
  5. package/dist/__tests__/lib/errors-classify.test.js.map +1 -0
  6. package/dist/__tests__/lib/errors-detailed.test.d.ts +2 -0
  7. package/dist/__tests__/lib/errors-detailed.test.d.ts.map +1 -0
  8. package/dist/__tests__/lib/errors-detailed.test.js +38 -0
  9. package/dist/__tests__/lib/errors-detailed.test.js.map +1 -0
  10. package/dist/__tests__/lib/errors-is-node-error.test.d.ts +2 -0
  11. package/dist/__tests__/lib/errors-is-node-error.test.d.ts.map +1 -0
  12. package/dist/__tests__/lib/errors-is-node-error.test.js +21 -0
  13. package/dist/__tests__/lib/errors-is-node-error.test.js.map +1 -0
  14. package/dist/__tests__/lib/errors-mcp-error.test.d.ts +2 -0
  15. package/dist/__tests__/lib/errors-mcp-error.test.d.ts.map +1 -0
  16. package/dist/__tests__/lib/errors-mcp-error.test.js +29 -0
  17. package/dist/__tests__/lib/errors-mcp-error.test.js.map +1 -0
  18. package/dist/__tests__/lib/errors-node-map.test.d.ts +2 -0
  19. package/dist/__tests__/lib/errors-node-map.test.d.ts.map +1 -0
  20. package/dist/__tests__/lib/errors-node-map.test.js +16 -0
  21. package/dist/__tests__/lib/errors-node-map.test.js.map +1 -0
  22. package/dist/__tests__/lib/errors-suggestion.test.d.ts +2 -0
  23. package/dist/__tests__/lib/errors-suggestion.test.d.ts.map +1 -0
  24. package/dist/__tests__/lib/errors-suggestion.test.js +11 -0
  25. package/dist/__tests__/lib/errors-suggestion.test.js.map +1 -0
  26. package/dist/__tests__/lib/file-operations/analyze-directory-edge-cases.test.d.ts +2 -0
  27. package/dist/__tests__/lib/file-operations/analyze-directory-edge-cases.test.d.ts.map +1 -0
  28. package/dist/__tests__/lib/file-operations/analyze-directory-edge-cases.test.js +15 -0
  29. package/dist/__tests__/lib/file-operations/analyze-directory-edge-cases.test.js.map +1 -0
  30. package/dist/__tests__/lib/file-operations/analyze-directory.test.d.ts +2 -0
  31. package/dist/__tests__/lib/file-operations/analyze-directory.test.d.ts.map +1 -0
  32. package/dist/__tests__/lib/file-operations/analyze-directory.test.js +28 -0
  33. package/dist/__tests__/lib/file-operations/analyze-directory.test.js.map +1 -0
  34. package/dist/__tests__/lib/file-operations/directory-tree-edge-cases.test.d.ts +2 -0
  35. package/dist/__tests__/lib/file-operations/directory-tree-edge-cases.test.d.ts.map +1 -0
  36. package/dist/__tests__/lib/file-operations/directory-tree-edge-cases.test.js +29 -0
  37. package/dist/__tests__/lib/file-operations/directory-tree-edge-cases.test.js.map +1 -0
  38. package/dist/__tests__/lib/file-operations/directory-tree.test.d.ts +2 -0
  39. package/dist/__tests__/lib/file-operations/directory-tree.test.d.ts.map +1 -0
  40. package/dist/__tests__/lib/file-operations/directory-tree.test.js +75 -0
  41. package/dist/__tests__/lib/file-operations/directory-tree.test.js.map +1 -0
  42. package/dist/__tests__/lib/file-operations/get-file-info.test.d.ts +2 -0
  43. package/dist/__tests__/lib/file-operations/get-file-info.test.d.ts.map +1 -0
  44. package/dist/__tests__/lib/file-operations/get-file-info.test.js +17 -0
  45. package/dist/__tests__/lib/file-operations/get-file-info.test.js.map +1 -0
  46. package/dist/__tests__/lib/file-operations/list-directory-edge-cases.test.d.ts +2 -0
  47. package/dist/__tests__/lib/file-operations/list-directory-edge-cases.test.d.ts.map +1 -0
  48. package/dist/__tests__/lib/file-operations/list-directory-edge-cases.test.js +21 -0
  49. package/dist/__tests__/lib/file-operations/list-directory-edge-cases.test.js.map +1 -0
  50. package/dist/__tests__/lib/file-operations/list-directory.test.d.ts +2 -0
  51. package/dist/__tests__/lib/file-operations/list-directory.test.d.ts.map +1 -0
  52. package/dist/__tests__/lib/file-operations/list-directory.test.js +31 -0
  53. package/dist/__tests__/lib/file-operations/list-directory.test.js.map +1 -0
  54. package/dist/__tests__/lib/file-operations/read-media-file.test.d.ts +2 -0
  55. package/dist/__tests__/lib/file-operations/read-media-file.test.d.ts.map +1 -0
  56. package/dist/__tests__/lib/file-operations/read-media-file.test.js +21 -0
  57. package/dist/__tests__/lib/file-operations/read-media-file.test.js.map +1 -0
  58. package/dist/__tests__/lib/file-operations/read-multiple-files-edge-cases.test.d.ts +2 -0
  59. package/dist/__tests__/lib/file-operations/read-multiple-files-edge-cases.test.d.ts.map +1 -0
  60. package/dist/__tests__/lib/file-operations/read-multiple-files-edge-cases.test.js +19 -0
  61. package/dist/__tests__/lib/file-operations/read-multiple-files-edge-cases.test.js.map +1 -0
  62. package/dist/__tests__/lib/file-operations/read-multiple-files.test.d.ts +2 -0
  63. package/dist/__tests__/lib/file-operations/read-multiple-files.test.d.ts.map +1 -0
  64. package/dist/__tests__/lib/file-operations/read-multiple-files.test.js +39 -0
  65. package/dist/__tests__/lib/file-operations/read-multiple-files.test.js.map +1 -0
  66. package/dist/__tests__/lib/file-operations/search-content-edge-cases.test.d.ts +2 -0
  67. package/dist/__tests__/lib/file-operations/search-content-edge-cases.test.d.ts.map +1 -0
  68. package/dist/__tests__/lib/file-operations/search-content-edge-cases.test.js +57 -0
  69. package/dist/__tests__/lib/file-operations/search-content-edge-cases.test.js.map +1 -0
  70. package/dist/__tests__/lib/file-operations/search-content.test.d.ts +2 -0
  71. package/dist/__tests__/lib/file-operations/search-content.test.d.ts.map +1 -0
  72. package/dist/__tests__/lib/file-operations/search-content.test.js +73 -0
  73. package/dist/__tests__/lib/file-operations/search-content.test.js.map +1 -0
  74. package/dist/__tests__/lib/file-operations/search-files-edge-cases.test.d.ts +2 -0
  75. package/dist/__tests__/lib/file-operations/search-files-edge-cases.test.d.ts.map +1 -0
  76. package/dist/__tests__/lib/file-operations/search-files-edge-cases.test.js +13 -0
  77. package/dist/__tests__/lib/file-operations/search-files-edge-cases.test.js.map +1 -0
  78. package/dist/__tests__/lib/file-operations/search-files.test.d.ts +2 -0
  79. package/dist/__tests__/lib/file-operations/search-files.test.d.ts.map +1 -0
  80. package/dist/__tests__/lib/file-operations/search-files.test.js +31 -0
  81. package/dist/__tests__/lib/file-operations/search-files.test.js.map +1 -0
  82. package/dist/__tests__/lib/file-operations.test.js +11 -0
  83. package/dist/__tests__/lib/file-operations.test.js.map +1 -1
  84. package/dist/__tests__/lib/fixtures/file-ops-fixture.d.ts +7 -0
  85. package/dist/__tests__/lib/fixtures/file-ops-fixture.d.ts.map +1 -0
  86. package/dist/__tests__/lib/fixtures/file-ops-fixture.js +87 -0
  87. package/dist/__tests__/lib/fixtures/file-ops-fixture.js.map +1 -0
  88. package/dist/__tests__/lib/fixtures/file-ops-hooks.d.ts +2 -0
  89. package/dist/__tests__/lib/fixtures/file-ops-hooks.d.ts.map +1 -0
  90. package/dist/__tests__/lib/fixtures/file-ops-hooks.js +13 -0
  91. package/dist/__tests__/lib/fixtures/file-ops-hooks.js.map +1 -0
  92. package/dist/__tests__/lib/fs-helpers/file-type.test.d.ts +2 -0
  93. package/dist/__tests__/lib/fs-helpers/file-type.test.d.ts.map +1 -0
  94. package/dist/__tests__/lib/fs-helpers/file-type.test.js +15 -0
  95. package/dist/__tests__/lib/fs-helpers/file-type.test.js.map +1 -0
  96. package/dist/__tests__/lib/fs-helpers/head-file-edge-cases.test.d.ts +2 -0
  97. package/dist/__tests__/lib/fs-helpers/head-file-edge-cases.test.d.ts.map +1 -0
  98. package/dist/__tests__/lib/fs-helpers/head-file-edge-cases.test.js +19 -0
  99. package/dist/__tests__/lib/fs-helpers/head-file-edge-cases.test.js.map +1 -0
  100. package/dist/__tests__/lib/fs-helpers/head-file.test.d.ts +2 -0
  101. package/dist/__tests__/lib/fs-helpers/head-file.test.d.ts.map +1 -0
  102. package/dist/__tests__/lib/fs-helpers/head-file.test.js +12 -0
  103. package/dist/__tests__/lib/fs-helpers/head-file.test.js.map +1 -0
  104. package/dist/__tests__/lib/fs-helpers/is-hidden.test.d.ts +2 -0
  105. package/dist/__tests__/lib/fs-helpers/is-hidden.test.d.ts.map +1 -0
  106. package/dist/__tests__/lib/fs-helpers/is-hidden.test.js +7 -0
  107. package/dist/__tests__/lib/fs-helpers/is-hidden.test.js.map +1 -0
  108. package/dist/__tests__/lib/fs-helpers/is-probably-binary.test.d.ts +2 -0
  109. package/dist/__tests__/lib/fs-helpers/is-probably-binary.test.d.ts.map +1 -0
  110. package/dist/__tests__/lib/fs-helpers/is-probably-binary.test.js +33 -0
  111. package/dist/__tests__/lib/fs-helpers/is-probably-binary.test.js.map +1 -0
  112. package/dist/__tests__/lib/fs-helpers/read-file-edge-cases.test.d.ts +2 -0
  113. package/dist/__tests__/lib/fs-helpers/read-file-edge-cases.test.d.ts.map +1 -0
  114. package/dist/__tests__/lib/fs-helpers/read-file-edge-cases.test.js +41 -0
  115. package/dist/__tests__/lib/fs-helpers/read-file-edge-cases.test.js.map +1 -0
  116. package/dist/__tests__/lib/fs-helpers/read-file.test.d.ts +2 -0
  117. package/dist/__tests__/lib/fs-helpers/read-file.test.d.ts.map +1 -0
  118. package/dist/__tests__/lib/fs-helpers/read-file.test.js +21 -0
  119. package/dist/__tests__/lib/fs-helpers/read-file.test.js.map +1 -0
  120. package/dist/__tests__/lib/fs-helpers/tail-file-edge-cases.test.d.ts +2 -0
  121. package/dist/__tests__/lib/fs-helpers/tail-file-edge-cases.test.d.ts.map +1 -0
  122. package/dist/__tests__/lib/fs-helpers/tail-file-edge-cases.test.js +26 -0
  123. package/dist/__tests__/lib/fs-helpers/tail-file-edge-cases.test.js.map +1 -0
  124. package/dist/__tests__/lib/fs-helpers/tail-file.test.d.ts +2 -0
  125. package/dist/__tests__/lib/fs-helpers/tail-file.test.d.ts.map +1 -0
  126. package/dist/__tests__/lib/fs-helpers/tail-file.test.js +11 -0
  127. package/dist/__tests__/lib/fs-helpers/tail-file.test.js.map +1 -0
  128. package/dist/__tests__/lib/path-validation.test.js +93 -104
  129. package/dist/__tests__/lib/path-validation.test.js.map +1 -1
  130. package/dist/__tests__/schemas/validators.test.js +111 -115
  131. package/dist/__tests__/schemas/validators.test.js.map +1 -1
  132. package/dist/__tests__/security/filesystem-boundary.test.js +41 -36
  133. package/dist/__tests__/security/filesystem-boundary.test.js.map +1 -1
  134. package/dist/instructions.md +20 -19
  135. package/dist/lib/constants.d.ts +2 -0
  136. package/dist/lib/constants.d.ts.map +1 -1
  137. package/dist/lib/constants.js +2 -0
  138. package/dist/lib/constants.js.map +1 -1
  139. package/dist/lib/errors.d.ts +2 -18
  140. package/dist/lib/errors.d.ts.map +1 -1
  141. package/dist/lib/errors.js +57 -29
  142. package/dist/lib/errors.js.map +1 -1
  143. package/dist/lib/file-operations/analyze-directory.d.ts +1 -0
  144. package/dist/lib/file-operations/analyze-directory.d.ts.map +1 -1
  145. package/dist/lib/file-operations/analyze-directory.js +91 -40
  146. package/dist/lib/file-operations/analyze-directory.js.map +1 -1
  147. package/dist/lib/file-operations/directory-helpers.d.ts +2 -19
  148. package/dist/lib/file-operations/directory-helpers.d.ts.map +1 -1
  149. package/dist/lib/file-operations/directory-helpers.js +26 -90
  150. package/dist/lib/file-operations/directory-helpers.js.map +1 -1
  151. package/dist/lib/file-operations/directory-tree-helpers.d.ts +38 -0
  152. package/dist/lib/file-operations/directory-tree-helpers.d.ts.map +1 -0
  153. package/dist/lib/file-operations/directory-tree-helpers.js +167 -0
  154. package/dist/lib/file-operations/directory-tree-helpers.js.map +1 -0
  155. package/dist/lib/file-operations/directory-tree.d.ts.map +1 -1
  156. package/dist/lib/file-operations/directory-tree.js +44 -154
  157. package/dist/lib/file-operations/directory-tree.js.map +1 -1
  158. package/dist/lib/file-operations/list-directory-helpers.d.ts +2 -1
  159. package/dist/lib/file-operations/list-directory-helpers.d.ts.map +1 -1
  160. package/dist/lib/file-operations/list-directory-helpers.js +16 -4
  161. package/dist/lib/file-operations/list-directory-helpers.js.map +1 -1
  162. package/dist/lib/file-operations/list-directory.d.ts +4 -2
  163. package/dist/lib/file-operations/list-directory.d.ts.map +1 -1
  164. package/dist/lib/file-operations/list-directory.js +42 -20
  165. package/dist/lib/file-operations/list-directory.js.map +1 -1
  166. package/dist/lib/file-operations/pattern-validator.d.ts +0 -10
  167. package/dist/lib/file-operations/pattern-validator.d.ts.map +1 -1
  168. package/dist/lib/file-operations/pattern-validator.js +44 -43
  169. package/dist/lib/file-operations/pattern-validator.js.map +1 -1
  170. package/dist/lib/file-operations/read-multiple-files.d.ts +3 -2
  171. package/dist/lib/file-operations/read-multiple-files.d.ts.map +1 -1
  172. package/dist/lib/file-operations/read-multiple-files.js +46 -29
  173. package/dist/lib/file-operations/read-multiple-files.js.map +1 -1
  174. package/dist/lib/file-operations/search/context-manager.d.ts +2 -0
  175. package/dist/lib/file-operations/search/context-manager.d.ts.map +1 -1
  176. package/dist/lib/file-operations/search/context-manager.js +11 -6
  177. package/dist/lib/file-operations/search/context-manager.js.map +1 -1
  178. package/dist/lib/file-operations/search/engine-options.d.ts +19 -0
  179. package/dist/lib/file-operations/search/engine-options.d.ts.map +1 -0
  180. package/dist/lib/file-operations/search/engine-options.js +32 -0
  181. package/dist/lib/file-operations/search/engine-options.js.map +1 -0
  182. package/dist/lib/file-operations/search/engine-stream.d.ts +6 -0
  183. package/dist/lib/file-operations/search/engine-stream.d.ts.map +1 -0
  184. package/dist/lib/file-operations/search/engine-stream.js +130 -0
  185. package/dist/lib/file-operations/search/engine-stream.js.map +1 -0
  186. package/dist/lib/file-operations/search/engine.d.ts +1 -17
  187. package/dist/lib/file-operations/search/engine.d.ts.map +1 -1
  188. package/dist/lib/file-operations/search/engine.js +7 -117
  189. package/dist/lib/file-operations/search/engine.js.map +1 -1
  190. package/dist/lib/file-operations/search/file-processor.d.ts.map +1 -1
  191. package/dist/lib/file-operations/search/file-processor.js +33 -25
  192. package/dist/lib/file-operations/search/file-processor.js.map +1 -1
  193. package/dist/lib/file-operations/search/match-strategy.d.ts.map +1 -1
  194. package/dist/lib/file-operations/search/match-strategy.js +49 -54
  195. package/dist/lib/file-operations/search/match-strategy.js.map +1 -1
  196. package/dist/lib/file-operations/search-files-helpers.d.ts +42 -0
  197. package/dist/lib/file-operations/search-files-helpers.d.ts.map +1 -0
  198. package/dist/lib/file-operations/search-files-helpers.js +180 -0
  199. package/dist/lib/file-operations/search-files-helpers.js.map +1 -0
  200. package/dist/lib/file-operations/search-files.d.ts +2 -9
  201. package/dist/lib/file-operations/search-files.d.ts.map +1 -1
  202. package/dist/lib/file-operations/search-files.js +8 -129
  203. package/dist/lib/file-operations/search-files.js.map +1 -1
  204. package/dist/lib/file-operations/sorting.d.ts +3 -2
  205. package/dist/lib/file-operations/sorting.d.ts.map +1 -1
  206. package/dist/lib/fs-helpers/binary-detect.d.ts.map +1 -1
  207. package/dist/lib/fs-helpers/binary-detect.js +16 -10
  208. package/dist/lib/fs-helpers/binary-detect.js.map +1 -1
  209. package/dist/lib/fs-helpers/fs-utils.d.ts.map +1 -1
  210. package/dist/lib/fs-helpers/fs-utils.js +16 -10
  211. package/dist/lib/fs-helpers/fs-utils.js.map +1 -1
  212. package/dist/lib/fs-helpers/readers/line-range.d.ts +4 -2
  213. package/dist/lib/fs-helpers/readers/line-range.d.ts.map +1 -1
  214. package/dist/lib/fs-helpers/readers/line-range.js +21 -15
  215. package/dist/lib/fs-helpers/readers/line-range.js.map +1 -1
  216. package/dist/lib/fs-helpers/readers/read-file.d.ts +6 -3
  217. package/dist/lib/fs-helpers/readers/read-file.d.ts.map +1 -1
  218. package/dist/lib/fs-helpers/readers/read-file.js +58 -19
  219. package/dist/lib/fs-helpers/readers/read-file.js.map +1 -1
  220. package/dist/lib/fs-helpers/readers/tail-file.d.ts.map +1 -1
  221. package/dist/lib/fs-helpers/readers/tail-file.js +27 -10
  222. package/dist/lib/fs-helpers/readers/tail-file.js.map +1 -1
  223. package/dist/lib/fs-helpers/readers/utf8.d.ts.map +1 -1
  224. package/dist/lib/fs-helpers/readers/utf8.js +20 -10
  225. package/dist/lib/fs-helpers/readers/utf8.js.map +1 -1
  226. package/dist/lib/path-validation/allowed-directories.d.ts +1 -2
  227. package/dist/lib/path-validation/allowed-directories.d.ts.map +1 -1
  228. package/dist/lib/path-validation/allowed-directories.js +25 -15
  229. package/dist/lib/path-validation/allowed-directories.js.map +1 -1
  230. package/dist/lib/path-validation/errors.d.ts +0 -1
  231. package/dist/lib/path-validation/errors.d.ts.map +1 -1
  232. package/dist/lib/path-validation/errors.js +26 -12
  233. package/dist/lib/path-validation/errors.js.map +1 -1
  234. package/dist/lib/path-validation/validators.d.ts +1 -0
  235. package/dist/lib/path-validation/validators.d.ts.map +1 -1
  236. package/dist/lib/path-validation/validators.js +26 -3
  237. package/dist/lib/path-validation/validators.js.map +1 -1
  238. package/dist/lib/path-validation.d.ts +2 -2
  239. package/dist/lib/path-validation.d.ts.map +1 -1
  240. package/dist/lib/path-validation.js +2 -2
  241. package/dist/lib/path-validation.js.map +1 -1
  242. package/dist/schemas/input-helpers.d.ts +2 -1
  243. package/dist/schemas/input-helpers.d.ts.map +1 -1
  244. package/dist/schemas/input-helpers.js +10 -1
  245. package/dist/schemas/input-helpers.js.map +1 -1
  246. package/dist/schemas/inputs.d.ts +2 -1
  247. package/dist/schemas/inputs.d.ts.map +1 -1
  248. package/dist/schemas/inputs.js +2 -1
  249. package/dist/schemas/inputs.js.map +1 -1
  250. package/dist/schemas/outputs.d.ts +12 -12
  251. package/dist/server.d.ts.map +1 -1
  252. package/dist/server.js +79 -35
  253. package/dist/server.js.map +1 -1
  254. package/dist/tools/analyze-directory.d.ts.map +1 -1
  255. package/dist/tools/analyze-directory.js +8 -34
  256. package/dist/tools/analyze-directory.js.map +1 -1
  257. package/dist/tools/directory-tree.d.ts.map +1 -1
  258. package/dist/tools/directory-tree.js +14 -35
  259. package/dist/tools/directory-tree.js.map +1 -1
  260. package/dist/tools/get-file-info.d.ts.map +1 -1
  261. package/dist/tools/get-file-info.js +4 -15
  262. package/dist/tools/get-file-info.js.map +1 -1
  263. package/dist/tools/list-allowed-dirs.d.ts.map +1 -1
  264. package/dist/tools/list-allowed-dirs.js +10 -3
  265. package/dist/tools/list-allowed-dirs.js.map +1 -1
  266. package/dist/tools/list-directory.d.ts.map +1 -1
  267. package/dist/tools/list-directory.js +30 -53
  268. package/dist/tools/list-directory.js.map +1 -1
  269. package/dist/tools/read-file.d.ts.map +1 -1
  270. package/dist/tools/read-file.js +31 -23
  271. package/dist/tools/read-file.js.map +1 -1
  272. package/dist/tools/read-media-file.d.ts.map +1 -1
  273. package/dist/tools/read-media-file.js +3 -3
  274. package/dist/tools/read-media-file.js.map +1 -1
  275. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  276. package/dist/tools/read-multiple-files.js +19 -18
  277. package/dist/tools/read-multiple-files.js.map +1 -1
  278. package/dist/tools/search-content.d.ts.map +1 -1
  279. package/dist/tools/search-content.js +23 -20
  280. package/dist/tools/search-content.js.map +1 -1
  281. package/dist/tools/search-files.d.ts.map +1 -1
  282. package/dist/tools/search-files.js +4 -30
  283. package/dist/tools/search-files.js.map +1 -1
  284. package/dist/tools/shared/formatting.d.ts +13 -0
  285. package/dist/tools/shared/formatting.d.ts.map +1 -0
  286. package/dist/tools/shared/formatting.js +31 -0
  287. package/dist/tools/shared/formatting.js.map +1 -0
  288. package/dist/tools/shared/search-formatting.d.ts.map +1 -1
  289. package/dist/tools/shared/search-formatting.js +32 -33
  290. package/dist/tools/shared/search-formatting.js.map +1 -1
  291. package/package.json +1 -1
@@ -1,111 +1,100 @@
1
1
  import * as fs from 'node:fs/promises';
2
2
  import * as os from 'node:os';
3
3
  import * as path from 'node:path';
4
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
4
+ import { afterAll, beforeAll, expect, it } from 'vitest';
5
5
  import { normalizePath } from '../../lib/path-utils.js';
6
6
  import { getAllowedDirectories, setAllowedDirectories, validateExistingPath, } from '../../lib/path-validation.js';
7
- describe('Path Validation', () => {
8
- let testDir;
9
- let subDir;
10
- let testFile;
11
- beforeAll(async () => {
12
- // Create a temporary test directory
13
- testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-test-'));
14
- subDir = path.join(testDir, 'subdir');
15
- await fs.mkdir(subDir);
16
- testFile = path.join(subDir, 'test.txt');
17
- await fs.writeFile(testFile, 'test content');
18
- // Set allowed directories to our test directory
19
- setAllowedDirectories([normalizePath(testDir)]);
20
- });
21
- afterAll(async () => {
22
- // Cleanup
23
- try {
24
- await fs.rm(testDir, { recursive: true, force: true });
25
- }
26
- catch {
27
- // Ignore cleanup errors
28
- }
29
- });
30
- describe('setAllowedDirectories / getAllowedDirectories', () => {
31
- it('should set and get allowed directories', () => {
32
- const dirs = ['/test/dir1', '/test/dir2'];
33
- setAllowedDirectories(dirs.map(normalizePath));
34
- const result = getAllowedDirectories();
35
- expect(result.length).toBe(2);
36
- // Reset to test directory
37
- setAllowedDirectories([normalizePath(testDir)]);
38
- });
39
- it('should return empty array when no directories set', () => {
40
- setAllowedDirectories([]);
41
- expect(getAllowedDirectories()).toEqual([]);
42
- // Reset to test directory
43
- setAllowedDirectories([normalizePath(testDir)]);
44
- });
45
- });
46
- describe('validateExistingPath', () => {
47
- it('should allow paths within allowed directories', async () => {
48
- const result = await validateExistingPath(testFile);
49
- expect(result).toContain('test.txt');
50
- });
51
- it('should allow the allowed directory itself', async () => {
52
- const result = await validateExistingPath(testDir);
53
- expect(result).toBeTruthy();
54
- });
55
- it('should allow subdirectories within allowed directories', async () => {
56
- const result = await validateExistingPath(subDir);
57
- expect(result).toContain('subdir');
58
- });
59
- it('should reject paths outside allowed directories', async () => {
60
- await expect(validateExistingPath('/etc/passwd')).rejects.toThrow();
61
- });
62
- it('should reject paths with .. traversal attempts', async () => {
63
- const traversalPath = path.join(testDir, '..', 'etc', 'passwd');
64
- await expect(validateExistingPath(traversalPath)).rejects.toThrow();
65
- });
66
- it('should reject non-existent paths', async () => {
67
- const nonExistent = path.join(testDir, 'non-existent-file.txt');
68
- await expect(validateExistingPath(nonExistent)).rejects.toThrow();
69
- });
70
- it('should allow paths when filesystem root is allowed', async () => {
71
- const rootDir = path.parse(testDir).root;
72
- setAllowedDirectories([normalizePath(rootDir)]);
73
- const result = await validateExistingPath(testFile);
74
- expect(result).toContain('test.txt');
75
- // Reset to test directory
76
- setAllowedDirectories([normalizePath(testDir)]);
77
- });
78
- });
79
- describe('edge cases', () => {
80
- it('should handle paths with spaces', async () => {
81
- const dirWithSpaces = path.join(testDir, 'dir with spaces');
82
- await fs.mkdir(dirWithSpaces);
83
- const fileInDir = path.join(dirWithSpaces, 'file.txt');
84
- await fs.writeFile(fileInDir, 'content');
85
- const result = await validateExistingPath(fileInDir);
86
- expect(result).toContain('file.txt');
87
- await fs.rm(dirWithSpaces, { recursive: true });
88
- });
89
- it('should handle paths with special characters', async () => {
90
- const specialDir = path.join(testDir, 'special-chars_123');
91
- await fs.mkdir(specialDir);
92
- const fileInDir = path.join(specialDir, 'test_file-1.txt');
93
- await fs.writeFile(fileInDir, 'content');
94
- const result = await validateExistingPath(fileInDir);
95
- expect(result).toContain('test_file-1.txt');
96
- await fs.rm(specialDir, { recursive: true });
97
- });
98
- it('should reject empty path', async () => {
99
- await expect(validateExistingPath('')).rejects.toThrow(/empty|whitespace/i);
100
- });
101
- it('should reject whitespace-only path', async () => {
102
- await expect(validateExistingPath(' ')).rejects.toThrow(/empty|whitespace/i);
103
- });
104
- it('should reject path with null bytes', async () => {
105
- // Paths with null bytes are invalid on most filesystems
106
- const pathWithNull = path.join(testDir, 'file\0name.txt');
107
- await expect(validateExistingPath(pathWithNull)).rejects.toThrow();
108
- });
109
- });
7
+ let testDir = '';
8
+ let subDir = '';
9
+ let testFile = '';
10
+ beforeAll(async () => {
11
+ testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-test-'));
12
+ subDir = path.join(testDir, 'subdir');
13
+ await fs.mkdir(subDir);
14
+ testFile = path.join(subDir, 'test.txt');
15
+ await fs.writeFile(testFile, 'test content');
16
+ setAllowedDirectories([normalizePath(testDir)]);
17
+ });
18
+ afterAll(async () => {
19
+ try {
20
+ await fs.rm(testDir, { recursive: true, force: true });
21
+ }
22
+ catch {
23
+ // ignore cleanup errors
24
+ }
25
+ });
26
+ function resetAllowedDirectories() {
27
+ setAllowedDirectories([normalizePath(testDir)]);
28
+ }
29
+ async function createFileInDir(dirName, fileName) {
30
+ const dirPath = path.join(testDir, dirName);
31
+ await fs.mkdir(dirPath, { recursive: true });
32
+ const filePath = path.join(dirPath, fileName);
33
+ await fs.writeFile(filePath, 'content');
34
+ return filePath;
35
+ }
36
+ it('setAllowedDirectories and getAllowedDirectories set and get allowed directories', () => {
37
+ const dirs = ['/test/dir1', '/test/dir2'];
38
+ setAllowedDirectories(dirs.map(normalizePath));
39
+ const result = getAllowedDirectories();
40
+ expect(result.length).toBe(2);
41
+ resetAllowedDirectories();
42
+ });
43
+ it('setAllowedDirectories returns empty array when no directories set', () => {
44
+ setAllowedDirectories([]);
45
+ expect(getAllowedDirectories()).toEqual([]);
46
+ resetAllowedDirectories();
47
+ });
48
+ it('validateExistingPath allows paths within allowed directories', async () => {
49
+ const result = await validateExistingPath(testFile);
50
+ expect(result).toContain('test.txt');
51
+ });
52
+ it('validateExistingPath allows the allowed directory itself', async () => {
53
+ const result = await validateExistingPath(testDir);
54
+ expect(result).toBeTruthy();
55
+ });
56
+ it('validateExistingPath allows subdirectories within allowed directories', async () => {
57
+ const result = await validateExistingPath(subDir);
58
+ expect(result).toContain('subdir');
59
+ });
60
+ it('validateExistingPath rejects paths outside allowed directories', async () => {
61
+ await expect(validateExistingPath('/etc/passwd')).rejects.toThrow();
62
+ });
63
+ it('validateExistingPath rejects traversal attempts', async () => {
64
+ const traversalPath = path.join(testDir, '..', 'etc', 'passwd');
65
+ await expect(validateExistingPath(traversalPath)).rejects.toThrow();
66
+ });
67
+ it('validateExistingPath rejects non-existent paths', async () => {
68
+ const nonExistent = path.join(testDir, 'non-existent-file.txt');
69
+ await expect(validateExistingPath(nonExistent)).rejects.toThrow();
70
+ });
71
+ it('validateExistingPath allows paths when filesystem root is allowed', async () => {
72
+ const rootDir = path.parse(testDir).root;
73
+ setAllowedDirectories([normalizePath(rootDir)]);
74
+ const result = await validateExistingPath(testFile);
75
+ expect(result).toContain('test.txt');
76
+ resetAllowedDirectories();
77
+ });
78
+ it('validateExistingPath handles paths with spaces', async () => {
79
+ const fileInDir = await createFileInDir('dir with spaces', 'file.txt');
80
+ const result = await validateExistingPath(fileInDir);
81
+ expect(result).toContain('file.txt');
82
+ await fs.rm(path.dirname(fileInDir), { recursive: true });
83
+ });
84
+ it('validateExistingPath handles paths with special characters', async () => {
85
+ const fileInDir = await createFileInDir('special-chars_123', 'test_file-1.txt');
86
+ const result = await validateExistingPath(fileInDir);
87
+ expect(result).toContain('test_file-1.txt');
88
+ await fs.rm(path.dirname(fileInDir), { recursive: true });
89
+ });
90
+ it('validateExistingPath rejects empty path', async () => {
91
+ await expect(validateExistingPath('')).rejects.toThrow(/empty|whitespace/i);
92
+ });
93
+ it('validateExistingPath rejects whitespace-only path', async () => {
94
+ await expect(validateExistingPath(' ')).rejects.toThrow(/empty|whitespace/i);
95
+ });
96
+ it('validateExistingPath rejects path with null bytes', async () => {
97
+ const pathWithNull = path.join(testDir, 'file\0name.txt');
98
+ await expect(validateExistingPath(pathWithNull)).rejects.toThrow();
110
99
  });
111
100
  //# sourceMappingURL=path-validation.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-validation.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/path-validation.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"path-validation.test.js","sourceRoot":"","sources":["../../../src/__tests__/lib/path-validation.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from 'vitest';
1
+ import { expect, it } from 'vitest';
2
2
  import { ErrorCode, McpError } from '../../lib/errors.js';
3
3
  function expectMcpError(fn, options) {
4
4
  try {
@@ -12,137 +12,133 @@ function expectMcpError(fn, options) {
12
12
  expect(mcpError.message).toContain(options.messageIncludes);
13
13
  }
14
14
  }
15
- // Inline validation functions (matching the implementation in tools)
16
- function validateLineRange(params) {
17
- const { lineStart, lineEnd, head, tail, path } = params;
15
+ function assertLineRangePair(lineStart, lineEnd, path) {
18
16
  const hasLineStart = lineStart !== undefined;
19
17
  const hasLineEnd = lineEnd !== undefined;
20
- if (hasLineStart !== hasLineEnd) {
21
- const missing = hasLineStart ? 'lineEnd' : 'lineStart';
22
- const provided = hasLineStart ? 'lineStart' : 'lineEnd';
23
- throw new McpError(ErrorCode.E_INVALID_INPUT, `Invalid lineRange: ${provided} requires ${missing} to also be specified`, path);
24
- }
25
- if (hasLineStart && hasLineEnd && lineEnd < lineStart) {
26
- throw new McpError(ErrorCode.E_INVALID_INPUT, `Invalid lineRange: lineEnd (${lineEnd}) must be >= lineStart (${lineStart})`, path);
27
- }
28
- const hasLineRange = hasLineStart && hasLineEnd;
18
+ if (hasLineStart === hasLineEnd)
19
+ return;
20
+ const missing = hasLineStart ? 'lineEnd' : 'lineStart';
21
+ const provided = hasLineStart ? 'lineStart' : 'lineEnd';
22
+ throw new McpError(ErrorCode.E_INVALID_INPUT, `Invalid lineRange: ${provided} requires ${missing} to also be specified`, path);
23
+ }
24
+ function assertLineRangeOrder(lineStart, lineEnd, path) {
25
+ if (lineStart === undefined || lineEnd === undefined)
26
+ return;
27
+ if (lineEnd >= lineStart)
28
+ return;
29
+ throw new McpError(ErrorCode.E_INVALID_INPUT, `Invalid lineRange: lineEnd (${lineEnd}) must be >= lineStart (${lineStart})`, path);
30
+ }
31
+ function assertExclusiveLineOptions(hasLineRange, head, tail, path) {
29
32
  const optionsCount = [
30
33
  hasLineRange,
31
34
  head !== undefined,
32
35
  tail !== undefined,
33
36
  ].filter(Boolean).length;
34
- if (optionsCount > 1) {
35
- throw new McpError(ErrorCode.E_INVALID_INPUT, 'Cannot specify multiple of lineRange (lineStart + lineEnd), head, or tail simultaneously', path);
36
- }
37
+ if (optionsCount <= 1)
38
+ return;
39
+ throw new McpError(ErrorCode.E_INVALID_INPUT, 'Cannot specify multiple of lineRange (lineStart + lineEnd), head, or tail simultaneously', path);
40
+ }
41
+ function validateLineRange(params) {
42
+ const { lineStart, lineEnd, head, tail, path } = params;
43
+ assertLineRangePair(lineStart, lineEnd, path);
44
+ assertLineRangeOrder(lineStart, lineEnd, path);
45
+ const hasLineRange = lineStart !== undefined && lineEnd !== undefined;
46
+ assertExclusiveLineOptions(hasLineRange, head, tail, path);
37
47
  }
38
48
  function validateHeadTail(head, tail) {
39
49
  if (head !== undefined && tail !== undefined) {
40
50
  throw new McpError(ErrorCode.E_INVALID_INPUT, 'Cannot specify both head and tail simultaneously');
41
51
  }
42
52
  }
43
- describe('validateLineRange', () => {
44
- const validCases = [
45
- {
46
- name: 'valid lineRange with both lineStart and lineEnd',
47
- params: { lineStart: 1, lineEnd: 10, path: '/test/file.txt' },
48
- },
49
- {
50
- name: 'no line options',
51
- params: { path: '/test/file.txt' },
52
- },
53
- {
54
- name: 'head option alone',
55
- params: { head: 10, path: '/test/file.txt' },
56
- },
57
- {
58
- name: 'tail option alone',
59
- params: { tail: 10, path: '/test/file.txt' },
60
- },
61
- {
62
- name: 'lineEnd equal to lineStart',
63
- params: { lineStart: 5, lineEnd: 5, path: '/test/file.txt' },
64
- },
65
- ];
66
- for (const testCase of validCases) {
67
- it(`should accept ${testCase.name}`, () => {
68
- expect(() => {
69
- validateLineRange(testCase.params);
70
- }).not.toThrow();
71
- });
72
- }
73
- const invalidCases = [
74
- {
75
- name: 'lineStart without lineEnd',
76
- params: { lineStart: 5, path: '/test/file.txt' },
77
- message: 'lineStart requires lineEnd',
78
- },
79
- {
80
- name: 'lineEnd without lineStart',
81
- params: { lineEnd: 10, path: '/test/file.txt' },
82
- message: 'lineEnd requires lineStart',
83
- },
84
- {
85
- name: 'lineEnd < lineStart',
86
- params: { lineStart: 10, lineEnd: 5, path: '/test/file.txt' },
87
- message: 'lineEnd (5) must be >= lineStart (10)',
88
- },
89
- {
90
- name: 'lineRange with head',
91
- params: {
92
- lineStart: 1,
93
- lineEnd: 10,
94
- head: 5,
95
- path: '/test/file.txt',
96
- },
97
- message: 'Cannot specify multiple',
98
- },
99
- {
100
- name: 'lineRange with tail',
101
- params: {
102
- lineStart: 1,
103
- lineEnd: 10,
104
- tail: 5,
105
- path: '/test/file.txt',
106
- },
107
- message: 'Cannot specify multiple',
108
- },
109
- {
110
- name: 'head with tail',
111
- params: { head: 5, tail: 5, path: '/test/file.txt' },
112
- message: 'Cannot specify multiple',
113
- },
114
- ];
115
- for (const testCase of invalidCases) {
116
- it(`should reject ${testCase.name}`, () => {
117
- expectMcpError(() => {
118
- validateLineRange(testCase.params);
119
- }, {
120
- code: ErrorCode.E_INVALID_INPUT,
121
- messageIncludes: testCase.message,
122
- });
123
- });
124
- }
125
- });
126
- describe('validateHeadTail', () => {
127
- const validCases = [
128
- [10, undefined],
129
- [undefined, 10],
130
- [undefined, undefined],
131
- ];
132
- for (const [head, tail] of validCases) {
133
- it('should accept valid head/tail combination', () => {
134
- expect(() => {
135
- validateHeadTail(head, tail);
136
- }).not.toThrow();
137
- });
138
- }
139
- it('should reject both head and tail', () => {
53
+ const validLineRangeCases = [
54
+ {
55
+ name: 'valid lineRange with both lineStart and lineEnd',
56
+ params: { lineStart: 1, lineEnd: 10, path: '/test/file.txt' },
57
+ },
58
+ {
59
+ name: 'no line options',
60
+ params: { path: '/test/file.txt' },
61
+ },
62
+ {
63
+ name: 'head option alone',
64
+ params: { head: 10, path: '/test/file.txt' },
65
+ },
66
+ {
67
+ name: 'tail option alone',
68
+ params: { tail: 10, path: '/test/file.txt' },
69
+ },
70
+ {
71
+ name: 'lineEnd equal to lineStart',
72
+ params: { lineStart: 5, lineEnd: 5, path: '/test/file.txt' },
73
+ },
74
+ ];
75
+ for (const testCase of validLineRangeCases) {
76
+ it(`validateLineRange accepts ${testCase.name}`, () => {
77
+ expect(() => {
78
+ validateLineRange(testCase.params);
79
+ }).not.toThrow();
80
+ });
81
+ }
82
+ const invalidLineRangeCases = [
83
+ {
84
+ name: 'lineStart without lineEnd',
85
+ params: { lineStart: 5, path: '/test/file.txt' },
86
+ message: 'lineStart requires lineEnd',
87
+ },
88
+ {
89
+ name: 'lineEnd without lineStart',
90
+ params: { lineEnd: 10, path: '/test/file.txt' },
91
+ message: 'lineEnd requires lineStart',
92
+ },
93
+ {
94
+ name: 'lineEnd < lineStart',
95
+ params: { lineStart: 10, lineEnd: 5, path: '/test/file.txt' },
96
+ message: 'lineEnd (5) must be >= lineStart (10)',
97
+ },
98
+ {
99
+ name: 'lineRange with head',
100
+ params: { lineStart: 1, lineEnd: 10, head: 5, path: '/test/file.txt' },
101
+ message: 'Cannot specify multiple',
102
+ },
103
+ {
104
+ name: 'lineRange with tail',
105
+ params: { lineStart: 1, lineEnd: 10, tail: 5, path: '/test/file.txt' },
106
+ message: 'Cannot specify multiple',
107
+ },
108
+ {
109
+ name: 'head with tail',
110
+ params: { head: 5, tail: 5, path: '/test/file.txt' },
111
+ message: 'Cannot specify multiple',
112
+ },
113
+ ];
114
+ for (const testCase of invalidLineRangeCases) {
115
+ it(`validateLineRange rejects ${testCase.name}`, () => {
140
116
  expectMcpError(() => {
141
- validateHeadTail(5, 5);
117
+ validateLineRange(testCase.params);
142
118
  }, {
143
119
  code: ErrorCode.E_INVALID_INPUT,
144
- messageIncludes: 'Cannot specify both head and tail',
120
+ messageIncludes: testCase.message,
145
121
  });
146
122
  });
123
+ }
124
+ const validHeadTailCases = [
125
+ [10, undefined],
126
+ [undefined, 10],
127
+ [undefined, undefined],
128
+ ];
129
+ for (const [head, tail] of validHeadTailCases) {
130
+ it('validateHeadTail accepts valid head/tail combination', () => {
131
+ expect(() => {
132
+ validateHeadTail(head, tail);
133
+ }).not.toThrow();
134
+ });
135
+ }
136
+ it('validateHeadTail rejects both head and tail', () => {
137
+ expectMcpError(() => {
138
+ validateHeadTail(5, 5);
139
+ }, {
140
+ code: ErrorCode.E_INVALID_INPUT,
141
+ messageIncludes: 'Cannot specify both head and tail',
142
+ });
147
143
  });
148
144
  //# sourceMappingURL=validators.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validators.test.js","sourceRoot":"","sources":["../../../src/__tests__/schemas/validators.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validators.test.js","sourceRoot":"","sources":["../../../src/__tests__/schemas/validators.test.ts"],"names":[],"mappings":"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"}
@@ -2,50 +2,55 @@ import * as fs from 'node:fs/promises';
2
2
  import * as path from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import fg from 'fast-glob';
5
- import { describe, expect, it } from 'vitest';
5
+ import { expect, it } from 'vitest';
6
6
  function getRepoRoot() {
7
7
  const currentDir = path.dirname(fileURLToPath(import.meta.url));
8
- // src/__tests__/security -> repo root
9
8
  return path.resolve(currentDir, '../../../../');
10
9
  }
11
10
  function hasFsImport(source) {
12
11
  return (/from\s+['"]node:fs\/promises['"]/u.test(source) ||
13
12
  /from\s+['"]node:fs['"]/u.test(source));
14
13
  }
15
- describe('security boundary: filesystem access', () => {
16
- it('keeps direct node:fs imports inside boundary modules', async () => {
17
- const repoRoot = getRepoRoot();
18
- const sourceFiles = await fg(['src/**/*.ts'], {
19
- cwd: repoRoot,
20
- ignore: ['src/__tests__/**'],
21
- onlyFiles: true,
22
- dot: false,
23
- });
24
- // These files are allowed to import node:fs*/ because they either:
25
- // - implement the security boundary itself
26
- // - centralize filesystem operations
27
- // - bootstrap the server before allowed directories exist
28
- const allowedFsImportFiles = new Set([
29
- 'src/server.ts',
30
- 'src/lib/path-validation.ts',
31
- 'src/lib/file-operations.ts',
32
- 'src/lib/fs-helpers.ts',
33
- 'src/lib/file-operations/search-content.ts',
34
- ]);
35
- const offenders = [];
36
- for (const relPath of sourceFiles) {
37
- const absPath = path.join(repoRoot, relPath);
38
- const content = await fs.readFile(absPath, 'utf-8');
39
- if (!hasFsImport(content)) {
40
- continue;
41
- }
42
- if (!allowedFsImportFiles.has(relPath.replace(/\\/gu, '/'))) {
43
- offenders.push(relPath);
44
- }
45
- }
46
- expect(offenders, `Unexpected node:fs imports detected outside boundary modules. ` +
47
- `To keep "validate-before-access" auditable, route filesystem access through ` +
48
- `src/lib/file-operations.ts and src/lib/fs-helpers.ts (and validate paths in src/lib/path-validation.ts).`).toEqual([]);
14
+ function normalizeRelPath(relPath) {
15
+ return relPath.replace(/\\/gu, '/');
16
+ }
17
+ function getAllowedFsImportFiles() {
18
+ return new Set([
19
+ 'src/server.ts',
20
+ 'src/lib/path-validation.ts',
21
+ 'src/lib/file-operations.ts',
22
+ 'src/lib/fs-helpers.ts',
23
+ 'src/lib/file-operations/search-content.ts',
24
+ ]);
25
+ }
26
+ async function listSourceFiles(repoRoot) {
27
+ return await fg(['src/**/*.ts'], {
28
+ cwd: repoRoot,
29
+ ignore: ['src/__tests__/**'],
30
+ onlyFiles: true,
31
+ dot: false,
49
32
  });
33
+ }
34
+ async function collectFsImportOffenders(repoRoot, sourceFiles, allowedFsImportFiles) {
35
+ const offenders = [];
36
+ for (const relPath of sourceFiles) {
37
+ const absPath = path.join(repoRoot, relPath);
38
+ const content = await fs.readFile(absPath, 'utf-8');
39
+ if (!hasFsImport(content))
40
+ continue;
41
+ if (!allowedFsImportFiles.has(normalizeRelPath(relPath))) {
42
+ offenders.push(relPath);
43
+ }
44
+ }
45
+ return offenders;
46
+ }
47
+ it('keeps direct node:fs imports inside boundary modules', async () => {
48
+ const repoRoot = getRepoRoot();
49
+ const sourceFiles = await listSourceFiles(repoRoot);
50
+ const allowedFsImportFiles = getAllowedFsImportFiles();
51
+ const offenders = await collectFsImportOffenders(repoRoot, sourceFiles, allowedFsImportFiles);
52
+ expect(offenders, `Unexpected node:fs imports detected outside boundary modules. ` +
53
+ `To keep "validate-before-access" auditable, route filesystem access through ` +
54
+ `src/lib/file-operations.ts and src/lib/fs-helpers.ts (and validate paths in src/lib/path-validation.ts).`).toEqual([]);
50
55
  });
51
56
  //# sourceMappingURL=filesystem-boundary.test.js.map