@j0hanz/filesystem-mcp 1.19.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +333 -838
  2. package/dist/cli-help.d.ts +3 -0
  3. package/dist/cli-help.d.ts.map +1 -0
  4. package/dist/cli-help.js +169 -0
  5. package/dist/cli-help.js.map +1 -0
  6. package/dist/cli.d.ts +28 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +168 -123
  9. package/dist/cli.js.map +1 -0
  10. package/dist/core/concurrency.d.ts +70 -0
  11. package/dist/core/concurrency.d.ts.map +1 -0
  12. package/dist/core/concurrency.js +173 -0
  13. package/dist/core/concurrency.js.map +1 -0
  14. package/dist/core/config.d.ts +19 -0
  15. package/dist/core/config.d.ts.map +1 -0
  16. package/dist/core/config.js +11 -0
  17. package/dist/core/config.js.map +1 -0
  18. package/dist/core/cursor.d.ts +23 -0
  19. package/dist/core/cursor.d.ts.map +1 -0
  20. package/dist/core/cursor.js +62 -0
  21. package/dist/core/cursor.js.map +1 -0
  22. package/dist/core/errors.d.ts +96 -0
  23. package/dist/core/errors.d.ts.map +1 -0
  24. package/dist/core/errors.js +356 -0
  25. package/dist/core/errors.js.map +1 -0
  26. package/dist/core/file-uri.d.ts +24 -0
  27. package/dist/core/file-uri.d.ts.map +1 -0
  28. package/dist/core/file-uri.js +52 -0
  29. package/dist/core/file-uri.js.map +1 -0
  30. package/dist/core/fmt.d.ts +38 -0
  31. package/dist/core/fmt.d.ts.map +1 -0
  32. package/dist/core/fmt.js +109 -0
  33. package/dist/core/fmt.js.map +1 -0
  34. package/dist/core/fs.d.ts +108 -0
  35. package/dist/core/fs.d.ts.map +1 -0
  36. package/dist/core/fs.js +243 -0
  37. package/dist/core/fs.js.map +1 -0
  38. package/dist/core/glob.d.ts +41 -0
  39. package/dist/core/glob.d.ts.map +1 -0
  40. package/dist/core/glob.js +399 -0
  41. package/dist/core/glob.js.map +1 -0
  42. package/dist/core/input-required.d.ts +147 -0
  43. package/dist/core/input-required.d.ts.map +1 -0
  44. package/dist/core/input-required.js +261 -0
  45. package/dist/core/input-required.js.map +1 -0
  46. package/dist/core/mime.d.ts +15 -0
  47. package/dist/core/mime.d.ts.map +1 -0
  48. package/dist/core/mime.js +188 -0
  49. package/dist/core/mime.js.map +1 -0
  50. package/dist/core/observability.d.ts +10 -0
  51. package/dist/core/observability.d.ts.map +1 -0
  52. package/dist/core/observability.js +76 -0
  53. package/dist/core/observability.js.map +1 -0
  54. package/dist/core/page-store.d.ts +41 -0
  55. package/dist/core/page-store.d.ts.map +1 -0
  56. package/dist/core/page-store.js +74 -0
  57. package/dist/core/page-store.js.map +1 -0
  58. package/dist/core/path-completer.d.ts +10 -0
  59. package/dist/core/path-completer.d.ts.map +1 -0
  60. package/dist/core/path-completer.js +227 -0
  61. package/dist/core/path-completer.js.map +1 -0
  62. package/dist/core/path-discovery.d.ts +8 -0
  63. package/dist/core/path-discovery.d.ts.map +1 -0
  64. package/dist/core/path-discovery.js +105 -0
  65. package/dist/core/path-discovery.js.map +1 -0
  66. package/dist/core/path-utils.d.ts +9 -0
  67. package/dist/core/path-utils.d.ts.map +1 -0
  68. package/dist/core/path-utils.js +121 -0
  69. package/dist/core/path-utils.js.map +1 -0
  70. package/dist/core/path.d.ts +148 -0
  71. package/dist/core/path.d.ts.map +1 -0
  72. package/dist/core/path.js +674 -0
  73. package/dist/core/path.js.map +1 -0
  74. package/dist/core/primitives.d.ts +23 -0
  75. package/dist/core/primitives.d.ts.map +1 -0
  76. package/dist/core/primitives.js +54 -0
  77. package/dist/core/primitives.js.map +1 -0
  78. package/dist/core/read.d.ts +74 -0
  79. package/dist/core/read.d.ts.map +1 -0
  80. package/dist/core/read.js +562 -0
  81. package/dist/core/read.js.map +1 -0
  82. package/dist/core/schema.d.ts +139 -0
  83. package/dist/core/schema.d.ts.map +1 -0
  84. package/dist/core/schema.js +345 -0
  85. package/dist/core/schema.js.map +1 -0
  86. package/dist/core/search.d.ts +100 -0
  87. package/dist/core/search.d.ts.map +1 -0
  88. package/dist/core/search.js +248 -0
  89. package/dist/core/search.js.map +1 -0
  90. package/dist/core/sensitive.d.ts +6 -0
  91. package/dist/core/sensitive.d.ts.map +1 -0
  92. package/dist/core/sensitive.js +142 -0
  93. package/dist/core/sensitive.js.map +1 -0
  94. package/dist/core/store.d.ts +57 -0
  95. package/dist/core/store.d.ts.map +1 -0
  96. package/dist/core/store.js +162 -0
  97. package/dist/core/store.js.map +1 -0
  98. package/dist/core/util.d.ts +26 -0
  99. package/dist/core/util.d.ts.map +1 -0
  100. package/dist/core/util.js +66 -0
  101. package/dist/core/util.js.map +1 -0
  102. package/dist/core/watcher-registry.d.ts +68 -0
  103. package/dist/core/watcher-registry.d.ts.map +1 -0
  104. package/dist/core/watcher-registry.js +312 -0
  105. package/dist/core/watcher-registry.js.map +1 -0
  106. package/dist/http-policy.d.ts +121 -0
  107. package/dist/http-policy.d.ts.map +1 -0
  108. package/dist/http-policy.js +340 -0
  109. package/dist/http-policy.js.map +1 -0
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +77 -41
  113. package/dist/index.js.map +1 -0
  114. package/dist/instructions.d.ts +12 -0
  115. package/dist/instructions.d.ts.map +1 -0
  116. package/dist/instructions.js +71 -0
  117. package/dist/instructions.js.map +1 -0
  118. package/dist/prompts.d.ts +8 -6
  119. package/dist/prompts.d.ts.map +1 -0
  120. package/dist/prompts.js +74 -168
  121. package/dist/prompts.js.map +1 -0
  122. package/dist/resources.d.ts +73 -9
  123. package/dist/resources.d.ts.map +1 -0
  124. package/dist/resources.js +392 -163
  125. package/dist/resources.js.map +1 -0
  126. package/dist/server.d.ts +62 -1
  127. package/dist/server.d.ts.map +1 -0
  128. package/dist/server.js +139 -1
  129. package/dist/server.js.map +1 -0
  130. package/dist/tools/batch.d.ts +89 -0
  131. package/dist/tools/batch.d.ts.map +1 -0
  132. package/dist/tools/batch.js +157 -0
  133. package/dist/tools/batch.js.map +1 -0
  134. package/dist/tools/create.d.ts +2 -0
  135. package/dist/tools/create.d.ts.map +1 -0
  136. package/dist/tools/create.js +142 -0
  137. package/dist/tools/create.js.map +1 -0
  138. package/dist/tools/define.d.ts +110 -0
  139. package/dist/tools/define.d.ts.map +1 -0
  140. package/dist/tools/define.js +394 -0
  141. package/dist/tools/define.js.map +1 -0
  142. package/dist/tools/delete-file.d.ts +2 -4
  143. package/dist/tools/delete-file.d.ts.map +1 -0
  144. package/dist/tools/delete-file.js +330 -87
  145. package/dist/tools/delete-file.js.map +1 -0
  146. package/dist/tools/diff.d.ts +2 -0
  147. package/dist/tools/diff.d.ts.map +1 -0
  148. package/dist/tools/diff.js +94 -0
  149. package/dist/tools/diff.js.map +1 -0
  150. package/dist/tools/edit.d.ts +2 -0
  151. package/dist/tools/edit.d.ts.map +1 -0
  152. package/dist/tools/edit.js +442 -0
  153. package/dist/tools/edit.js.map +1 -0
  154. package/dist/tools/index.d.ts +26 -0
  155. package/dist/tools/index.d.ts.map +1 -0
  156. package/dist/tools/index.js +52 -0
  157. package/dist/tools/index.js.map +1 -0
  158. package/dist/tools/list.d.ts +2 -0
  159. package/dist/tools/list.d.ts.map +1 -0
  160. package/dist/tools/list.js +291 -0
  161. package/dist/tools/list.js.map +1 -0
  162. package/dist/tools/move.d.ts +2 -0
  163. package/dist/tools/move.d.ts.map +1 -0
  164. package/dist/tools/move.js +321 -0
  165. package/dist/tools/move.js.map +1 -0
  166. package/dist/tools/patch.d.ts +2 -0
  167. package/dist/tools/patch.d.ts.map +1 -0
  168. package/dist/tools/patch.js +155 -0
  169. package/dist/tools/patch.js.map +1 -0
  170. package/dist/tools/progress.d.ts +52 -0
  171. package/dist/tools/progress.d.ts.map +1 -0
  172. package/dist/tools/progress.js +172 -0
  173. package/dist/tools/progress.js.map +1 -0
  174. package/dist/tools/read.d.ts +2 -4
  175. package/dist/tools/read.d.ts.map +1 -0
  176. package/dist/tools/read.js +398 -152
  177. package/dist/tools/read.js.map +1 -0
  178. package/dist/tools/replace-in-files.d.ts +2 -4
  179. package/dist/tools/replace-in-files.d.ts.map +1 -0
  180. package/dist/tools/replace-in-files.js +435 -264
  181. package/dist/tools/replace-in-files.js.map +1 -0
  182. package/dist/tools/roots.d.ts +2 -4
  183. package/dist/tools/roots.d.ts.map +1 -0
  184. package/dist/tools/roots.js +29 -52
  185. package/dist/tools/roots.js.map +1 -0
  186. package/dist/tools/search-content.d.ts +2 -4
  187. package/dist/tools/search-content.d.ts.map +1 -0
  188. package/dist/tools/search-content.js +262 -228
  189. package/dist/tools/search-content.js.map +1 -0
  190. package/dist/tools/search-files.d.ts +2 -4
  191. package/dist/tools/search-files.d.ts.map +1 -0
  192. package/dist/tools/search-files.js +162 -161
  193. package/dist/tools/search-files.js.map +1 -0
  194. package/dist/tools/stat.d.ts +2 -4
  195. package/dist/tools/stat.d.ts.map +1 -0
  196. package/dist/tools/stat.js +202 -62
  197. package/dist/tools/stat.js.map +1 -0
  198. package/dist/transport/http.d.ts +5 -0
  199. package/dist/transport/http.d.ts.map +1 -0
  200. package/dist/transport/http.js +276 -0
  201. package/dist/transport/http.js.map +1 -0
  202. package/dist/transport/shared.d.ts +45 -0
  203. package/dist/transport/shared.d.ts.map +1 -0
  204. package/dist/transport/shared.js +65 -0
  205. package/dist/transport/shared.js.map +1 -0
  206. package/dist/transport/stdio.d.ts +32 -0
  207. package/dist/transport/stdio.d.ts.map +1 -0
  208. package/dist/transport/stdio.js +279 -0
  209. package/dist/transport/stdio.js.map +1 -0
  210. package/dist/transport.d.ts +5 -0
  211. package/dist/transport.d.ts.map +1 -0
  212. package/dist/transport.js +4 -0
  213. package/dist/transport.js.map +1 -0
  214. package/package.json +37 -46
  215. package/dist/assets/logo.svg +0 -35
  216. package/dist/completions.d.ts +0 -2
  217. package/dist/completions.js +0 -572
  218. package/dist/config.d.ts +0 -119
  219. package/dist/config.js +0 -31
  220. package/dist/lib/abort.d.ts +0 -7
  221. package/dist/lib/abort.js +0 -81
  222. package/dist/lib/constants.d.ts +0 -42
  223. package/dist/lib/constants.js +0 -313
  224. package/dist/lib/errors.d.ts +0 -28
  225. package/dist/lib/errors.js +0 -301
  226. package/dist/lib/file-operations/core.d.ts +0 -53
  227. package/dist/lib/file-operations/core.js +0 -144
  228. package/dist/lib/file-operations/metadata.d.ts +0 -77
  229. package/dist/lib/file-operations/metadata.js +0 -878
  230. package/dist/lib/file-operations/search.d.ts +0 -46
  231. package/dist/lib/file-operations/search.js +0 -1194
  232. package/dist/lib/file-operations/traversal.d.ts +0 -40
  233. package/dist/lib/file-operations/traversal.js +0 -310
  234. package/dist/lib/fs-helpers.d.ts +0 -46
  235. package/dist/lib/fs-helpers.js +0 -606
  236. package/dist/lib/globs.d.ts +0 -2
  237. package/dist/lib/globs.js +0 -19
  238. package/dist/lib/logger.d.ts +0 -27
  239. package/dist/lib/logger.js +0 -91
  240. package/dist/lib/observability.d.ts +0 -33
  241. package/dist/lib/observability.js +0 -373
  242. package/dist/lib/paths.d.ts +0 -35
  243. package/dist/lib/paths.js +0 -634
  244. package/dist/lib/resource-store.d.ts +0 -28
  245. package/dist/lib/resource-store.js +0 -195
  246. package/dist/lib/utils.d.ts +0 -7
  247. package/dist/lib/utils.js +0 -37
  248. package/dist/lib/zod-codecs.d.ts +0 -2
  249. package/dist/lib/zod-codecs.js +0 -18
  250. package/dist/pkg-info.d.ts +0 -7
  251. package/dist/pkg-info.js +0 -9
  252. package/dist/resources/generated-instructions.d.ts +0 -1
  253. package/dist/resources/generated-instructions.js +0 -105
  254. package/dist/resources/tool-catalog.d.ts +0 -2
  255. package/dist/resources/tool-catalog.js +0 -78
  256. package/dist/resources/tool-info.d.ts +0 -9
  257. package/dist/resources/tool-info.js +0 -206
  258. package/dist/resources/workflows.d.ts +0 -1
  259. package/dist/resources/workflows.js +0 -72
  260. package/dist/schemas.d.ts +0 -505
  261. package/dist/schemas.js +0 -676
  262. package/dist/server/bootstrap.d.ts +0 -6
  263. package/dist/server/bootstrap.js +0 -563
  264. package/dist/server/event-store.d.ts +0 -18
  265. package/dist/server/event-store.js +0 -71
  266. package/dist/server/roots-manager.d.ts +0 -28
  267. package/dist/server/roots-manager.js +0 -227
  268. package/dist/server/task-store.d.ts +0 -10
  269. package/dist/server/task-store.js +0 -91
  270. package/dist/tools/apply-patch.d.ts +0 -4
  271. package/dist/tools/apply-patch.js +0 -235
  272. package/dist/tools/calculate-hash.d.ts +0 -4
  273. package/dist/tools/calculate-hash.js +0 -187
  274. package/dist/tools/contract.d.ts +0 -50
  275. package/dist/tools/contract.js +0 -1
  276. package/dist/tools/create-directory.d.ts +0 -4
  277. package/dist/tools/create-directory.js +0 -68
  278. package/dist/tools/diff-files.d.ts +0 -4
  279. package/dist/tools/diff-files.js +0 -136
  280. package/dist/tools/edit-file.d.ts +0 -4
  281. package/dist/tools/edit-file.js +0 -256
  282. package/dist/tools/icons.d.ts +0 -15
  283. package/dist/tools/icons.js +0 -24
  284. package/dist/tools/list-directory.d.ts +0 -4
  285. package/dist/tools/list-directory.js +0 -218
  286. package/dist/tools/move-file.d.ts +0 -4
  287. package/dist/tools/move-file.js +0 -178
  288. package/dist/tools/read-multiple.d.ts +0 -4
  289. package/dist/tools/read-multiple.js +0 -207
  290. package/dist/tools/shared.d.ts +0 -172
  291. package/dist/tools/shared.js +0 -599
  292. package/dist/tools/stat-many.d.ts +0 -4
  293. package/dist/tools/stat-many.js +0 -104
  294. package/dist/tools/task-support.d.ts +0 -29
  295. package/dist/tools/task-support.js +0 -472
  296. package/dist/tools/tree.d.ts +0 -4
  297. package/dist/tools/tree.js +0 -102
  298. package/dist/tools/write-file.d.ts +0 -4
  299. package/dist/tools/write-file.js +0 -60
  300. package/dist/tools.d.ts +0 -5
  301. package/dist/tools.js +0 -54
