@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.
- package/LICENSE +21 -0
- package/README.de.md +441 -0
- package/README.es.md +441 -0
- package/README.fr.md +441 -0
- package/README.md +530 -0
- package/README.pt-BR.md +441 -0
- package/README.zh-CN.md +441 -0
- package/dist/bin/install-skills.d.ts +19 -0
- package/dist/bin/install-skills.d.ts.map +1 -0
- package/dist/bin/install-skills.js +218 -0
- package/dist/bin/install-skills.js.map +1 -0
- package/dist/chunker/index.d.ts +24 -0
- package/dist/chunker/index.d.ts.map +1 -0
- package/dist/chunker/index.js +2 -0
- package/dist/chunker/index.js.map +1 -0
- package/dist/chunker/semantic-chunker.d.ts +96 -0
- package/dist/chunker/semantic-chunker.d.ts.map +1 -0
- package/dist/chunker/semantic-chunker.js +362 -0
- package/dist/chunker/semantic-chunker.js.map +1 -0
- package/dist/chunker/sentence-splitter.d.ts +32 -0
- package/dist/chunker/sentence-splitter.d.ts.map +1 -0
- package/dist/chunker/sentence-splitter.js +231 -0
- package/dist/chunker/sentence-splitter.js.map +1 -0
- package/dist/chunker/token-containment.d.ts +39 -0
- package/dist/chunker/token-containment.d.ts.map +1 -0
- package/dist/chunker/token-containment.js +83 -0
- package/dist/chunker/token-containment.js.map +1 -0
- package/dist/cli/common.d.ts +34 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +121 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/delete.d.ts +3 -0
- package/dist/cli/delete.d.ts.map +1 -0
- package/dist/cli/delete.js +169 -0
- package/dist/cli/delete.js.map +1 -0
- package/dist/cli/file-collection.d.ts +2 -0
- package/dist/cli/file-collection.d.ts.map +1 -0
- package/dist/cli/file-collection.js +53 -0
- package/dist/cli/file-collection.js.map +1 -0
- package/dist/cli/ingest.d.ts +69 -0
- package/dist/cli/ingest.d.ts.map +1 -0
- package/dist/cli/ingest.js +323 -0
- package/dist/cli/ingest.js.map +1 -0
- package/dist/cli/list.d.ts +27 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +207 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/options.d.ts +89 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +244 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/cli/query.d.ts +17 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +194 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/read-neighbors.d.ts +3 -0
- package/dist/cli/read-neighbors.d.ts.map +1 -0
- package/dist/cli/read-neighbors.js +192 -0
- package/dist/cli/read-neighbors.js.map +1 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +78 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/sync.d.ts +6 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +271 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli-main.d.ts +9 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +60 -0
- package/dist/cli-main.js.map +1 -0
- package/dist/embedder/index.d.ts +143 -0
- package/dist/embedder/index.d.ts.map +1 -0
- package/dist/embedder/index.js +429 -0
- package/dist/embedder/index.js.map +1 -0
- package/dist/embedder/remote.d.ts +51 -0
- package/dist/embedder/remote.d.ts.map +1 -0
- package/dist/embedder/remote.js +182 -0
- package/dist/embedder/remote.js.map +1 -0
- package/dist/features/list.d.ts +37 -0
- package/dist/features/list.d.ts.map +1 -0
- package/dist/features/list.js +41 -0
- package/dist/features/list.js.map +1 -0
- package/dist/features/sync.d.ts +219 -0
- package/dist/features/sync.d.ts.map +1 -0
- package/dist/features/sync.js +461 -0
- package/dist/features/sync.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/compute.d.ts +63 -0
- package/dist/ingest/compute.d.ts.map +1 -0
- package/dist/ingest/compute.js +161 -0
- package/dist/ingest/compute.js.map +1 -0
- package/dist/ingest/file.d.ts +40 -0
- package/dist/ingest/file.d.ts.map +1 -0
- package/dist/ingest/file.js +74 -0
- package/dist/ingest/file.js.map +1 -0
- package/dist/ingest/visual.d.ts +52 -0
- package/dist/ingest/visual.d.ts.map +1 -0
- package/dist/ingest/visual.js +294 -0
- package/dist/ingest/visual.js.map +1 -0
- package/dist/parser/docx-parser.d.ts +12 -0
- package/dist/parser/docx-parser.d.ts.map +1 -0
- package/dist/parser/docx-parser.js +375 -0
- package/dist/parser/docx-parser.js.map +1 -0
- package/dist/parser/html-parser.d.ts +16 -0
- package/dist/parser/html-parser.d.ts.map +1 -0
- package/dist/parser/html-parser.js +119 -0
- package/dist/parser/html-parser.js.map +1 -0
- package/dist/parser/index.d.ts +125 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +364 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/pdf-extract.d.ts +49 -0
- package/dist/parser/pdf-extract.d.ts.map +1 -0
- package/dist/parser/pdf-extract.js +114 -0
- package/dist/parser/pdf-extract.js.map +1 -0
- package/dist/parser/pdf-filter.d.ts +91 -0
- package/dist/parser/pdf-filter.d.ts.map +1 -0
- package/dist/parser/pdf-filter.js +522 -0
- package/dist/parser/pdf-filter.js.map +1 -0
- package/dist/parser/title-extractor.d.ts +28 -0
- package/dist/parser/title-extractor.d.ts.map +1 -0
- package/dist/parser/title-extractor.js +105 -0
- package/dist/parser/title-extractor.js.map +1 -0
- package/dist/pdf-visual/captioner.d.ts +11 -0
- package/dist/pdf-visual/captioner.d.ts.map +1 -0
- package/dist/pdf-visual/captioner.js +48 -0
- package/dist/pdf-visual/captioner.js.map +1 -0
- package/dist/pdf-visual/captioners/fast.d.ts +7 -0
- package/dist/pdf-visual/captioners/fast.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/fast.js +108 -0
- package/dist/pdf-visual/captioners/fast.js.map +1 -0
- package/dist/pdf-visual/captioners/quality.d.ts +7 -0
- package/dist/pdf-visual/captioners/quality.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/quality.js +101 -0
- package/dist/pdf-visual/captioners/quality.js.map +1 -0
- package/dist/pdf-visual/captioners/shared.d.ts +81 -0
- package/dist/pdf-visual/captioners/shared.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/shared.js +156 -0
- package/dist/pdf-visual/captioners/shared.js.map +1 -0
- package/dist/pdf-visual/detector.d.ts +9 -0
- package/dist/pdf-visual/detector.d.ts.map +1 -0
- package/dist/pdf-visual/detector.js +269 -0
- package/dist/pdf-visual/detector.js.map +1 -0
- package/dist/pdf-visual/index.d.ts +13 -0
- package/dist/pdf-visual/index.d.ts.map +1 -0
- package/dist/pdf-visual/index.js +53 -0
- package/dist/pdf-visual/index.js.map +1 -0
- package/dist/pdf-visual/renderer.d.ts +9 -0
- package/dist/pdf-visual/renderer.d.ts.map +1 -0
- package/dist/pdf-visual/renderer.js +186 -0
- package/dist/pdf-visual/renderer.js.map +1 -0
- package/dist/pdf-visual/types.d.ts +53 -0
- package/dist/pdf-visual/types.d.ts.map +1 -0
- package/dist/pdf-visual/types.js +17 -0
- package/dist/pdf-visual/types.js.map +1 -0
- package/dist/server/error-utils.d.ts +63 -0
- package/dist/server/error-utils.d.ts.map +1 -0
- package/dist/server/error-utils.js +124 -0
- package/dist/server/error-utils.js.map +1 -0
- package/dist/server/index.d.ts +216 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1068 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/list-scanner.d.ts +30 -0
- package/dist/server/list-scanner.d.ts.map +1 -0
- package/dist/server/list-scanner.js +50 -0
- package/dist/server/list-scanner.js.map +1 -0
- package/dist/server/tool-definitions.d.ts +8 -0
- package/dist/server/tool-definitions.d.ts.map +1 -0
- package/dist/server/tool-definitions.js +181 -0
- package/dist/server/tool-definitions.js.map +1 -0
- package/dist/server/tool-input.d.ts +37 -0
- package/dist/server/tool-input.d.ts.map +1 -0
- package/dist/server/tool-input.js +211 -0
- package/dist/server/tool-input.js.map +1 -0
- package/dist/server/types.d.ts +307 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +3 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server-main.d.ts +40 -0
- package/dist/server-main.d.ts.map +1 -0
- package/dist/server-main.js +254 -0
- package/dist/server-main.js.map +1 -0
- package/dist/utils/base-dirs.d.ts +145 -0
- package/dist/utils/base-dirs.d.ts.map +1 -0
- package/dist/utils/base-dirs.js +344 -0
- package/dist/utils/base-dirs.js.map +1 -0
- package/dist/utils/errors.d.ts +32 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +61 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/limits.d.ts +26 -0
- package/dist/utils/limits.d.ts.map +1 -0
- package/dist/utils/limits.js +28 -0
- package/dist/utils/limits.js.map +1 -0
- package/dist/utils/list-sources.d.ts +38 -0
- package/dist/utils/list-sources.d.ts.map +1 -0
- package/dist/utils/list-sources.js +40 -0
- package/dist/utils/list-sources.js.map +1 -0
- package/dist/utils/raw-data-utils.d.ts +76 -0
- package/dist/utils/raw-data-utils.d.ts.map +1 -0
- package/dist/utils/raw-data-utils.js +202 -0
- package/dist/utils/raw-data-utils.js.map +1 -0
- package/dist/utils/scan.d.ts +114 -0
- package/dist/utils/scan.d.ts.map +1 -0
- package/dist/utils/scan.js +209 -0
- package/dist/utils/scan.js.map +1 -0
- package/dist/utils/scope-match.d.ts +38 -0
- package/dist/utils/scope-match.d.ts.map +1 -0
- package/dist/utils/scope-match.js +86 -0
- package/dist/utils/scope-match.js.map +1 -0
- package/dist/utils/sensitive-path.d.ts +9 -0
- package/dist/utils/sensitive-path.d.ts.map +1 -0
- package/dist/utils/sensitive-path.js +78 -0
- package/dist/utils/sensitive-path.js.map +1 -0
- package/dist/utils/sync-path-key.d.ts +14 -0
- package/dist/utils/sync-path-key.d.ts.map +1 -0
- package/dist/utils/sync-path-key.js +27 -0
- package/dist/utils/sync-path-key.js.map +1 -0
- package/dist/utils/type-guards.d.ts +18 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +34 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/dist/utils/visual-profile.d.ts +10 -0
- package/dist/utils/visual-profile.d.ts.map +1 -0
- package/dist/utils/visual-profile.js +15 -0
- package/dist/utils/visual-profile.js.map +1 -0
- package/dist/vectordb/index.d.ts +132 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +617 -0
- package/dist/vectordb/index.js.map +1 -0
- package/dist/vectordb/search-filters.d.ts +15 -0
- package/dist/vectordb/search-filters.d.ts.map +1 -0
- package/dist/vectordb/search-filters.js +129 -0
- package/dist/vectordb/search-filters.js.map +1 -0
- package/dist/vectordb/types.d.ts +194 -0
- package/dist/vectordb/types.d.ts.map +1 -0
- package/dist/vectordb/types.js +237 -0
- package/dist/vectordb/types.js.map +1 -0
- package/package.json +108 -0
- package/skills/mcp-local-rag/SKILL.md +234 -0
- package/skills/mcp-local-rag/references/cli-reference.md +190 -0
- 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"}
|