@ssmeo/mcp-local-rag 0.18.6

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 (247) hide show
  1. package/LICENSE +21 -0
  2. package/README.de.md +441 -0
  3. package/README.es.md +441 -0
  4. package/README.fr.md +441 -0
  5. package/README.md +530 -0
  6. package/README.pt-BR.md +441 -0
  7. package/README.zh-CN.md +441 -0
  8. package/dist/bin/install-skills.d.ts +19 -0
  9. package/dist/bin/install-skills.d.ts.map +1 -0
  10. package/dist/bin/install-skills.js +218 -0
  11. package/dist/bin/install-skills.js.map +1 -0
  12. package/dist/chunker/index.d.ts +24 -0
  13. package/dist/chunker/index.d.ts.map +1 -0
  14. package/dist/chunker/index.js +2 -0
  15. package/dist/chunker/index.js.map +1 -0
  16. package/dist/chunker/semantic-chunker.d.ts +96 -0
  17. package/dist/chunker/semantic-chunker.d.ts.map +1 -0
  18. package/dist/chunker/semantic-chunker.js +362 -0
  19. package/dist/chunker/semantic-chunker.js.map +1 -0
  20. package/dist/chunker/sentence-splitter.d.ts +32 -0
  21. package/dist/chunker/sentence-splitter.d.ts.map +1 -0
  22. package/dist/chunker/sentence-splitter.js +231 -0
  23. package/dist/chunker/sentence-splitter.js.map +1 -0
  24. package/dist/chunker/token-containment.d.ts +39 -0
  25. package/dist/chunker/token-containment.d.ts.map +1 -0
  26. package/dist/chunker/token-containment.js +83 -0
  27. package/dist/chunker/token-containment.js.map +1 -0
  28. package/dist/cli/common.d.ts +34 -0
  29. package/dist/cli/common.d.ts.map +1 -0
  30. package/dist/cli/common.js +121 -0
  31. package/dist/cli/common.js.map +1 -0
  32. package/dist/cli/delete.d.ts +3 -0
  33. package/dist/cli/delete.d.ts.map +1 -0
  34. package/dist/cli/delete.js +169 -0
  35. package/dist/cli/delete.js.map +1 -0
  36. package/dist/cli/file-collection.d.ts +2 -0
  37. package/dist/cli/file-collection.d.ts.map +1 -0
  38. package/dist/cli/file-collection.js +53 -0
  39. package/dist/cli/file-collection.js.map +1 -0
  40. package/dist/cli/ingest.d.ts +69 -0
  41. package/dist/cli/ingest.d.ts.map +1 -0
  42. package/dist/cli/ingest.js +323 -0
  43. package/dist/cli/ingest.js.map +1 -0
  44. package/dist/cli/list.d.ts +27 -0
  45. package/dist/cli/list.d.ts.map +1 -0
  46. package/dist/cli/list.js +207 -0
  47. package/dist/cli/list.js.map +1 -0
  48. package/dist/cli/options.d.ts +89 -0
  49. package/dist/cli/options.d.ts.map +1 -0
  50. package/dist/cli/options.js +244 -0
  51. package/dist/cli/options.js.map +1 -0
  52. package/dist/cli/query.d.ts +17 -0
  53. package/dist/cli/query.d.ts.map +1 -0
  54. package/dist/cli/query.js +194 -0
  55. package/dist/cli/query.js.map +1 -0
  56. package/dist/cli/read-neighbors.d.ts +3 -0
  57. package/dist/cli/read-neighbors.d.ts.map +1 -0
  58. package/dist/cli/read-neighbors.js +192 -0
  59. package/dist/cli/read-neighbors.js.map +1 -0
  60. package/dist/cli/status.d.ts +6 -0
  61. package/dist/cli/status.d.ts.map +1 -0
  62. package/dist/cli/status.js +78 -0
  63. package/dist/cli/status.js.map +1 -0
  64. package/dist/cli/sync.d.ts +6 -0
  65. package/dist/cli/sync.d.ts.map +1 -0
  66. package/dist/cli/sync.js +271 -0
  67. package/dist/cli/sync.js.map +1 -0
  68. package/dist/cli-main.d.ts +9 -0
  69. package/dist/cli-main.d.ts.map +1 -0
  70. package/dist/cli-main.js +60 -0
  71. package/dist/cli-main.js.map +1 -0
  72. package/dist/embedder/index.d.ts +143 -0
  73. package/dist/embedder/index.d.ts.map +1 -0
  74. package/dist/embedder/index.js +429 -0
  75. package/dist/embedder/index.js.map +1 -0
  76. package/dist/embedder/remote.d.ts +51 -0
  77. package/dist/embedder/remote.d.ts.map +1 -0
  78. package/dist/embedder/remote.js +182 -0
  79. package/dist/embedder/remote.js.map +1 -0
  80. package/dist/features/list.d.ts +37 -0
  81. package/dist/features/list.d.ts.map +1 -0
  82. package/dist/features/list.js +41 -0
  83. package/dist/features/list.js.map +1 -0
  84. package/dist/features/sync.d.ts +219 -0
  85. package/dist/features/sync.d.ts.map +1 -0
  86. package/dist/features/sync.js +461 -0
  87. package/dist/features/sync.js.map +1 -0
  88. package/dist/index.d.ts +3 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.js +56 -0
  91. package/dist/index.js.map +1 -0
  92. package/dist/ingest/compute.d.ts +63 -0
  93. package/dist/ingest/compute.d.ts.map +1 -0
  94. package/dist/ingest/compute.js +161 -0
  95. package/dist/ingest/compute.js.map +1 -0
  96. package/dist/ingest/file.d.ts +40 -0
  97. package/dist/ingest/file.d.ts.map +1 -0
  98. package/dist/ingest/file.js +74 -0
  99. package/dist/ingest/file.js.map +1 -0
  100. package/dist/ingest/visual.d.ts +52 -0
  101. package/dist/ingest/visual.d.ts.map +1 -0
  102. package/dist/ingest/visual.js +294 -0
  103. package/dist/ingest/visual.js.map +1 -0
  104. package/dist/parser/docx-parser.d.ts +12 -0
  105. package/dist/parser/docx-parser.d.ts.map +1 -0
  106. package/dist/parser/docx-parser.js +375 -0
  107. package/dist/parser/docx-parser.js.map +1 -0
  108. package/dist/parser/html-parser.d.ts +16 -0
  109. package/dist/parser/html-parser.d.ts.map +1 -0
  110. package/dist/parser/html-parser.js +119 -0
  111. package/dist/parser/html-parser.js.map +1 -0
  112. package/dist/parser/index.d.ts +125 -0
  113. package/dist/parser/index.d.ts.map +1 -0
  114. package/dist/parser/index.js +364 -0
  115. package/dist/parser/index.js.map +1 -0
  116. package/dist/parser/pdf-extract.d.ts +49 -0
  117. package/dist/parser/pdf-extract.d.ts.map +1 -0
  118. package/dist/parser/pdf-extract.js +114 -0
  119. package/dist/parser/pdf-extract.js.map +1 -0
  120. package/dist/parser/pdf-filter.d.ts +91 -0
  121. package/dist/parser/pdf-filter.d.ts.map +1 -0
  122. package/dist/parser/pdf-filter.js +522 -0
  123. package/dist/parser/pdf-filter.js.map +1 -0
  124. package/dist/parser/title-extractor.d.ts +28 -0
  125. package/dist/parser/title-extractor.d.ts.map +1 -0
  126. package/dist/parser/title-extractor.js +105 -0
  127. package/dist/parser/title-extractor.js.map +1 -0
  128. package/dist/pdf-visual/captioner.d.ts +11 -0
  129. package/dist/pdf-visual/captioner.d.ts.map +1 -0
  130. package/dist/pdf-visual/captioner.js +48 -0
  131. package/dist/pdf-visual/captioner.js.map +1 -0
  132. package/dist/pdf-visual/captioners/fast.d.ts +7 -0
  133. package/dist/pdf-visual/captioners/fast.d.ts.map +1 -0
  134. package/dist/pdf-visual/captioners/fast.js +108 -0
  135. package/dist/pdf-visual/captioners/fast.js.map +1 -0
  136. package/dist/pdf-visual/captioners/quality.d.ts +7 -0
  137. package/dist/pdf-visual/captioners/quality.d.ts.map +1 -0
  138. package/dist/pdf-visual/captioners/quality.js +101 -0
  139. package/dist/pdf-visual/captioners/quality.js.map +1 -0
  140. package/dist/pdf-visual/captioners/shared.d.ts +81 -0
  141. package/dist/pdf-visual/captioners/shared.d.ts.map +1 -0
  142. package/dist/pdf-visual/captioners/shared.js +156 -0
  143. package/dist/pdf-visual/captioners/shared.js.map +1 -0
  144. package/dist/pdf-visual/detector.d.ts +9 -0
  145. package/dist/pdf-visual/detector.d.ts.map +1 -0
  146. package/dist/pdf-visual/detector.js +269 -0
  147. package/dist/pdf-visual/detector.js.map +1 -0
  148. package/dist/pdf-visual/index.d.ts +13 -0
  149. package/dist/pdf-visual/index.d.ts.map +1 -0
  150. package/dist/pdf-visual/index.js +53 -0
  151. package/dist/pdf-visual/index.js.map +1 -0
  152. package/dist/pdf-visual/renderer.d.ts +9 -0
  153. package/dist/pdf-visual/renderer.d.ts.map +1 -0
  154. package/dist/pdf-visual/renderer.js +186 -0
  155. package/dist/pdf-visual/renderer.js.map +1 -0
  156. package/dist/pdf-visual/types.d.ts +53 -0
  157. package/dist/pdf-visual/types.d.ts.map +1 -0
  158. package/dist/pdf-visual/types.js +17 -0
  159. package/dist/pdf-visual/types.js.map +1 -0
  160. package/dist/server/error-utils.d.ts +63 -0
  161. package/dist/server/error-utils.d.ts.map +1 -0
  162. package/dist/server/error-utils.js +124 -0
  163. package/dist/server/error-utils.js.map +1 -0
  164. package/dist/server/index.d.ts +216 -0
  165. package/dist/server/index.d.ts.map +1 -0
  166. package/dist/server/index.js +1068 -0
  167. package/dist/server/index.js.map +1 -0
  168. package/dist/server/list-scanner.d.ts +30 -0
  169. package/dist/server/list-scanner.d.ts.map +1 -0
  170. package/dist/server/list-scanner.js +50 -0
  171. package/dist/server/list-scanner.js.map +1 -0
  172. package/dist/server/tool-definitions.d.ts +8 -0
  173. package/dist/server/tool-definitions.d.ts.map +1 -0
  174. package/dist/server/tool-definitions.js +181 -0
  175. package/dist/server/tool-definitions.js.map +1 -0
  176. package/dist/server/tool-input.d.ts +37 -0
  177. package/dist/server/tool-input.d.ts.map +1 -0
  178. package/dist/server/tool-input.js +211 -0
  179. package/dist/server/tool-input.js.map +1 -0
  180. package/dist/server/types.d.ts +307 -0
  181. package/dist/server/types.d.ts.map +1 -0
  182. package/dist/server/types.js +3 -0
  183. package/dist/server/types.js.map +1 -0
  184. package/dist/server-main.d.ts +40 -0
  185. package/dist/server-main.d.ts.map +1 -0
  186. package/dist/server-main.js +254 -0
  187. package/dist/server-main.js.map +1 -0
  188. package/dist/utils/base-dirs.d.ts +145 -0
  189. package/dist/utils/base-dirs.d.ts.map +1 -0
  190. package/dist/utils/base-dirs.js +344 -0
  191. package/dist/utils/base-dirs.js.map +1 -0
  192. package/dist/utils/errors.d.ts +32 -0
  193. package/dist/utils/errors.d.ts.map +1 -0
  194. package/dist/utils/errors.js +61 -0
  195. package/dist/utils/errors.js.map +1 -0
  196. package/dist/utils/limits.d.ts +26 -0
  197. package/dist/utils/limits.d.ts.map +1 -0
  198. package/dist/utils/limits.js +28 -0
  199. package/dist/utils/limits.js.map +1 -0
  200. package/dist/utils/list-sources.d.ts +38 -0
  201. package/dist/utils/list-sources.d.ts.map +1 -0
  202. package/dist/utils/list-sources.js +40 -0
  203. package/dist/utils/list-sources.js.map +1 -0
  204. package/dist/utils/raw-data-utils.d.ts +76 -0
  205. package/dist/utils/raw-data-utils.d.ts.map +1 -0
  206. package/dist/utils/raw-data-utils.js +202 -0
  207. package/dist/utils/raw-data-utils.js.map +1 -0
  208. package/dist/utils/scan.d.ts +114 -0
  209. package/dist/utils/scan.d.ts.map +1 -0
  210. package/dist/utils/scan.js +209 -0
  211. package/dist/utils/scan.js.map +1 -0
  212. package/dist/utils/scope-match.d.ts +38 -0
  213. package/dist/utils/scope-match.d.ts.map +1 -0
  214. package/dist/utils/scope-match.js +86 -0
  215. package/dist/utils/scope-match.js.map +1 -0
  216. package/dist/utils/sensitive-path.d.ts +9 -0
  217. package/dist/utils/sensitive-path.d.ts.map +1 -0
  218. package/dist/utils/sensitive-path.js +78 -0
  219. package/dist/utils/sensitive-path.js.map +1 -0
  220. package/dist/utils/sync-path-key.d.ts +14 -0
  221. package/dist/utils/sync-path-key.d.ts.map +1 -0
  222. package/dist/utils/sync-path-key.js +27 -0
  223. package/dist/utils/sync-path-key.js.map +1 -0
  224. package/dist/utils/type-guards.d.ts +18 -0
  225. package/dist/utils/type-guards.d.ts.map +1 -0
  226. package/dist/utils/type-guards.js +34 -0
  227. package/dist/utils/type-guards.js.map +1 -0
  228. package/dist/utils/visual-profile.d.ts +10 -0
  229. package/dist/utils/visual-profile.d.ts.map +1 -0
  230. package/dist/utils/visual-profile.js +15 -0
  231. package/dist/utils/visual-profile.js.map +1 -0
  232. package/dist/vectordb/index.d.ts +132 -0
  233. package/dist/vectordb/index.d.ts.map +1 -0
  234. package/dist/vectordb/index.js +617 -0
  235. package/dist/vectordb/index.js.map +1 -0
  236. package/dist/vectordb/search-filters.d.ts +15 -0
  237. package/dist/vectordb/search-filters.d.ts.map +1 -0
  238. package/dist/vectordb/search-filters.js +129 -0
  239. package/dist/vectordb/search-filters.js.map +1 -0
  240. package/dist/vectordb/types.d.ts +194 -0
  241. package/dist/vectordb/types.d.ts.map +1 -0
  242. package/dist/vectordb/types.js +237 -0
  243. package/dist/vectordb/types.js.map +1 -0
  244. package/package.json +108 -0
  245. package/skills/mcp-local-rag/SKILL.md +234 -0
  246. package/skills/mcp-local-rag/references/cli-reference.md +190 -0
  247. package/skills/mcp-local-rag/references/html-ingestion.md +78 -0