@@ -1,606 +0,0 @@
1
- var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
- if (value !== null && value !== void 0) {
3
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
- var dispose, inner;
5
- if (async) {
6
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
- dispose = value[Symbol.asyncDispose];
8
- }
9
- if (dispose === void 0) {
10
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
- dispose = value[Symbol.dispose];
12
- if (async) inner = dispose;
13
- }
14
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
- env.stack.push({ value: value, dispose: dispose, async: async });
17
- }
18
- else if (async) {
19
- env.stack.push({ async: true });
20
- }
21
- return value;
22
- };
23
- var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
- return function (env) {
25
- function fail(e) {
26
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
- env.hasError = true;
28
- }
29
- var r, s = 0;
30
- function next() {
31
- while (r = env.stack.pop()) {
32
- try {
33
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
- if (r.dispose) {
35
- var result = r.dispose.call(r.value);
36
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
- }
38
- else s |= 1;
39
- }
40
- catch (e) {
41
- fail(e);
42
- }
43
- }
44
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
- if (env.hasError) throw env.error;
46
- }
47
- return next();
48
- };
49
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
- var e = new Error(message);
51
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
- });
53
- import { isUtf8 } from 'node:buffer';
54
- import { createHash, randomUUID } from 'node:crypto';
55
- import { createReadStream } from 'node:fs';
56
- import { open, rename, stat, unlink, writeFile, } from 'node:fs/promises';
57
- import { extname } from 'node:path';
58
- import { pipeline } from 'node:stream/promises';
59
- import { assertNotAborted, withAbort } from './abort.js';
60
- import { BINARY_CHECK_BUFFER_SIZE, KNOWN_BINARY_EXTENSIONS, MAX_TEXT_FILE_SIZE, PARALLEL_CONCURRENCY, } from './constants.js';
61
- import { ErrorCode, McpError, normalizeUnknownError } from './errors.js';
62
- import { assertAllowedFileAccess, validateExistingPath } from './paths.js';
63
- const READ_ONLY_FILE_FLAG = 'r';
64
- function assertPositiveSafeIntegerOption(name, value, message) {
65
- if (value === undefined)
66
- return;
67
- if (typeof value !== 'number' ||
68
- !Number.isFinite(value) ||
69
- !Number.isSafeInteger(value) ||
70
- value < 1) {
71
- throw new McpError(ErrorCode.INVALID_INPUT, message ?? `${name} must be a positive integer`);
72
- }
73
- }
74
- function normalizeConcurrency(concurrency) {
75
- assertPositiveSafeIntegerOption('concurrency', concurrency);
76
- return concurrency;
77
- }
78
- function createParallelAbortError() {
79
- return new DOMException('Operation aborted', 'AbortError');
80
- }
81
- export async function processInParallel(items, processor, concurrency = PARALLEL_CONCURRENCY, signal) {
82
- const itemCount = items.length;
83
- if (itemCount === 0)
84
- return { results: [], errors: [] };
85
- const effectiveConcurrency = normalizeConcurrency(concurrency);
86
- // Pre-allocate slots by index to guarantee input-order output.
87
- const resultSlots = new Array(itemCount);
88
- const errors = [];
89
- if (signal?.aborted)
90
- throw createParallelAbortError();
91
- let nextIndex = 0;
92
- const next = async () => {
93
- while (nextIndex < itemCount) {
94
- if (signal?.aborted)
95
- throw createParallelAbortError();
96
- const index = nextIndex;
97
- nextIndex += 1;
98
- const item = items[index];
99
- try {
100
- const result = await processor(item);
101
- if (signal?.aborted)
102
- throw createParallelAbortError();
103
- resultSlots[index] = result;
104
- }
105
- catch (error) {
106
- if (signal?.aborted)
107
- throw createParallelAbortError();
108
- errors.push({
109
- index,
110
- error: normalizeUnknownError(error),
111
- });
112
- }
113
- }
114
- };
115
- const workerCount = Math.min(itemCount, effectiveConcurrency);
116
- const workers = new Array(workerCount);
117
- for (let index = 0; index < workerCount; index += 1) {
118
- workers[index] = next();
119
- }
120
- await Promise.allSettled(workers);
121
- if (signal?.aborted)
122
- throw createParallelAbortError();
123
- const results = [];
124
- for (const slot of resultSlots) {
125
- if (slot !== undefined) {
126
- results.push(slot);
127
- }
128
- }
129
- return { results, errors };
130
- }
131
- export function getFileType(stats) {
132
- if (stats.isFile())
133
- return 'file';
134
- if (stats.isDirectory())
135
- return 'directory';
136
- if (stats.isSymbolicLink())
137
- return 'symlink';
138
- return 'other';
139
- }
140
- export function isHidden(name) {
141
- return name.startsWith('.');
142
- }
143
- function hasKnownBinaryExtension(filePath) {
144
- const ext = extname(filePath).toLowerCase();
145
- return KNOWN_BINARY_EXTENSIONS.has(ext);
146
- }
147
- async function openReadableFileHandle(filePath, signal) {
148
- return withAbort(open(filePath, READ_ONLY_FILE_FLAG), signal);
149
- }
150
- async function readProbe(handle, signal) {
151
- const buffer = Buffer.alloc(BINARY_CHECK_BUFFER_SIZE);
152
- const { bytesRead } = await withAbort(handle.read(buffer, 0, BINARY_CHECK_BUFFER_SIZE, 0), signal);
153
- if (bytesRead === 0) {
154
- return Buffer.alloc(0);
155
- }
156
- return buffer.subarray(0, bytesRead);
157
- }
158
- function hasUtf16Bom(slice) {
159
- return (slice.length >= 2 &&
160
- ((slice[0] === 0xff && slice[1] === 0xfe) ||
161
- (slice[0] === 0xfe && slice[1] === 0xff)));
162
- }
163
- export async function isProbablyBinary(filePath, existingHandle, signal) {
164
- const env_1 = { stack: [], error: void 0, hasError: false };
165
- try {
166
- if (hasKnownBinaryExtension(filePath)) {
167
- return true;
168
- }
169
- if (existingHandle) {
170
- const slice = await readProbe(existingHandle, signal);
171
- return isBinarySlice(slice);
172
- }
173
- const effectivePath = await validateExistingPath(filePath, signal);
174
- const handle = __addDisposableResource(env_1, await openReadableFileHandle(effectivePath, signal), true);
175
- const slice = await readProbe(handle, signal);
176
- return isBinarySlice(slice);
177
- }
178
- catch (e_1) {
179
- env_1.error = e_1;
180
- env_1.hasError = true;
181
- }
182
- finally {
183
- const result_1 = __disposeResources(env_1);
184
- if (result_1)
185
- await result_1;
186
- }
187
- }
188
- function isBinarySlice(slice) {
189
- if (slice.length === 0)
190
- return false;
191
- if (hasUtf16Bom(slice))
192
- return false;
193
- if (slice.includes(0))
194
- return true;
195
- return !isUtf8(slice);
196
- }
197
- export async function calculateFileContentHash(filePath, signal) {
198
- const hasher = createHash('sha256');
199
- await pipeline(createReadStream(filePath, { signal, highWaterMark: STREAM_CHUNK_SIZE }), hasher, { signal });
200
- return hasher.digest('hex');
201
- }
202
- function validateReadOptions(options) {
203
- const hasHead = options.head !== undefined;
204
- const hasTail = options.tail !== undefined;
205
- const hasStart = options.startLine !== undefined;
206
- const hasEnd = options.endLine !== undefined;
207
- assertPositiveSafeIntegerOption('maxSize', options.maxSize, 'maxSize must be at least 1');
208
- assertPositiveSafeIntegerOption('head', options.head, 'head must be at least 1');
209
- assertPositiveSafeIntegerOption('tail', options.tail, 'tail must be at least 1');
210
- assertPositiveSafeIntegerOption('startLine', options.startLine, 'startLine must be at least 1');
211
- assertPositiveSafeIntegerOption('endLine', options.endLine, 'endLine must be at least 1');
212
- if (hasHead && (hasStart || hasEnd)) {
213
- throw new McpError(ErrorCode.INVALID_INPUT, 'head cannot be used together with startLine/endLine');
214
- }
215
- if (hasTail && (hasHead || hasStart || hasEnd)) {
216
- throw new McpError(ErrorCode.INVALID_INPUT, 'tail cannot be used together with head/startLine/endLine');
217
- }
218
- {
219
- const effectiveStart = options.startLine ?? 1;
220
- if (options.endLine !== undefined && options.endLine < effectiveStart) {
221
- throw new McpError(ErrorCode.INVALID_INPUT, 'endLine must be greater than or equal to startLine (default: 1)');
222
- }
223
- }
224
- }
225
- function normalizeOptions(options) {
226
- validateReadOptions(options);
227
- const normalized = {
228
- encoding: options.encoding ?? 'utf-8',
229
- maxSize: Math.min(options.maxSize ?? MAX_TEXT_FILE_SIZE, MAX_TEXT_FILE_SIZE),
230
- skipBinary: options.skipBinary ?? false,
231
- };
232
- if (options.head !== undefined) {
233
- normalized.head = options.head;
234
- }
235
- if (options.tail !== undefined) {
236
- normalized.tail = options.tail;
237
- }
238
- if (options.endLine !== undefined) {
239
- normalized.startLine = options.startLine ?? 1;
240
- normalized.endLine = options.endLine;
241
- }
242
- else if (options.startLine !== undefined) {
243
- normalized.startLine = options.startLine;
244
- }
245
- if (options.signal) {
246
- normalized.signal = options.signal;
247
- }
248
- return normalized;
249
- }
250
- function prepareReadOptions(options) {
251
- const normalized = normalizeOptions(options);
252
- assertNotAborted(normalized.signal);
253
- return normalized;
254
- }
255
- function buildReadContentOptions(normalized) {
256
- const readOptions = {
257
- encoding: normalized.encoding,
258
- maxSize: normalized.maxSize,
259
- };
260
- if (normalized.signal) {
261
- readOptions.signal = normalized.signal;
262
- }
263
- return readOptions;
264
- }
265
- function resolveReadMode(options) {
266
- if (options.head !== undefined)
267
- return 'head';
268
- if (options.tail !== undefined)
269
- return 'tail';
270
- if (options.startLine !== undefined || options.endLine !== undefined)
271
- return 'range';
272
- return 'full';
273
- }
274
- const STREAM_CHUNK_SIZE = 64 * 1024;
275
- function createTooLargeError(bytesRead, maxSize, requestedPath) {
276
- return new McpError(ErrorCode.TOO_LARGE, `File exceeds size limit (${bytesRead} > ${maxSize} bytes)`, requestedPath, { size: bytesRead, maxSize });
277
- }
278
- async function readFileBufferWithLimit(handle, maxSize, requestedPath, signal) {
279
- const stream = handle.createReadStream({
280
- start: 0,
281
- highWaterMark: STREAM_CHUNK_SIZE,
282
- autoClose: false,
283
- emitClose: false,
284
- signal,
285
- });
286
- const chunks = [];
287
- let totalSize = 0;
288
- try {
289
- for await (const chunk of stream) {
290
- const buffer = Buffer.isBuffer(chunk)
291
- ? chunk
292
- : Buffer.from(chunk);
293
- totalSize += buffer.length;
294
- if (totalSize > maxSize) {
295
- stream.destroy();
296
- throw createTooLargeError(totalSize, maxSize, requestedPath);
297
- }
298
- chunks.push(buffer);
299
- }
300
- }
301
- finally {
302
- if (!stream.destroyed) {
303
- stream.destroy();
304
- }
305
- }
306
- return Buffer.concat(chunks, totalSize);
307
- }
308
- function countLines(content) {
309
- if (content.length === 0)
310
- return 0;
311
- let count = 1;
312
- for (let i = 0; i < content.length; i++) {
313
- if (content.charCodeAt(i) === 10)
314
- count++;
315
- }
316
- return count;
317
- }
318
- async function readHeadContent(handle, head, options) {
319
- assertNotAborted(options.signal);
320
- const lines = [];
321
- let estimatedBytes = 0;
322
- const newlineBytes = Buffer.byteLength('\n', options.encoding);
323
- const iterator = handle
324
- .readLines({ encoding: options.encoding, signal: options.signal })[Symbol.asyncIterator]();
325
- let hasMoreLines = false;
326
- let next = await iterator.next();
327
- try {
328
- while (!next.done) {
329
- const line = next.value;
330
- lines.push(line);
331
- estimatedBytes +=
332
- Buffer.byteLength(line, options.encoding) + newlineBytes;
333
- if (estimatedBytes >= options.maxSize) {
334
- hasMoreLines = true;
335
- break;
336
- }
337
- if (lines.length === head) {
338
- const peek = await iterator.next();
339
- hasMoreLines = !peek.done;
340
- break;
341
- }
342
- next = await iterator.next();
343
- }
344
- }
345
- finally {
346
- await iterator.return?.();
347
- }
348
- const content = lines.join('\n');
349
- const linesRead = lines.length;
350
- return {
351
- content,
352
- truncated: hasMoreLines,
353
- linesRead,
354
- hasMoreLines,
355
- };
356
- }
357
- async function readRangeContent(handle, startLine, endLine, options) {
358
- assertNotAborted(options.signal);
359
- const lines = [];
360
- let lineNumber = 0;
361
- let estimatedBytes = 0;
362
- const hasEndLine = endLine !== undefined;
363
- let stoppedByLimit = false;
364
- let reachedEof = false;
365
- const newlineBytes = Buffer.byteLength('\n', options.encoding);
366
- const iterator = handle
367
- .readLines({ encoding: options.encoding, signal: options.signal })[Symbol.asyncIterator]();
368
- let hasMoreLines = false;
369
- const stopAt = endLine ?? Number.POSITIVE_INFINITY;
370
- let stoppedEarly = false;
371
- let next = await iterator.next();
372
- try {
373
- while (!next.done) {
374
- const line = next.value;
375
- lineNumber++;
376
- if (lineNumber < startLine) {
377
- next = await iterator.next();
378
- continue;
379
- }
380
- if (lineNumber > stopAt) {
381
- hasMoreLines = true;
382
- stoppedEarly = true;
383
- break;
384
- }
385
- lines.push(line);
386
- estimatedBytes +=
387
- Buffer.byteLength(line, options.encoding) + newlineBytes;
388
- if (estimatedBytes >= options.maxSize) {
389
- stoppedByLimit = true;
390
- stoppedEarly = true;
391
- break;
392
- }
393
- if (hasEndLine && lineNumber === stopAt) {
394
- const peek = await iterator.next();
395
- hasMoreLines = !peek.done;
396
- reachedEof = Boolean(peek.done);
397
- stoppedEarly = true;
398
- break;
399
- }
400
- next = await iterator.next();
401
- }
402
- }
403
- finally {
404
- await iterator.return?.();
405
- }
406
- if (!stoppedEarly) {
407
- reachedEof = true;
408
- }
409
- const content = lines.join('\n');
410
- const linesRead = countLines(content);
411
- const effectiveHasMoreLines = hasEndLine
412
- ? hasMoreLines || (stoppedByLimit && !reachedEof)
413
- : stoppedByLimit && !reachedEof;
414
- return {
415
- content,
416
- truncated: stoppedByLimit || effectiveHasMoreLines,
417
- linesRead,
418
- hasMoreLines: effectiveHasMoreLines,
419
- };
420
- }
421
- async function readTailContent(handle, tail, options) {
422
- assertNotAborted(options.signal);
423
- const ring = new Array(tail);
424
- let totalLines = 0;
425
- let head = 0;
426
- let size = 0;
427
- for await (const line of handle.readLines({
428
- encoding: options.encoding,
429
- signal: options.signal,
430
- })) {
431
- ring[head] = line;
432
- head = (head + 1) % tail;
433
- if (size < tail)
434
- size++;
435
- totalLines++;
436
- }
437
- const lines = new Array(size);
438
- const start = size < tail ? 0 : head;
439
- for (let i = 0; i < size; i++) {
440
- lines[i] = ring[(start + i) % tail] ?? '';
441
- }
442
- const content = lines.join('\n');
443
- const linesRead = countLines(content);
444
- const hasMoreLines = totalLines > tail;
445
- return {
446
- content,
447
- truncated: hasMoreLines,
448
- linesRead,
449
- hasMoreLines,
450
- };
451
- }
452
- async function readFullContent(handle, encoding, maxSize, requestedPath, signal) {
453
- const buffer = await readFileBufferWithLimit(handle, maxSize, requestedPath, signal);
454
- const content = buffer.toString(encoding);
455
- return { content, totalLines: countLines(content) };
456
- }
457
- async function assertNotBinary(validPath, filePath, normalized) {
458
- assertNotAborted(normalized.signal);
459
- const isBinary = await isProbablyBinary(validPath, undefined, normalized.signal);
460
- if (!isBinary)
461
- return;
462
- throw new McpError(ErrorCode.INVALID_INPUT, 'Binary file detected.', filePath);
463
- }
464
- function assertSizeWithinLimit(size, maxSize, filePath) {
465
- if (size <= maxSize)
466
- return;
467
- throw new McpError(ErrorCode.TOO_LARGE, `File too large (${size} > ${maxSize} bytes). Use head to preview.`, filePath, { size, maxSize });
468
- }
469
- function requireReadOption(normalized, key, filePath) {
470
- const value = normalized[key];
471
- if (value !== undefined) {
472
- return value;
473
- }
474
- throw new McpError(ErrorCode.INVALID_INPUT, `Missing ${key} option`, filePath);
475
- }
476
- async function executeHeadRead(context) {
477
- const head = requireReadOption(context.normalized, 'head', context.filePath);
478
- const readOptions = buildReadContentOptions(context.normalized);
479
- const { content, truncated, linesRead, hasMoreLines } = await readHeadContent(context.handle, head, readOptions);
480
- return {
481
- path: context.validPath,
482
- content,
483
- truncated,
484
- readMode: 'head',
485
- head,
486
- linesRead,
487
- hasMoreLines,
488
- };
489
- }
490
- async function executeRangeRead(context) {
491
- const startLine = requireReadOption(context.normalized, 'startLine', context.filePath);
492
- const { endLine } = context.normalized;
493
- const readOptions = buildReadContentOptions(context.normalized);
494
- const { content, truncated, linesRead, hasMoreLines } = await readRangeContent(context.handle, startLine, endLine, readOptions);
495
- return {
496
- path: context.validPath,
497
- content,
498
- truncated,
499
- readMode: 'range',
500
- startLine,
501
- ...(endLine !== undefined ? { endLine } : {}),
502
- linesRead,
503
- hasMoreLines,
504
- };
505
- }
506
- async function executeFullRead(context) {
507
- assertSizeWithinLimit(context.stats.size, context.normalized.maxSize, context.filePath);
508
- const { content, totalLines } = await readFullContent(context.handle, context.normalized.encoding, context.normalized.maxSize, context.filePath, context.normalized.signal);
509
- return {
510
- path: context.validPath,
511
- content,
512
- truncated: false,
513
- totalLines,
514
- readMode: 'full',
515
- linesRead: totalLines,
516
- hasMoreLines: false,
517
- };
518
- }
519
- async function executeTailRead(context) {
520
- const tail = requireReadOption(context.normalized, 'tail', context.filePath);
521
- const readOptions = buildReadContentOptions(context.normalized);
522
- const { content, truncated, linesRead, hasMoreLines } = await readTailContent(context.handle, tail, readOptions);
523
- return {
524
- path: context.validPath,
525
- content,
526
- truncated,
527
- readMode: 'tail',
528
- tail,
529
- linesRead,
530
- hasMoreLines,
531
- };
532
- }
533
- const READ_MODE_HANDLERS = {
534
- head: executeHeadRead,
535
- range: executeRangeRead,
536
- full: executeFullRead,
537
- tail: executeTailRead,
538
- };
539
- async function readByMode(context) {
540
- const mode = resolveReadMode(context.normalized);
541
- return READ_MODE_HANDLERS[mode](context);
542
- }
543
- function assertFileStats(filePath, stats) {
544
- if (!stats.isFile()) {
545
- throw new McpError(ErrorCode.NOT_FILE, 'Not a regular file', filePath);
546
- }
547
- }
548
- async function readFileWithStatsInternal(filePath, validPath, stats, normalized) {
549
- const env_2 = { stack: [], error: void 0, hasError: false };
550
- try {
551
- assertNotAborted(normalized.signal);
552
- assertAllowedFileAccess(filePath, validPath);
553
- assertFileStats(filePath, stats);
554
- if (normalized.skipBinary) {
555
- await assertNotBinary(validPath, filePath, normalized);
556
- }
557
- assertNotAborted(normalized.signal);
558
- const handle = __addDisposableResource(env_2, await openReadableFileHandle(validPath, normalized.signal), true);
559
- return await readByMode({
560
- handle,
561
- validPath,
562
- filePath,
563
- stats,
564
- normalized,
565
- });
566
- }
567
- catch (e_2) {
568
- env_2.error = e_2;
569
- env_2.hasError = true;
570
- }
571
- finally {
572
- const result_2 = __disposeResources(env_2);
573
- if (result_2)
574
- await result_2;
575
- }
576
- }
577
- export async function readFileWithStats(filePath, validPath, stats, options = {}) {
578
- const normalized = prepareReadOptions(options);
579
- return readFileWithStatsInternal(filePath, validPath, stats, normalized);
580
- }
581
- export async function readFile(filePath, options = {}) {
582
- const normalized = prepareReadOptions(options);
583
- const validPath = await validateExistingPath(filePath, normalized.signal);
584
- assertNotAborted(normalized.signal);
585
- const stats = await withAbort(stat(validPath), normalized.signal);
586
- return readFileWithStatsInternal(filePath, validPath, stats, normalized);
587
- }
588
- export async function atomicWriteFile(filePath, content, options = {}) {
589
- const { encoding = 'utf-8', signal } = options;
590
- const tempPath = `${filePath}.${randomUUID()}.tmp`;
591
- try {
592
- assertNotAborted(signal);
593
- await writeFile(tempPath, content, { encoding, signal });
594
- await withAbort(rename(tempPath, filePath), signal);
595
- }
596
- catch (error) {
597
- // Attempt cleanup on error, but don't overwrite the original error
598
- try {
599
- await unlink(tempPath).catch(() => { });
600
- }
601
- catch {
602
- // Ignore cleanup errors
603
- }
604
- throw error;
605
- }
606
- }
@@ -1,2 +0,0 @@
1
- export declare function isSafeGlobPattern(value: string): boolean;
2
- export declare function assertSafeGlobPattern(value: string, message?: string): void;
package/dist/lib/globs.js DELETED
@@ -1,19 +0,0 @@
1
- import { ErrorCode, McpError } from './errors.js';
2
- const ABSOLUTE_GLOB_RE = /^([/\\]|[A-Za-z]:[/\\]|\\\\)/u;
3
- const PARENT_SEGMENT_RE = /[\\/]\.\.(?:[/\\]|$)/u;
4
- export function isSafeGlobPattern(value) {
5
- if (value.length === 0)
6
- return false;
7
- if (value.includes('**/**/**'))
8
- return false;
9
- if (ABSOLUTE_GLOB_RE.test(value))
10
- return false;
11
- if (value.startsWith('..') || PARENT_SEGMENT_RE.test(value))
12
- return false;
13
- return true;
14
- }
15
- export function assertSafeGlobPattern(value, message = 'Invalid glob or unsafe path (absolute/.. forbidden)') {
16
- if (!isSafeGlobPattern(value)) {
17
- throw new McpError(ErrorCode.INVALID_PATTERN, message);
18
- }
19
- }
@@ -1,27 +0,0 @@
1
- import type { LoggingLevel, McpServer } from '@modelcontextprotocol/server';
2
- import { AsyncLocalStorage } from 'node:async_hooks';
3
- interface SessionContextData {
4
- sessionId?: string;
5
- }
6
- export declare const SessionContext: AsyncLocalStorage<SessionContextData>;
7
- export interface LogEvent {
8
- level: LoggingLevel;
9
- message: string;
10
- data?: unknown;
11
- sessionId?: string;
12
- }
13
- export interface LoggingState {
14
- minimumLevel: LoggingLevel;
15
- }
16
- export declare function createLoggingState(minimumLevel?: LoggingLevel): LoggingState;
17
- export declare function logToMcp(server: McpServer | undefined, level: LoggingLevel, data: string, minLevel?: LoggingLevel): void;
18
- export declare const Logger: {
19
- emit(level: LoggingLevel, message: string, data?: unknown): void;
20
- debug(message: string, data?: unknown): void;
21
- info(message: string, data?: unknown): void;
22
- notice(message: string, data?: unknown): void;
23
- warn(message: string, data?: unknown): void;
24
- error(message: string, data?: unknown): void;
25
- critical(message: string, data?: unknown): void;
26
- };
27
- export {};