abb-opencode-local-rag 0.1.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.
- package/LICENSE +21 -0
- package/README.de.md +416 -0
- package/README.es.md +416 -0
- package/README.fr.md +416 -0
- package/README.md +491 -0
- package/README.pt-BR.md +416 -0
- package/README.zh-CN.md +416 -0
- package/dist/bin/install-skills.d.ts +20 -0
- package/dist/bin/install-skills.d.ts.map +1 -0
- package/dist/bin/install-skills.js +195 -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 +97 -0
- package/dist/chunker/semantic-chunker.d.ts.map +1 -0
- package/dist/chunker/semantic-chunker.js +294 -0
- package/dist/chunker/semantic-chunker.js.map +1 -0
- package/dist/chunker/sentence-splitter.d.ts +28 -0
- package/dist/chunker/sentence-splitter.d.ts.map +1 -0
- package/dist/chunker/sentence-splitter.js +219 -0
- package/dist/chunker/sentence-splitter.js.map +1 -0
- package/dist/cli/common.d.ts +65 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +138 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/delete.d.ts +8 -0
- package/dist/cli/delete.d.ts.map +1 -0
- package/dist/cli/delete.js +173 -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 +100 -0
- package/dist/cli/ingest.d.ts.map +1 -0
- package/dist/cli/ingest.js +363 -0
- package/dist/cli/ingest.js.map +1 -0
- package/dist/cli/list.d.ts +35 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +210 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/options.d.ts +100 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +241 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/cli/query.d.ts +24 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +191 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/read-neighbors.d.ts +11 -0
- package/dist/cli/read-neighbors.d.ts.map +1 -0
- package/dist/cli/read-neighbors.js +224 -0
- package/dist/cli/read-neighbors.js.map +1 -0
- package/dist/cli/status.d.ts +8 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +80 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/sync.d.ts +8 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +244 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli-main.d.ts +12 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +63 -0
- package/dist/cli-main.js.map +1 -0
- package/dist/embedder/index.d.ts +85 -0
- package/dist/embedder/index.d.ts.map +1 -0
- package/dist/embedder/index.js +284 -0
- package/dist/embedder/index.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 +40 -0
- package/dist/features/list.js.map +1 -0
- package/dist/features/sync.d.ts +207 -0
- package/dist/features/sync.d.ts.map +1 -0
- package/dist/features/sync.js +380 -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 +53 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/compute.d.ts +86 -0
- package/dist/ingest/compute.d.ts.map +1 -0
- package/dist/ingest/compute.js +177 -0
- package/dist/ingest/compute.js.map +1 -0
- package/dist/ingest/file.d.ts +27 -0
- package/dist/ingest/file.d.ts.map +1 -0
- package/dist/ingest/file.js +67 -0
- package/dist/ingest/file.js.map +1 -0
- package/dist/ingest/visual.d.ts +45 -0
- package/dist/ingest/visual.d.ts.map +1 -0
- package/dist/ingest/visual.js +234 -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 +328 -0
- package/dist/parser/docx-parser.js.map +1 -0
- package/dist/parser/html-parser.d.ts +18 -0
- package/dist/parser/html-parser.d.ts.map +1 -0
- package/dist/parser/html-parser.js +102 -0
- package/dist/parser/html-parser.js.map +1 -0
- package/dist/parser/index.d.ts +214 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +454 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/pdf-extract.d.ts +81 -0
- package/dist/parser/pdf-extract.d.ts.map +1 -0
- package/dist/parser/pdf-extract.js +112 -0
- package/dist/parser/pdf-extract.js.map +1 -0
- package/dist/parser/pdf-filter.d.ts +117 -0
- package/dist/parser/pdf-filter.d.ts.map +1 -0
- package/dist/parser/pdf-filter.js +528 -0
- package/dist/parser/pdf-filter.js.map +1 -0
- package/dist/parser/title-extractor.d.ts +69 -0
- package/dist/parser/title-extractor.d.ts.map +1 -0
- package/dist/parser/title-extractor.js +145 -0
- package/dist/parser/title-extractor.js.map +1 -0
- package/dist/pdf-visual/captioner.d.ts +16 -0
- package/dist/pdf-visual/captioner.d.ts.map +1 -0
- package/dist/pdf-visual/captioner.js +63 -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 +103 -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 +127 -0
- package/dist/pdf-visual/captioners/quality.js.map +1 -0
- package/dist/pdf-visual/captioners/shared.d.ts +44 -0
- package/dist/pdf-visual/captioners/shared.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/shared.js +104 -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 +234 -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 +45 -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 +177 -0
- package/dist/pdf-visual/renderer.js.map +1 -0
- package/dist/pdf-visual/types.d.ts +62 -0
- package/dist/pdf-visual/types.d.ts.map +1 -0
- package/dist/pdf-visual/types.js +32 -0
- package/dist/pdf-visual/types.js.map +1 -0
- package/dist/server/error-utils.d.ts +79 -0
- package/dist/server/error-utils.d.ts.map +1 -0
- package/dist/server/error-utils.js +148 -0
- package/dist/server/error-utils.js.map +1 -0
- package/dist/server/index.d.ts +258 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1104 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/list-scanner.d.ts +52 -0
- package/dist/server/list-scanner.d.ts.map +1 -0
- package/dist/server/list-scanner.js +72 -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 +216 -0
- package/dist/server/tool-input.js.map +1 -0
- package/dist/server/types.d.ts +331 -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 +46 -0
- package/dist/server-main.d.ts.map +1 -0
- package/dist/server-main.js +242 -0
- package/dist/server-main.js.map +1 -0
- package/dist/utils/base-dirs.d.ts +212 -0
- package/dist/utils/base-dirs.d.ts.map +1 -0
- package/dist/utils/base-dirs.js +422 -0
- package/dist/utils/base-dirs.js.map +1 -0
- package/dist/utils/errors.d.ts +24 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +53 -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 +47 -0
- package/dist/utils/list-sources.d.ts.map +1 -0
- package/dist/utils/list-sources.js +50 -0
- package/dist/utils/list-sources.js.map +1 -0
- package/dist/utils/raw-data-utils.d.ts +131 -0
- package/dist/utils/raw-data-utils.d.ts.map +1 -0
- package/dist/utils/raw-data-utils.js +255 -0
- package/dist/utils/raw-data-utils.js.map +1 -0
- package/dist/utils/scan.d.ts +126 -0
- package/dist/utils/scan.d.ts.map +1 -0
- package/dist/utils/scan.js +221 -0
- package/dist/utils/scan.js.map +1 -0
- package/dist/utils/scope-match.d.ts +43 -0
- package/dist/utils/scope-match.d.ts.map +1 -0
- package/dist/utils/scope-match.js +87 -0
- package/dist/utils/scope-match.js.map +1 -0
- package/dist/utils/sensitive-path.d.ts +23 -0
- package/dist/utils/sensitive-path.d.ts.map +1 -0
- package/dist/utils/sensitive-path.js +91 -0
- package/dist/utils/sensitive-path.js.map +1 -0
- package/dist/utils/sync-path-key.d.ts +20 -0
- package/dist/utils/sync-path-key.d.ts.map +1 -0
- package/dist/utils/sync-path-key.js +33 -0
- package/dist/utils/sync-path-key.js.map +1 -0
- package/dist/vectordb/index.d.ts +168 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +619 -0
- package/dist/vectordb/index.js.map +1 -0
- package/dist/vectordb/search-filters.d.ts +39 -0
- package/dist/vectordb/search-filters.d.ts.map +1 -0
- package/dist/vectordb/search-filters.js +136 -0
- package/dist/vectordb/search-filters.js.map +1 -0
- package/dist/vectordb/types.d.ts +196 -0
- package/dist/vectordb/types.d.ts.map +1 -0
- package/dist/vectordb/types.js +224 -0
- package/dist/vectordb/types.js.map +1 -0
- package/package.json +105 -0
- package/skills/mcp-local-rag/SKILL.md +308 -0
- package/skills/mcp-local-rag/references/cli-reference.md +175 -0
- package/skills/mcp-local-rag/references/html-ingestion.md +78 -0
- package/skills/mcp-local-rag/references/query-optimization.md +57 -0
- package/skills/mcp-local-rag/references/result-refinement.md +56 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// HTML Parser using Readability and Turndown
|
|
2
|
+
// Extracts main content from HTML and converts to Markdown
|
|
3
|
+
import { Readability } from '@mozilla/readability';
|
|
4
|
+
import { JSDOM } from 'jsdom';
|
|
5
|
+
import TurndownService from 'turndown';
|
|
6
|
+
import { extractHtmlTitle } from './title-extractor.js';
|
|
7
|
+
// ============================================
|
|
8
|
+
// Turndown Service Configuration
|
|
9
|
+
// ============================================
|
|
10
|
+
/**
|
|
11
|
+
* Create and configure Turndown service for HTML to Markdown conversion
|
|
12
|
+
*/
|
|
13
|
+
function createTurndownService() {
|
|
14
|
+
const turndownService = new TurndownService({
|
|
15
|
+
headingStyle: 'atx', // Use # style headings
|
|
16
|
+
codeBlockStyle: 'fenced', // Use ``` for code blocks
|
|
17
|
+
bulletListMarker: '-', // Use - for bullet lists
|
|
18
|
+
emDelimiter: '_', // Use _ for emphasis
|
|
19
|
+
strongDelimiter: '**', // Use ** for bold
|
|
20
|
+
});
|
|
21
|
+
// Keep code blocks intact
|
|
22
|
+
turndownService.addRule('codeBlocks', {
|
|
23
|
+
filter: ['pre'],
|
|
24
|
+
replacement: (_content, node) => {
|
|
25
|
+
const element = node;
|
|
26
|
+
const codeElement = element.querySelector('code');
|
|
27
|
+
const code = codeElement ? codeElement.textContent : element.textContent;
|
|
28
|
+
const language = codeElement?.className?.replace('language-', '') || '';
|
|
29
|
+
return `\n\`\`\`${language}\n${code?.trim() || ''}\n\`\`\`\n`;
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
return turndownService;
|
|
33
|
+
}
|
|
34
|
+
// ============================================
|
|
35
|
+
// HTML Parser
|
|
36
|
+
// ============================================
|
|
37
|
+
/**
|
|
38
|
+
* Parse HTML content and extract main content as Markdown
|
|
39
|
+
*
|
|
40
|
+
* Flow:
|
|
41
|
+
* 1. HTML string → JSDOM (DOM creation)
|
|
42
|
+
* 2. JSDOM → Readability (main content extraction, noise removal)
|
|
43
|
+
* 3. Readability result → Turndown (Markdown conversion)
|
|
44
|
+
* 4. Title extracted separately via extractHtmlTitle (NOT prepended to content)
|
|
45
|
+
*
|
|
46
|
+
* @param html - Raw HTML string
|
|
47
|
+
* @param url - Source URL (used for resolving relative links)
|
|
48
|
+
* @returns Object with content (markdown) and title (extracted separately)
|
|
49
|
+
*/
|
|
50
|
+
export async function parseHtml(html, url) {
|
|
51
|
+
// Handle empty or whitespace-only HTML
|
|
52
|
+
if (!html || html.trim().length === 0) {
|
|
53
|
+
return { content: '', title: '' };
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
// Create DOM from HTML string
|
|
57
|
+
const dom = new JSDOM(html, {
|
|
58
|
+
url,
|
|
59
|
+
// Enable features needed for Readability
|
|
60
|
+
runScripts: 'outside-only',
|
|
61
|
+
});
|
|
62
|
+
const document = dom.window.document;
|
|
63
|
+
// Use Readability to extract main content
|
|
64
|
+
const reader = new Readability(document, {
|
|
65
|
+
keepClasses: false,
|
|
66
|
+
debug: false,
|
|
67
|
+
});
|
|
68
|
+
const article = reader.parse();
|
|
69
|
+
// If Readability couldn't extract content, fall back to body text
|
|
70
|
+
if (!article?.content) {
|
|
71
|
+
// Try to get body content directly
|
|
72
|
+
const bodyContent = document.body?.innerHTML || '';
|
|
73
|
+
if (!bodyContent.trim()) {
|
|
74
|
+
return { content: '', title: '' };
|
|
75
|
+
}
|
|
76
|
+
// Convert raw body HTML to Markdown
|
|
77
|
+
const turndownService = createTurndownService();
|
|
78
|
+
return { content: turndownService.turndown(bodyContent).trim(), title: '' };
|
|
79
|
+
}
|
|
80
|
+
// Convert extracted HTML content to Markdown
|
|
81
|
+
const turndownService = createTurndownService();
|
|
82
|
+
const markdown = turndownService.turndown(article.content);
|
|
83
|
+
// Extract title separately (NOT prepended to markdown content)
|
|
84
|
+
// Use URL-derived filename as fallback when Readability has no title
|
|
85
|
+
let urlFileName = '';
|
|
86
|
+
try {
|
|
87
|
+
urlFileName = new URL(url).pathname.split('/').filter(Boolean).pop() || '';
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Non-URL string, empty fallback
|
|
91
|
+
}
|
|
92
|
+
const titleResult = extractHtmlTitle(article.title || '', urlFileName);
|
|
93
|
+
const title = titleResult.title;
|
|
94
|
+
return { content: markdown.trim(), title };
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
// Log error but don't throw - return empty values for graceful degradation
|
|
98
|
+
console.error('Failed to parse HTML:', error);
|
|
99
|
+
return { content: '', title: '' };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=html-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-parser.js","sourceRoot":"","sources":["../../src/parser/html-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import type { Document as MupdfDocument } from 'mupdf';
|
|
2
|
+
import { type AtomicTextRange } from '../chunker/index.js';
|
|
3
|
+
import { AppError } from '../utils/errors.js';
|
|
4
|
+
import type { EmbedderInterface, FilteredTextFragment } from './pdf-filter.js';
|
|
5
|
+
/**
|
|
6
|
+
* File extensions supported by the parser module (parseFile + parsePdf).
|
|
7
|
+
* Exported so other modules (e.g. list_files) stay in sync automatically
|
|
8
|
+
* when new formats are added here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SUPPORTED_EXTENSIONS: Set<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Result from parsing a document, containing both content and extracted title.
|
|
13
|
+
* Title is display-only metadata (NOT used for search scoring).
|
|
14
|
+
*/
|
|
15
|
+
export interface ParseResult {
|
|
16
|
+
content: string;
|
|
17
|
+
title: string;
|
|
18
|
+
atomicRanges?: readonly AtomicTextRange[];
|
|
19
|
+
imageAnchors?: readonly ParsedImageAnchor[];
|
|
20
|
+
}
|
|
21
|
+
export interface ParsedImageAnchor {
|
|
22
|
+
offset: number;
|
|
23
|
+
imageIndex: number;
|
|
24
|
+
mimeType: 'image/png' | 'image/jpeg';
|
|
25
|
+
bytes: Uint8Array;
|
|
26
|
+
}
|
|
27
|
+
export interface ParseFileOptions {
|
|
28
|
+
images?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* DocumentParser configuration.
|
|
32
|
+
*
|
|
33
|
+
* Accepts either a single `baseDir` (legacy single-root shape — preserved for
|
|
34
|
+
* backward compatibility with downstream callers that have not yet migrated
|
|
35
|
+
* to the multi-root model) or a `baseDirs` array (multi-root shape produced
|
|
36
|
+
* by `resolveBaseDirs`). Exactly one of the two MUST be supplied; supplying
|
|
37
|
+
* both is rejected by the constructor so misconfiguration cannot silently
|
|
38
|
+
* pick one source over the other.
|
|
39
|
+
*
|
|
40
|
+
* Behavior under a single allowed root (`{ baseDir }` or
|
|
41
|
+
* `{ baseDirs: [oneRoot] }`) is byte-identical to the previous single-root
|
|
42
|
+
* implementation — see `validateFilePath` for the iteration contract under
|
|
43
|
+
* multiple roots.
|
|
44
|
+
*/
|
|
45
|
+
export type ParserConfig = {
|
|
46
|
+
/** Security: single allowed base directory (legacy shape). */
|
|
47
|
+
baseDir: string;
|
|
48
|
+
baseDirs?: undefined;
|
|
49
|
+
/** Maximum file size (100MB). */
|
|
50
|
+
maxFileSize: number;
|
|
51
|
+
} | {
|
|
52
|
+
/** Security: one or more allowed base directories (multi-root shape). */
|
|
53
|
+
baseDirs: readonly string[];
|
|
54
|
+
baseDir?: undefined;
|
|
55
|
+
/** Maximum file size (100MB). */
|
|
56
|
+
maxFileSize: number;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Validation error (equivalent to 400)
|
|
60
|
+
*/
|
|
61
|
+
export declare class ValidationError extends AppError {
|
|
62
|
+
constructor(message: string, cause?: Error);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* File operation error (equivalent to 500)
|
|
66
|
+
*/
|
|
67
|
+
export declare class FileOperationError extends AppError {
|
|
68
|
+
constructor(message: string, cause?: Error);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Document parser class (PDF/DOCX/TXT/MD support)
|
|
72
|
+
*
|
|
73
|
+
* Responsibilities:
|
|
74
|
+
* - File path validation (path traversal prevention)
|
|
75
|
+
* - File size validation (100MB limit)
|
|
76
|
+
* - Parse 4 formats (PDF/DOCX/TXT/MD)
|
|
77
|
+
*/
|
|
78
|
+
export declare class DocumentParser {
|
|
79
|
+
private readonly config;
|
|
80
|
+
/** Raw allowed roots in input order (pre-realpath). Always non-empty. */
|
|
81
|
+
private readonly rawBaseDirs;
|
|
82
|
+
/**
|
|
83
|
+
* Lazily cached realpath-normalized allowed roots, each with a trailing
|
|
84
|
+
* path separator so the `startsWith` check is sibling-prefix safe (e.g.
|
|
85
|
+
* `/foo/bar/` must not match `/foo/barista/x.txt`). Order is preserved
|
|
86
|
+
* from `rawBaseDirs` so the legacy single-root rejection message keeps
|
|
87
|
+
* referencing the user-configured first root. Assumes the allowed roots
|
|
88
|
+
* are stable for the process lifetime.
|
|
89
|
+
*/
|
|
90
|
+
private resolvedBaseDirs;
|
|
91
|
+
constructor(config: ParserConfig);
|
|
92
|
+
/**
|
|
93
|
+
* File path validation (Absolute path requirement + Path traversal prevention).
|
|
94
|
+
*
|
|
95
|
+
* This is THE place realpath is used (with the base-dir resolver): the
|
|
96
|
+
* security/containment boundary. Following symlinks here makes prefix
|
|
97
|
+
* containment unforgeable. Stored/scanned/looked-up paths elsewhere use
|
|
98
|
+
* resolve() — see {@link BaseDirsConfig} for the path policy.
|
|
99
|
+
*
|
|
100
|
+
* Multi-root semantics: a file is accepted iff its realpath (or, for a
|
|
101
|
+
* non-symlink path that does not yet exist, its `resolve()`-normalized
|
|
102
|
+
* absolute path) is under ANY realpath-normalized allowed root using a
|
|
103
|
+
* trailing-separator prefix check. Broken symlinks are still rejected
|
|
104
|
+
* outright — the lstat-based detection mirrors the previous single-root
|
|
105
|
+
* behavior.
|
|
106
|
+
*
|
|
107
|
+
* Under a single allowed root the behavior is identical to the previous
|
|
108
|
+
* single-root implementation.
|
|
109
|
+
*
|
|
110
|
+
* @param filePath - File path to validate (must be absolute)
|
|
111
|
+
* @throws ValidationError - When path is not absolute or outside all allowed roots
|
|
112
|
+
*/
|
|
113
|
+
validateFilePath(filePath: string): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* File size validation (100MB limit)
|
|
116
|
+
*
|
|
117
|
+
* @param filePath - File path to validate
|
|
118
|
+
* @throws ValidationError - When file size exceeds limit
|
|
119
|
+
* @throws FileOperationError - When file read fails
|
|
120
|
+
*/
|
|
121
|
+
validateFileSize(filePath: string): void;
|
|
122
|
+
/**
|
|
123
|
+
* File parsing (auto format detection)
|
|
124
|
+
*
|
|
125
|
+
* @param filePath - File path to parse
|
|
126
|
+
* @returns ParseResult with content and extracted title
|
|
127
|
+
* @throws ValidationError - Path traversal, size exceeded, unsupported format
|
|
128
|
+
* @throws FileOperationError - File read failed, parse failed
|
|
129
|
+
*/
|
|
130
|
+
parseFile(filePath: string, options?: ParseFileOptions): Promise<ParseResult>;
|
|
131
|
+
/**
|
|
132
|
+
* PDF parsing with header/footer filtering
|
|
133
|
+
*
|
|
134
|
+
* Features:
|
|
135
|
+
* - Extracts text with position information (x, y, fontSize)
|
|
136
|
+
* - Semantic header/footer detection using embedding similarity
|
|
137
|
+
* - Uses hasEOL for proper line break handling
|
|
138
|
+
* - Extracts document title from PDF metadata and first page font heuristic
|
|
139
|
+
*
|
|
140
|
+
* @param filePath - PDF file path
|
|
141
|
+
* @param embedder - Embedder for semantic header/footer detection
|
|
142
|
+
* @returns ParseResult with content and extracted title
|
|
143
|
+
* @throws FileOperationError - File read failed, parse failed
|
|
144
|
+
*/
|
|
145
|
+
parsePdf(filePath: string, embedder: EmbedderInterface): Promise<ParseResult>;
|
|
146
|
+
/**
|
|
147
|
+
* Per-page PDF parsing for the visual-enrichment path.
|
|
148
|
+
*
|
|
149
|
+
* Opens a mupdf `Document`, delegates per-page extraction to the shared
|
|
150
|
+
* `extractPdfPages` helper with the `'preserve-whitespace,preserve-images'`
|
|
151
|
+
* stext option string so mupdf emits `block.type === 'image'` blocks for
|
|
152
|
+
* the downstream visual-candidate detector.
|
|
153
|
+
*
|
|
154
|
+
* Returns the open `Document` handle alongside the per-page records and
|
|
155
|
+
* title-resolution materials so the caller can:
|
|
156
|
+
* - run the renderer (`page.toPixmap()`) on the same handle,
|
|
157
|
+
* - feed `metadataTitle` + `pages[0].page1FontHint` into `extractPdfTitle`
|
|
158
|
+
* after `buildChunksAndEmbeddings` returns.
|
|
159
|
+
*
|
|
160
|
+
* Disposal contract (asymmetric — read carefully):
|
|
161
|
+
* - SUCCESS path: this method returns the open `doc` handle. The caller
|
|
162
|
+
* owns disposal and MUST wrap the call site in
|
|
163
|
+
* `try { ... } finally { doc.destroy() }`.
|
|
164
|
+
* - ERROR path: when this method throws, `doc` has already been destroyed
|
|
165
|
+
* internally before the exception propagates (so the caller never
|
|
166
|
+
* receives a handle it would not know to clean up). Callers MUST NOT
|
|
167
|
+
* call `doc.destroy()` on an error from this method.
|
|
168
|
+
* Title resolution stays here so visual captions cannot change PDF metadata.
|
|
169
|
+
* Visual candidate selection remains `pdf-visual/detector`'s responsibility.
|
|
170
|
+
*
|
|
171
|
+
* @param filePath - PDF file path (validated against BASE_DIR and size limit)
|
|
172
|
+
* @param embedder - Embedder for semantic header/footer detection
|
|
173
|
+
* @returns Open mupdf `Document`, resolved title, and per-page text/layout records.
|
|
174
|
+
* @throws ValidationError - Path traversal, size exceeded
|
|
175
|
+
* @throws FileOperationError - File read or parse failed (after destroying `doc` internally)
|
|
176
|
+
*/
|
|
177
|
+
parsePdfPages(filePath: string, embedder: EmbedderInterface): Promise<{
|
|
178
|
+
doc: MupdfDocument;
|
|
179
|
+
title: string;
|
|
180
|
+
pages: Array<{
|
|
181
|
+
pageNum: number;
|
|
182
|
+
text: string;
|
|
183
|
+
textFragments: FilteredTextFragment[];
|
|
184
|
+
stextJson: unknown;
|
|
185
|
+
}>;
|
|
186
|
+
}>;
|
|
187
|
+
/**
|
|
188
|
+
* DOCX parsing (using mammoth)
|
|
189
|
+
*
|
|
190
|
+
* Uses DOCX package metadata plus one Mammoth HTML conversion for title and body extraction.
|
|
191
|
+
*
|
|
192
|
+
* @param filePath - DOCX file path
|
|
193
|
+
* @returns ParseResult with content and extracted title
|
|
194
|
+
* @throws FileOperationError - File read failed, parse failed
|
|
195
|
+
*/
|
|
196
|
+
private parseDocx;
|
|
197
|
+
/**
|
|
198
|
+
* TXT parsing (using fs.readFile)
|
|
199
|
+
*
|
|
200
|
+
* @param filePath - TXT file path
|
|
201
|
+
* @returns ParseResult with content and extracted title
|
|
202
|
+
* @throws FileOperationError - File read failed
|
|
203
|
+
*/
|
|
204
|
+
private parseTxt;
|
|
205
|
+
/**
|
|
206
|
+
* MD parsing (using fs.readFile)
|
|
207
|
+
*
|
|
208
|
+
* @param filePath - MD file path
|
|
209
|
+
* @returns ParseResult with content and extracted title
|
|
210
|
+
* @throws FileOperationError - File read failed
|
|
211
|
+
*/
|
|
212
|
+
private parseMd;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"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"}
|