@@ -0,0 +1,28 @@
1
+ // Cross-cutting numeric limits shared across CLI and MCP server entry points.
2
+ // Dependency-free leaf module so any layer can import it without coupling.
3
+ /**
4
+ * Maximum directory recursion depth when scanning a base directory or ingest
5
+ * target. Applied identically by the CLI `ingest`/`list` walkers and the MCP
6
+ * server's `list_files` scan so the boundary is consistent everywhere.
7
+ */
8
+ export const MAX_SCAN_DEPTH = 10;
9
+ /**
10
+ * Default maximum file size for ingestion, in bytes (100 MB). Used when neither
11
+ * the CLI `--max-file-size` flag nor the `MAX_FILE_SIZE` env var is provided.
12
+ */
13
+ export const DEFAULT_MAX_FILE_SIZE = 104_857_600;
14
+ /**
15
+ * Hard upper bound (inclusive) for the configurable max file size, in bytes
16
+ * (500 MB). Values above this are rejected by `validateMaxFileSize`.
17
+ */
18
+ export const MAX_FILE_SIZE_LIMIT = 524_288_000;
19
+ /** Inclusive result-count range shared by CLI, MCP validation, and VectorStore. */
20
+ export const MIN_QUERY_LIMIT = 1;
21
+ export const MAX_QUERY_LIMIT = 20;
22
+ /** Maximum number of adjacent chunks accepted on either side of a target. */
23
+ export const MAX_NEIGHBOR_COUNT = 50;
24
+ /** Inclusive upper bound for the configurable minimum chunk length. */
25
+ export const MAX_CHUNK_MIN_LENGTH = 10_000;
26
+ /** Maximum encoded bytes for one visual attachment returned with a chunk. */
27
+ export const MAX_VISUAL_RENDITION_BYTES = 512 * 1024;
28
+ //# sourceMappingURL=limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/utils/limits.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2EAA2E;AAE3E;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAA;AAEhC;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAA;AAEhD;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAA;AAE9C,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAA;AAChC,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAA;AAEjC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAA;AAEpC,uEAAuE;AACvE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAA;AAE1C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,GAAG,IAAI,CAAA"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * An ingested entry paired with its identity key (`realpathForMatch` of the
3
+ * stored `filePath`). Only the fields the classifier reads are required, so the
4
+ * caller's richer row type is consumed structurally.
5
+ */
6
+ export interface KeyedIngestedEntry {
7
+ entry: {
8
+ filePath: string;
9
+ chunkCount: number;
10
+ timestamp: string;
11
+ };
12
+ key: string;
13
+ }
14
+ /**
15
+ * A classified source: a raw-data entry restored to its original `source`, or a
16
+ * real-file / orphaned entry keyed by `filePath`. Structurally compatible with
17
+ * the `SourceEntry` union both surfaces already return (no type-move refactor).
18
+ */
19
+ export type ClassifiedSource = {
20
+ source: string;
21
+ chunkCount: number;
22
+ timestamp: string;
23
+ } | {
24
+ filePath: string;
25
+ chunkCount: number;
26
+ timestamp: string;
27
+ };
28
+ /**
29
+ * Classify the ingested entries that matched no scanned file into `sources`.
30
+ *
31
+ * Under a `scope`, a managed raw-data entry is always emitted — it has no
32
+ * filesystem path to be in or out of scope — while a real-file entry is kept
33
+ * only when its stored path is in scope. An out-of-scope real file therefore
34
+ * appears in neither `files[]` nor `sources[]`, rather than being
35
+ * misreported as an orphan.
36
+ */
37
+ export declare function classifyIngestedSources(ingestedKeyed: readonly KeyedIngestedEntry[], matchedKeys: ReadonlySet<string>, dbPath: string, scope?: string[]): ClassifiedSource[];
38
+ //# sourceMappingURL=list-sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-sources.d.ts","sourceRoot":"","sources":["../../src/utils/list-sources.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClE,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/D;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,SAAS,kBAAkB,EAAE,EAC5C,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EAAE,GACf,gBAAgB,EAAE,CAwBpB"}
@@ -0,0 +1,40 @@
1
+ // Pure `sources` classifier shared by the MCP `list_files` handler and the
2
+ // `list` CLI, so the raw-data / real-file scope branch lives in one place.
3
+ //
4
+ // `sources` are ingested entries whose identity key matched no scanned file:
5
+ // content from `ingest_data`, plus orphaned DB entries for files no longer on
6
+ // disk under a scanned root.
7
+ import { extractSourceFromPath, isManagedRawDataPath } from './raw-data-utils.js';
8
+ import { matchesAnyScope } from './scope-match.js';
9
+ /**
10
+ * Classify the ingested entries that matched no scanned file into `sources`.
11
+ *
12
+ * Under a `scope`, a managed raw-data entry is always emitted — it has no
13
+ * filesystem path to be in or out of scope — while a real-file entry is kept
14
+ * only when its stored path is in scope. An out-of-scope real file therefore
15
+ * appears in neither `files[]` nor `sources[]`, rather than being
16
+ * misreported as an orphan.
17
+ */
18
+ export function classifyIngestedSources(ingestedKeyed, matchedKeys, dbPath, scope) {
19
+ const scopePrefixes = scope && scope.length > 0 ? scope : undefined;
20
+ return ingestedKeyed
21
+ .filter(({ key }) => !matchedKeys.has(key))
22
+ .filter(({ entry }) => {
23
+ if (!scopePrefixes) {
24
+ return true;
25
+ }
26
+ // Raw-data sources are exempt from scope; real-file entries respect it.
27
+ return (isManagedRawDataPath(entry.filePath, dbPath) ||
28
+ matchesAnyScope(entry.filePath, scopePrefixes));
29
+ })
30
+ .map(({ entry }) => {
31
+ if (isManagedRawDataPath(entry.filePath, dbPath)) {
32
+ const source = extractSourceFromPath(entry.filePath);
33
+ if (source) {
34
+ return { source, chunkCount: entry.chunkCount, timestamp: entry.timestamp };
35
+ }
36
+ }
37
+ return { filePath: entry.filePath, chunkCount: entry.chunkCount, timestamp: entry.timestamp };
38
+ });
39
+ }
40
+ //# sourceMappingURL=list-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-sources.js","sourceRoot":"","sources":["../../src/utils/list-sources.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,6BAA6B;AAE7B,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAqBlD;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,aAA4C,EAC5C,WAAgC,EAChC,MAAc,EACd,KAAgB;IAEhB,MAAM,aAAa,GAAG,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAEnE,OAAO,aAAa;SACjB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC1C,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;QACpB,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,wEAAwE;QACxE,OAAO,CACL,oBAAoB,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC;YAC5C,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,CAC/C,CAAA;IACH,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;QACjB,IAAI,oBAAoB,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;YACjD,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;YACpD,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAA;YAC7E,CAAC;QACH,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAA;IAC/F,CAAC,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,76 @@
1
+ /** Encode to URL-safe base64, so a source can be used as a filename. */
2
+ export declare function encodeBase64Url(str: string): string;
3
+ /** Decode URL-safe base64 (base64url). */
4
+ export declare function decodeBase64Url(base64url: string): string;
5
+ /**
6
+ * Drop the query string and fragment from an HTTP(S) source, so the same page
7
+ * maps to one path. A non-URL source (`clipboard://...`) passes through.
8
+ */
9
+ export declare function normalizeSource(source: string): string;
10
+ /** Formats accepted by ingest_data at runtime and in its public schema. */
11
+ export declare const CONTENT_FORMATS: readonly ['text', 'html', 'markdown'];
12
+ export type ContentFormat = (typeof CONTENT_FORMATS)[number];
13
+ /** Raw-data directory for a given LanceDB path. */
14
+ export declare function getRawDataDir(dbPath: string): string;
15
+ /** `{dbPath}/raw-data/{base64url(normalizedSource)}.{ext}` */
16
+ export declare function generateRawDataPath(dbPath: string, source: string): string;
17
+ /** Save content under raw-data, creating the directory if needed. */
18
+ export declare function saveRawData(dbPath: string, source: string, content: string): Promise<string>;
19
+ /** True only for managed raw-data content files under this database. */
20
+ export declare function isManagedRawDataPath(filePath: string, dbPath: string): boolean;
21
+ /**
22
+ * Lexical containment in `<dbPath>/raw-data/`. Safe for cleanup gates
23
+ * (`unlink` does not follow symlinks). Use {@link isPathInRawDataDir}
24
+ * when the result controls `readFile`.
25
+ */
26
+ export declare function isPathInRawDataDirLexical(filePath: string, dbPath: string): boolean;
27
+ /**
28
+ * Lexical containment plus `realpath` so a symlink under raw-data
29
+ * pointing outside cannot route a read through the raw-data fast-path.
30
+ * Fail-closed on `realpath` errors.
31
+ */
32
+ export declare function isPathInRawDataDir(filePath: string, dbPath: string): Promise<boolean>;
33
+ /** Original source of a raw-data path, or `null` when it is not one. */
34
+ export declare function extractSourceFromPath(filePath: string): string | null;
35
+ /**
36
+ * Metadata stored alongside each raw-data .md file as a .meta.json sidecar
37
+ */
38
+ /** What {@link saveMetaJson} writes. */
39
+ export interface RawDataMeta {
40
+ title: string | null;
41
+ source: string;
42
+ format: ContentFormat;
43
+ }
44
+ /**
45
+ * What re-ingest reads back. Only `title` is consumed, so a sidecar missing
46
+ * `source` or `format` still yields a usable title rather than failing an
47
+ * otherwise valid ingest.
48
+ */
49
+ export interface RawDataMetaRead {
50
+ title: string | null;
51
+ }
52
+ /** Replaces the trailing `.md` with `.meta.json`. */
53
+ export declare function generateMetaJsonPath(mdPath: string): string;
54
+ /** Save metadata as a JSON sidecar beside a raw-data .md file. */
55
+ export declare function saveMetaJson(mdPath: string, meta: RawDataMeta): Promise<void>;
56
+ /** `null` when the sidecar does not exist; any other read error is re-thrown. */
57
+ export declare function loadMetaJson(mdPath: string): Promise<RawDataMetaRead | null>;
58
+ /**
59
+ * True when a filesystem error means the target path does not exist.
60
+ */
61
+ export declare function isEnoent(error: unknown): boolean;
62
+ /**
63
+ * Pre-unlink existence of the on-disk raw-data artifacts for a target .md
64
+ * path: the raw-data file itself and its .meta.json sidecar.
65
+ */
66
+ export interface RawDataArtifactExistence {
67
+ rawDataExisted: boolean;
68
+ metaExisted: boolean;
69
+ }
70
+ /**
71
+ * Report which raw-data artifacts exist. Single source for the delete
72
+ * `existed` signal, so the MCP and CLI paths cannot drift. Call BEFORE
73
+ * unlinking — it reports pre-unlink state.
74
+ */
75
+ export declare function checkRawDataArtifacts(targetPath: string): Promise<RawDataArtifactExistence>;
76
+ //# sourceMappingURL=raw-data-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-data-utils.d.ts","sourceRoot":"","sources":["../../src/utils/raw-data-utils.ts"],"names":[],"mappings":"AAYA,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAUzD;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAatD;AAMD,2EAA2E;AAC3E,eAAO,MAAM,eAAe,YAAI,MAAM,EAAE,MAAM,EAAE,UAAU,CAAU,CAAA;AACpE,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAQ5D,mDAAmD;AACnD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK1E;AAMD,qEAAqE;AACrE,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAUjB;AAMD,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAI9E;AAUD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAInF;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW3F;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBrE;AAMD;;GAEG;AACH,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,aAAa,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAYD,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,kEAAkE;AAClE,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnF;AAED,iFAAiF;AACjF,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAWlF;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhD;AAkBD;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,OAAO,CAAA;IACvB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAIjG"}
@@ -0,0 +1,202 @@
1
+ // Raw Data Utilities for ingest_data tool
2
+ // Handles: base64url encoding, source normalization, file saving, source extraction
3
+ import { access, mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
4
+ import { basename, dirname, join, posix, resolve, sep } from 'node:path';
5
+ import { errorCode, isRecord } from './type-guards.js';
6
+ // ============================================
7
+ // Base64URL Encoding/Decoding
8
+ // ============================================
9
+ /** Encode to URL-safe base64, so a source can be used as a filename. */
10
+ export function encodeBase64Url(str) {
11
+ return Buffer.from(str, 'utf-8')
12
+ .toString('base64')
13
+ .replace(/\+/g, '-')
14
+ .replace(/\//g, '_')
15
+ .replace(/=+$/, '');
16
+ }
17
+ /** Decode URL-safe base64 (base64url). */
18
+ export function decodeBase64Url(base64url) {
19
+ // Convert base64url to standard base64
20
+ let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
21
+ // Add padding if needed
22
+ while (base64.length % 4 !== 0) {
23
+ base64 += '=';
24
+ }
25
+ return Buffer.from(base64, 'base64').toString('utf-8');
26
+ }
27
+ // ============================================
28
+ // Source Normalization
29
+ // ============================================
30
+ /**
31
+ * Drop the query string and fragment from an HTTP(S) source, so the same page
32
+ * maps to one path. A non-URL source (`clipboard://...`) passes through.
33
+ */
34
+ export function normalizeSource(source) {
35
+ try {
36
+ const parsed = new URL(source);
37
+ // Only normalize HTTP(S) URLs
38
+ if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
39
+ return `${parsed.origin}${parsed.pathname}`;
40
+ }
41
+ // Non-HTTP URLs (clipboard://, etc.) are returned as-is
42
+ return source;
43
+ }
44
+ catch {
45
+ // Not a valid URL, return as-is
46
+ return source;
47
+ }
48
+ }
49
+ // ============================================
50
+ // Format Utilities
51
+ // ============================================
52
+ /** Formats accepted by ingest_data at runtime and in its public schema. */
53
+ export const CONTENT_FORMATS = ['text', 'html', 'markdown'];
54
+ const RAW_DATA_EXTENSION = 'md';
55
+ // ============================================
56
+ // Path Generation
57
+ // ============================================
58
+ /** Raw-data directory for a given LanceDB path. */
59
+ export function getRawDataDir(dbPath) {
60
+ return join(dbPath, 'raw-data');
61
+ }
62
+ /** `{dbPath}/raw-data/{base64url(normalizedSource)}.{ext}` */
63
+ export function generateRawDataPath(dbPath, source) {
64
+ const normalizedSource = normalizeSource(source);
65
+ const encoded = encodeBase64Url(normalizedSource);
66
+ // Use resolve to ensure absolute path (required by validateFilePath)
67
+ return resolve(getRawDataDir(dbPath), `${encoded}.${RAW_DATA_EXTENSION}`);
68
+ }
69
+ // ============================================
70
+ // File Operations
71
+ // ============================================
72
+ /** Save content under raw-data, creating the directory if needed. */
73
+ export async function saveRawData(dbPath, source, content) {
74
+ const filePath = generateRawDataPath(dbPath, source);
75
+ // Ensure directory exists
76
+ await mkdir(dirname(filePath), { recursive: true });
77
+ // Write content to file
78
+ await writeFile(filePath, content, 'utf-8');
79
+ return filePath;
80
+ }
81
+ // ============================================
82
+ // Path Detection and Source Extraction
83
+ // ============================================
84
+ /** True only for managed raw-data content files under this database. */
85
+ export function isManagedRawDataPath(filePath, dbPath) {
86
+ return (isPathInRawDataDirLexical(filePath, dbPath) && /^[A-Za-z0-9_-]+\.md$/.test(basename(filePath)));
87
+ }
88
+ /**
89
+ * Case-normalize a path for prefix containment. Windows filesystems are
90
+ * case-insensitive by default, so the boundary check must mirror that.
91
+ */
92
+ function caseNormalize(p) {
93
+ return process.platform === 'win32' ? p.toLowerCase() : p;
94
+ }
95
+ /**
96
+ * Lexical containment in `<dbPath>/raw-data/`. Safe for cleanup gates
97
+ * (`unlink` does not follow symlinks). Use {@link isPathInRawDataDir}
98
+ * when the result controls `readFile`.
99
+ */
100
+ export function isPathInRawDataDirLexical(filePath, dbPath) {
101
+ const target = caseNormalize(resolve(filePath));
102
+ const rawDir = caseNormalize(resolve(getRawDataDir(dbPath)));
103
+ return target === rawDir || target.startsWith(rawDir + sep);
104
+ }
105
+ /**
106
+ * Lexical containment plus `realpath` so a symlink under raw-data
107
+ * pointing outside cannot route a read through the raw-data fast-path.
108
+ * Fail-closed on `realpath` errors.
109
+ */
110
+ export async function isPathInRawDataDir(filePath, dbPath) {
111
+ if (!isPathInRawDataDirLexical(filePath, dbPath)) {
112
+ return false;
113
+ }
114
+ try {
115
+ const realTarget = caseNormalize(await realpath(resolve(filePath)));
116
+ const realRaw = caseNormalize(await realpath(resolve(getRawDataDir(dbPath))));
117
+ return realTarget === realRaw || realTarget.startsWith(realRaw + sep);
118
+ }
119
+ catch {
120
+ return false;
121
+ }
122
+ }
123
+ /** Original source of a raw-data path, or `null` when it is not one. */
124
+ export function extractSourceFromPath(filePath) {
125
+ const normalized = filePath.replace(/\\/g, '/');
126
+ const rawDataMarker = '/raw-data/';
127
+ const rawDataIndex = normalized.indexOf(rawDataMarker);
128
+ if (rawDataIndex === -1) {
129
+ return null;
130
+ }
131
+ const fileName = posix.basename(normalized);
132
+ const dotIndex = fileName.lastIndexOf('.');
133
+ if (dotIndex === -1) {
134
+ return null;
135
+ }
136
+ const encoded = fileName.slice(0, dotIndex);
137
+ return decodeBase64Url(encoded);
138
+ }
139
+ /**
140
+ * Read one persisted sidecar. The file is plain JSON on disk, so a malformed or
141
+ * hand-edited value is a real possibility and each field is checked rather than
142
+ * assumed.
143
+ */
144
+ function toRawDataMetaRead(parsed) {
145
+ const title = isRecord(parsed) ? parsed['title'] : undefined;
146
+ return { title: typeof title === 'string' ? title : null };
147
+ }
148
+ /** Replaces the trailing `.md` with `.meta.json`. */
149
+ export function generateMetaJsonPath(mdPath) {
150
+ return mdPath.replace(/\.md$/, '.meta.json');
151
+ }
152
+ /** Save metadata as a JSON sidecar beside a raw-data .md file. */
153
+ export async function saveMetaJson(mdPath, meta) {
154
+ const metaPath = generateMetaJsonPath(mdPath);
155
+ await writeFile(metaPath, JSON.stringify(meta, null, 2), 'utf-8');
156
+ }
157
+ /** `null` when the sidecar does not exist; any other read error is re-thrown. */
158
+ export async function loadMetaJson(mdPath) {
159
+ const metaPath = generateMetaJsonPath(mdPath);
160
+ try {
161
+ const content = await readFile(metaPath, 'utf-8');
162
+ return toRawDataMetaRead(JSON.parse(content));
163
+ }
164
+ catch (error) {
165
+ if (isEnoent(error)) {
166
+ return null;
167
+ }
168
+ throw error;
169
+ }
170
+ }
171
+ /**
172
+ * True when a filesystem error means the target path does not exist.
173
+ */
174
+ export function isEnoent(error) {
175
+ return errorCode(error) === 'ENOENT';
176
+ }
177
+ // ============================================
178
+ // Raw-Data Artifact Existence
179
+ // ============================================
180
+ /**
181
+ * Whether a path exists. access()-based, never throws.
182
+ */
183
+ async function pathExists(path) {
184
+ try {
185
+ await access(path);
186
+ return true;
187
+ }
188
+ catch {
189
+ return false;
190
+ }
191
+ }
192
+ /**
193
+ * Report which raw-data artifacts exist. Single source for the delete
194
+ * `existed` signal, so the MCP and CLI paths cannot drift. Call BEFORE
195
+ * unlinking — it reports pre-unlink state.
196
+ */
197
+ export async function checkRawDataArtifacts(targetPath) {
198
+ const rawDataExisted = await pathExists(targetPath);
199
+ const metaExisted = await pathExists(generateMetaJsonPath(targetPath));
200
+ return { rawDataExisted, metaExisted };
201
+ }
202
+ //# sourceMappingURL=raw-data-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-data-utils.js","sourceRoot":"","sources":["../../src/utils/raw-data-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Canonical identity key for the `list`/`list_files` cross-reference: a file's
3
+ * realpath, falling back to the input path when realpath fails (orphaned or
4
+ * raw-data entries). Matching ingested DB entries against scanned files by this
5
+ * key recognizes the same physical file across symlinked spellings (prefix or
6
+ * alias). Storage, lookup, and display still use the normal resolve() path —
7
+ * realpath here is the file-identity comparison, not a user-facing value.
8
+ */
9
+ export declare function realpathForMatch(filePath: string): Promise<string>;
10
+ /**
11
+ * Canonical form of one explicitly requested path: its parent chain resolved
12
+ * through symbolic links, with the final component appended verbatim. `null` when
13
+ * the parent chain cannot be resolved at all — absent, or a directory this
14
+ * process may not traverse — which a caller must treat as "not contained",
15
+ * because telling those cases apart would report the state of paths outside its
16
+ * configured roots.
17
+ *
18
+ * Only the parent chain is resolved, because the requested entry itself is judged
19
+ * by {@link classifyRequestedPath}'s `lstat`: a symbolic link named directly
20
+ * inside a root is an in-root entry that is refused as a link, not a path to be
21
+ * reported by whatever it points at.
22
+ *
23
+ * `realpath` here is the containment (security) boundary, the same role it plays
24
+ * in `DocumentParser.validateFilePath` — never a spelling anything is stored,
25
+ * looked up, or displayed under. Those stay `resolve()`-only.
26
+ */
27
+ export declare function canonicalizeRequestedPath(path: string): Promise<string | null>;
28
+ /** Why the collect predicates below refuse a path. */
29
+ export type ScanRejection =
30
+ /** A symbolic link, which is never followed. */
31
+ 'symlink'
32
+ /** Under a configured excluded prefix (the database or cache directory). */
33
+ | 'excluded'
34
+ /** A regular file whose extension is not a supported document type. */
35
+ | 'unsupported'
36
+ /** Neither a regular file nor a directory (socket, FIFO, device, …). */
37
+ | 'irregular';
38
+ /** What a path is, once the collect predicates have judged it. */
39
+ export type ScanEntryKind = 'file' | 'directory' | ScanRejection;
40
+ /** The `Dirent` / `Stats` subset the collect predicates read. */
41
+ interface EntryTypeFacts {
42
+ isSymbolicLink(): boolean;
43
+ isDirectory(): boolean;
44
+ isFile(): boolean;
45
+ }
46
+ /**
47
+ * The collect predicates of {@link bfsCollectSupportedFiles} as one decision,
48
+ * so a discovered entry and an explicitly requested path are judged by the same
49
+ * rules rather than by two implementations that drift.
50
+ *
51
+ * Evaluation order is part of the contract: a symbolic link is reported as a
52
+ * link even under an excluded prefix, and a directory needs no extension test.
53
+ *
54
+ * `platform` is a parameter so the Windows exclusion semantics are provable on
55
+ * a POSIX host. Both `Dirent` and `Stats` satisfy {@link EntryTypeFacts}.
56
+ */
57
+ export declare function classifyScanEntry(fullPath: string, entry: EntryTypeFacts, excludePaths: readonly string[], platform?: NodeJS.Platform): ScanEntryKind;
58
+ /**
59
+ * Classify one explicitly requested path with {@link classifyScanEntry}, so a
60
+ * path a caller names is subject to the same predicates as a path the walker
61
+ * discovers.
62
+ *
63
+ * `lstat` rather than `stat`, so a symbolic link is reported as a link instead of
64
+ * as whatever it points at; and `lstat` rather than any read, so a caller can
65
+ * refuse the path before its bytes cost anything — reading a FIFO blocks forever,
66
+ * and reading through a link reaches outside the configured roots.
67
+ *
68
+ * Any stat failure is `'missing'`: an unreachable path and an absent one are the
69
+ * same non-answer to "what is here".
70
+ */
71
+ export declare function classifyRequestedPath(path: string, excludePaths: readonly string[], platform?: NodeJS.Platform): Promise<ScanEntryKind | 'missing'>;
72
+ /** A directory that could not be read during the scan. */
73
+ export interface UnreadableDir {
74
+ dirPath: string;
75
+ /** Node error `code` (e.g. `EACCES`), or `'UNKNOWN'` when unavailable. */
76
+ code: string;
77
+ }
78
+ /** Structured result of a bounded directory scan. */
79
+ export interface DirScanResult {
80
+ /** Supported files found under the root, in BFS-discovery order (unsorted). */
81
+ files: string[];
82
+ /** Directories skipped because `readdir` failed (caller decides how to warn). */
83
+ unreadableDirs: UnreadableDir[];
84
+ /**
85
+ * Each entry is the first unvisited directory of a branch pruned for
86
+ * exceeding `maxDepth` — the directory that was reached but never read. That
87
+ * path and every descendant of it is unobserved by this scan; its ancestors
88
+ * and fully visited siblings are not listed.
89
+ */
90
+ depthLimitedDirs: string[];
91
+ /** Full paths of directory entries skipped because they are symbolic links. */
92
+ skippedSymlinks: string[];
93
+ /** True if any branch was pruned for exceeding `maxDepth`. */
94
+ depthLimited: boolean;
95
+ }
96
+ export interface BfsCollectOptions {
97
+ /** Traversal bound; defaults to {@link MAX_SCAN_DEPTH}. */
98
+ maxDepth?: number;
99
+ /** Absolute prefixes to restrict traversal and collection to. */
100
+ scope?: string[] | undefined;
101
+ /** Selects case sensitivity of the exclusion comparison; defaults to the host. */
102
+ platform?: NodeJS.Platform;
103
+ }
104
+ /**
105
+ * Bounded BFS scan of a single root, depth counted from `rootPath` itself.
106
+ * Symlinks are never followed. An unreadable directory is recorded and does
107
+ * not abort the scan.
108
+ *
109
+ * Does not sort, dedupe, or emit warnings — each caller owns its own output
110
+ * contract for those.
111
+ */
112
+ export declare function bfsCollectSupportedFiles(rootPath: string, excludePaths: readonly string[], options?: BfsCollectOptions): Promise<DirScanResult>;
113
+ export {};
114
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/utils/scan.ts"],"names":[],"mappings":"AAkBA;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMpF;AAED,sDAAsD;AACtD,MAAM,MAAM,aAAa;AACvB,gDAAgD;AAC9C,SAAS;AACX,4EAA4E;GAC1E,UAAU;AACZ,uEAAuE;GACrE,aAAa;AACf,wEAAwE;GACtE,WAAW,CAAA;AAEf,kEAAkE;AAClE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,aAAa,CAAA;AAEhE,iEAAiE;AACjE,UAAU,cAAc;IACtB,cAAc,IAAI,OAAO,CAAA;IACzB,WAAW,IAAI,OAAO,CAAA;IACtB,MAAM,IAAI,OAAO,CAAA;CAClB;AA+BD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,cAAc,EACrB,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,aAAa,CAcf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAMpC;AAED,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;CACb;AAED,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,iFAAiF;IACjF,cAAc,EAAE,aAAa,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,+EAA+E;IAC/E,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,8DAA8D;IAC9D,YAAY,EAAE,OAAO,CAAA;CACtB;AAmDD,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,aAAa,CAAC,CAoDxB"}