@chnxthr/knowledge-mcp 0.0.0-stage → 0.3.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.md +37 -2
- package/dist/bootstrap.d.ts +1 -0
- package/dist/bootstrap.js +18 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +5 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/auth.d.ts +38 -0
- package/dist/core/auth.js +93 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/config.d.ts +259 -0
- package/dist/core/config.js +172 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +25 -0
- package/dist/core/context.js +37 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/env.d.ts +2 -0
- package/dist/core/env.js +5 -0
- package/dist/core/env.js.map +1 -0
- package/dist/core/log_mask.d.ts +10 -0
- package/dist/core/log_mask.js +88 -0
- package/dist/core/log_mask.js.map +1 -0
- package/dist/core/oauth.d.ts +46 -0
- package/dist/core/oauth.js +507 -0
- package/dist/core/oauth.js.map +1 -0
- package/dist/core/paths.d.ts +5 -0
- package/dist/core/paths.js +47 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/scope.d.ts +28 -0
- package/dist/core/scope.js +54 -0
- package/dist/core/scope.js.map +1 -0
- package/dist/core/upstream.d.ts +30 -0
- package/dist/core/upstream.js +164 -0
- package/dist/core/upstream.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/define.d.ts +144 -0
- package/dist/plugin/define.js +44 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/load.d.ts +2 -0
- package/dist/plugin/load.js +41 -0
- package/dist/plugin/load.js.map +1 -0
- package/dist/plugin/ping.d.ts +9 -0
- package/dist/plugin/ping.js +29 -0
- package/dist/plugin/ping.js.map +1 -0
- package/dist/plugin/registry.d.ts +62 -0
- package/dist/plugin/registry.js +248 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/result.d.ts +20 -0
- package/dist/plugin/result.js +59 -0
- package/dist/plugin/result.js.map +1 -0
- package/dist/plugins/drive/chunker.d.ts +28 -0
- package/dist/plugins/drive/chunker.js +356 -0
- package/dist/plugins/drive/chunker.js.map +1 -0
- package/dist/plugins/drive/clean_text.d.ts +13 -0
- package/dist/plugins/drive/clean_text.js +31 -0
- package/dist/plugins/drive/clean_text.js.map +1 -0
- package/dist/plugins/drive/client.d.ts +25 -0
- package/dist/plugins/drive/client.js +62 -0
- package/dist/plugins/drive/client.js.map +1 -0
- package/dist/plugins/drive/embeddings.d.ts +15 -0
- package/dist/plugins/drive/embeddings.js +118 -0
- package/dist/plugins/drive/embeddings.js.map +1 -0
- package/dist/plugins/drive/exclude.d.ts +11 -0
- package/dist/plugins/drive/exclude.js +36 -0
- package/dist/plugins/drive/exclude.js.map +1 -0
- package/dist/plugins/drive/extract_text.d.ts +26 -0
- package/dist/plugins/drive/extract_text.js +108 -0
- package/dist/plugins/drive/extract_text.js.map +1 -0
- package/dist/plugins/drive/get_token.d.ts +5 -0
- package/dist/plugins/drive/get_token.js +113 -0
- package/dist/plugins/drive/get_token.js.map +1 -0
- package/dist/plugins/drive/index.d.ts +5 -0
- package/dist/plugins/drive/index.js +72 -0
- package/dist/plugins/drive/index.js.map +1 -0
- package/dist/plugins/drive/indexer.d.ts +69 -0
- package/dist/plugins/drive/indexer.js +204 -0
- package/dist/plugins/drive/indexer.js.map +1 -0
- package/dist/plugins/drive/mathpix.d.ts +4 -0
- package/dist/plugins/drive/mathpix.js +102 -0
- package/dist/plugins/drive/mathpix.js.map +1 -0
- package/dist/plugins/drive/path.d.ts +40 -0
- package/dist/plugins/drive/path.js +87 -0
- package/dist/plugins/drive/path.js.map +1 -0
- package/dist/plugins/drive/qdrant.d.ts +50 -0
- package/dist/plugins/drive/qdrant.js +61 -0
- package/dist/plugins/drive/qdrant.js.map +1 -0
- package/dist/plugins/drive/reindex.d.ts +2 -0
- package/dist/plugins/drive/reindex.js +263 -0
- package/dist/plugins/drive/reindex.js.map +1 -0
- package/dist/plugins/drive/settings.d.ts +11 -0
- package/dist/plugins/drive/settings.js +13 -0
- package/dist/plugins/drive/settings.js.map +1 -0
- package/dist/plugins/drive/sync.d.ts +16 -0
- package/dist/plugins/drive/sync.js +139 -0
- package/dist/plugins/drive/sync.js.map +1 -0
- package/dist/plugins/drive/sync_state.d.ts +3 -0
- package/dist/plugins/drive/sync_state.js +26 -0
- package/dist/plugins/drive/sync_state.js.map +1 -0
- package/dist/plugins/drive/tools/list_drive_folder.d.ts +104 -0
- package/dist/plugins/drive/tools/list_drive_folder.js +221 -0
- package/dist/plugins/drive/tools/list_drive_folder.js.map +1 -0
- package/dist/plugins/drive/tools/read_drive_file.d.ts +66 -0
- package/dist/plugins/drive/tools/read_drive_file.js +206 -0
- package/dist/plugins/drive/tools/read_drive_file.js.map +1 -0
- package/dist/plugins/drive/tools/search_drive.d.ts +52 -0
- package/dist/plugins/drive/tools/search_drive.js +78 -0
- package/dist/plugins/drive/tools/search_drive.js.map +1 -0
- package/dist/plugins/drive/tools/semantic_search_drive.d.ts +109 -0
- package/dist/plugins/drive/tools/semantic_search_drive.js +228 -0
- package/dist/plugins/drive/tools/semantic_search_drive.js.map +1 -0
- package/dist/plugins/github/index.d.ts +1 -0
- package/dist/plugins/github/index.js +27 -0
- package/dist/plugins/github/index.js.map +1 -0
- package/dist/plugins/github/repo_tree.d.ts +57 -0
- package/dist/plugins/github/repo_tree.js +123 -0
- package/dist/plugins/github/repo_tree.js.map +1 -0
- package/dist/plugins/index.d.ts +11 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/railway/index.d.ts +1 -0
- package/dist/plugins/railway/index.js +21 -0
- package/dist/plugins/railway/index.js.map +1 -0
- package/dist/plugins/railway/tools.d.ts +114 -0
- package/dist/plugins/railway/tools.js +165 -0
- package/dist/plugins/railway/tools.js.map +1 -0
- package/dist/plugins/slack/api.d.ts +63 -0
- package/dist/plugins/slack/api.js +280 -0
- package/dist/plugins/slack/api.js.map +1 -0
- package/dist/plugins/slack/index.d.ts +1 -0
- package/dist/plugins/slack/index.js +80 -0
- package/dist/plugins/slack/index.js.map +1 -0
- package/dist/plugins/slack/tools/slack_files.d.ts +87 -0
- package/dist/plugins/slack/tools/slack_files.js +204 -0
- package/dist/plugins/slack/tools/slack_files.js.map +1 -0
- package/dist/plugins/slack/tools/slack_list_channels.d.ts +46 -0
- package/dist/plugins/slack/tools/slack_list_channels.js +197 -0
- package/dist/plugins/slack/tools/slack_list_channels.js.map +1 -0
- package/dist/plugins/slack/tools/slack_read_channel.d.ts +56 -0
- package/dist/plugins/slack/tools/slack_read_channel.js +150 -0
- package/dist/plugins/slack/tools/slack_read_channel.js.map +1 -0
- package/dist/plugins/slack/tools/slack_search.d.ts +53 -0
- package/dist/plugins/slack/tools/slack_search.js +132 -0
- package/dist/plugins/slack/tools/slack_search.js.map +1 -0
- package/dist/run.d.ts +8 -0
- package/dist/run.js +270 -0
- package/dist/run.js.map +1 -0
- package/dist/server/http.d.ts +5 -0
- package/dist/server/http.js +406 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/identity.d.ts +17 -0
- package/dist/server/identity.js +47 -0
- package/dist/server/identity.js.map +1 -0
- package/dist/server/mcp.d.ts +7 -0
- package/dist/server/mcp.js +55 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/server/stdio.d.ts +2 -0
- package/dist/server/stdio.js +40 -0
- package/dist/server/stdio.js.map +1 -0
- package/dist/store/index.d.ts +11 -0
- package/dist/store/index.js +31 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/keys.d.ts +9 -0
- package/dist/store/keys.js +32 -0
- package/dist/store/keys.js.map +1 -0
- package/dist/store/sqlite.d.ts +38 -0
- package/dist/store/sqlite.js +316 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/supabase.d.ts +35 -0
- package/dist/store/supabase.js +269 -0
- package/dist/store/supabase.js.map +1 -0
- package/dist/store/supabase_client.d.ts +10 -0
- package/dist/store/supabase_client.js +31 -0
- package/dist/store/supabase_client.js.map +1 -0
- package/dist/store/tool_log.d.ts +12 -0
- package/dist/store/tool_log.js +8 -0
- package/dist/store/tool_log.js.map +1 -0
- package/dist/store/types.d.ts +96 -0
- package/dist/store/types.js +2 -0
- package/dist/store/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +84 -4
- package/sql/supabase.sql +185 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../../src/plugins/drive/embeddings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Normalized form used for every exclusion comparison. */
|
|
2
|
+
export declare function normalizeFolderName(name: string): string;
|
|
3
|
+
/** Merged exclusion set (normalized): built-in dev artifacts + configured sensitive folders. */
|
|
4
|
+
export declare const EXCLUDED_FOLDER_NAMES: Set<string>;
|
|
5
|
+
/** True if this single folder name is excluded. */
|
|
6
|
+
export declare function isExcludedName(name: string | null | undefined): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* True if any path segment matches an excluded folder name.
|
|
9
|
+
* Segment-wise (not includes()) so e.g. "rebuild.md" doesn't match "build".
|
|
10
|
+
*/
|
|
11
|
+
export declare function isExcludedPath(path: string): boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search-index folder exclusions — single source of truth.
|
|
3
|
+
*
|
|
4
|
+
* Shared by full reindex (reindex.ts), incremental sync (sync.ts) and the read/list/search
|
|
5
|
+
* tools (path.ts). Two buckets:
|
|
6
|
+
* 1. Built-in dev artifacts (node_modules, .git, build outputs) — always excluded so whole code
|
|
7
|
+
* projects in Drive don't flood the index with library-doc noise.
|
|
8
|
+
* 2. Configured sensitive folders (config.drive.excludeFolders) — your PII/contract/HR/backup folders.
|
|
9
|
+
*
|
|
10
|
+
* Names are compared after normalization (Unicode NFC, trimmed, lower-cased). Drive keeps whatever form the
|
|
11
|
+
* uploader sent, so a macOS-uploaded Korean folder name can arrive as NFD and "HR " or "hr" must still match.
|
|
12
|
+
*/
|
|
13
|
+
import { getConfig } from '../../core/config.js';
|
|
14
|
+
const BUILTIN_EXCLUDES = [
|
|
15
|
+
'node_modules', '.git', '.next', '.nuxt', '.svelte-kit',
|
|
16
|
+
'dist', 'build', 'coverage', '.cache', '.turbo', '.parcel-cache',
|
|
17
|
+
'__pycache__', '.venv', 'venv', '.pytest_cache', '.mypy_cache',
|
|
18
|
+
];
|
|
19
|
+
/** Normalized form used for every exclusion comparison. */
|
|
20
|
+
export function normalizeFolderName(name) {
|
|
21
|
+
return name.normalize('NFC').trim().toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
/** Merged exclusion set (normalized): built-in dev artifacts + configured sensitive folders. */
|
|
24
|
+
export const EXCLUDED_FOLDER_NAMES = new Set([...BUILTIN_EXCLUDES, ...getConfig().drive.excludeFolders].map(normalizeFolderName));
|
|
25
|
+
/** True if this single folder name is excluded. */
|
|
26
|
+
export function isExcludedName(name) {
|
|
27
|
+
return !!name && EXCLUDED_FOLDER_NAMES.has(normalizeFolderName(name));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* True if any path segment matches an excluded folder name.
|
|
31
|
+
* Segment-wise (not includes()) so e.g. "rebuild.md" doesn't match "build".
|
|
32
|
+
*/
|
|
33
|
+
export function isExcludedPath(path) {
|
|
34
|
+
return path.split('/').some((seg) => isExcludedName(seg));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=exclude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclude.js","sourceRoot":"","sources":["../../../src/plugins/drive/exclude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,gBAAgB,GAAG;IACvB,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa;IACvD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe;IAChE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa;CAC/D,CAAC;AAEF,2DAA2D;AAC3D,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpD,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAC1C,CAAC,GAAG,gBAAgB,EAAE,GAAG,SAAS,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CACpF,CAAC;AAEF,mDAAmD;AACnD,MAAM,UAAU,cAAc,CAAC,IAA+B;IAC5D,OAAO,CAAC,CAAC,IAAI,IAAI,qBAAqB,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 문서 형식별 텍스트 추출 router. 벡터 색인 전처리.
|
|
3
|
+
*
|
|
4
|
+
* 무료 추출 (OCR 불필요):
|
|
5
|
+
* - text/markdown, text/plain → 그대로
|
|
6
|
+
* - Google Docs → Drive export text/markdown
|
|
7
|
+
* - Google Sheets → Drive export text/csv
|
|
8
|
+
* - Google Slides → Drive export text/plain
|
|
9
|
+
* - Word .docx → mammoth (텍스트 레이어)
|
|
10
|
+
* - PDF (digital) → pdf-parse (텍스트 레이어)
|
|
11
|
+
*
|
|
12
|
+
* OCR 필요 (후속 — Mathpix):
|
|
13
|
+
* - PDF (스캔본, 텍스트 부족) → Mathpix
|
|
14
|
+
* - .pptx / image → Mathpix / Gemini multimodal
|
|
15
|
+
*
|
|
16
|
+
* lazy import (mammoth/pdf-parse) — 필요 시에만 로드.
|
|
17
|
+
*/
|
|
18
|
+
import type { drive_v3 } from 'googleapis';
|
|
19
|
+
export interface ExtractResult {
|
|
20
|
+
text: string;
|
|
21
|
+
method: string;
|
|
22
|
+
needsOcr?: boolean;
|
|
23
|
+
meta?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/** 추출 + 정제 (노이즈 cleanup). 색인·검색 진입점. */
|
|
26
|
+
export declare function extractText(drive: drive_v3.Drive, fileId: string, mimeType: string): Promise<ExtractResult>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { cleanExtractedText } from './clean_text.js';
|
|
2
|
+
/** 스캔본 판정 threshold — 페이지당 평균 글자 수 */
|
|
3
|
+
const MIN_CHARS_PER_PAGE = 80;
|
|
4
|
+
async function downloadText(drive, fileId) {
|
|
5
|
+
const r = await drive.files.get({ fileId, alt: 'media', supportsAllDrives: true }, { responseType: 'text' });
|
|
6
|
+
return r.data;
|
|
7
|
+
}
|
|
8
|
+
async function downloadBuffer(drive, fileId) {
|
|
9
|
+
const r = await drive.files.get({ fileId, alt: 'media', supportsAllDrives: true }, { responseType: 'arraybuffer' });
|
|
10
|
+
return Buffer.from(r.data);
|
|
11
|
+
}
|
|
12
|
+
async function exportGoogle(drive, fileId, mimeType) {
|
|
13
|
+
const r = await drive.files.export({ fileId, mimeType }, { responseType: 'text' });
|
|
14
|
+
return r.data;
|
|
15
|
+
}
|
|
16
|
+
/** 추출 + 정제 (노이즈 cleanup). 색인·검색 진입점. */
|
|
17
|
+
export async function extractText(drive, fileId, mimeType) {
|
|
18
|
+
const raw = await extractRaw(drive, fileId, mimeType);
|
|
19
|
+
return { ...raw, text: cleanExtractedText(raw.text) };
|
|
20
|
+
}
|
|
21
|
+
/** 형식별 원본 추출 (정제 전). */
|
|
22
|
+
async function extractRaw(drive, fileId, mimeType) {
|
|
23
|
+
// 1. Native text
|
|
24
|
+
if (mimeType === 'text/markdown' || mimeType === 'text/plain') {
|
|
25
|
+
return { text: await downloadText(drive, fileId), method: 'native' };
|
|
26
|
+
}
|
|
27
|
+
// 2. Google Workspace — Drive export (무료)
|
|
28
|
+
if (mimeType === 'application/vnd.google-apps.document') {
|
|
29
|
+
return { text: await exportGoogle(drive, fileId, 'text/markdown'), method: 'gdoc→md' };
|
|
30
|
+
}
|
|
31
|
+
if (mimeType === 'application/vnd.google-apps.spreadsheet') {
|
|
32
|
+
return { text: await exportGoogle(drive, fileId, 'text/csv'), method: 'gsheet→csv' };
|
|
33
|
+
}
|
|
34
|
+
if (mimeType === 'application/vnd.google-apps.presentation') {
|
|
35
|
+
return { text: await exportGoogle(drive, fileId, 'text/plain'), method: 'gslide→txt' };
|
|
36
|
+
}
|
|
37
|
+
// 3. Word .docx — mammoth (텍스트 레이어)
|
|
38
|
+
if (mimeType.includes('wordprocessingml')) {
|
|
39
|
+
const mammoth = (await import('mammoth')).default ?? (await import('mammoth'));
|
|
40
|
+
const buffer = await downloadBuffer(drive, fileId);
|
|
41
|
+
const result = await mammoth.extractRawText({ buffer });
|
|
42
|
+
return { text: result.value, method: 'docx→mammoth' };
|
|
43
|
+
}
|
|
44
|
+
// 4. PDF — pdf-parse v2. digital 텍스트, 스캔본(<MIN) 은 Mathpix OCR fallback
|
|
45
|
+
if (mimeType === 'application/pdf') {
|
|
46
|
+
const buffer = await downloadBuffer(drive, fileId);
|
|
47
|
+
const { PDFParse } = (await import('pdf-parse'));
|
|
48
|
+
const parser = new PDFParse({ data: new Uint8Array(buffer) });
|
|
49
|
+
let text = '';
|
|
50
|
+
let pages = 1;
|
|
51
|
+
try {
|
|
52
|
+
const result = await parser.getText();
|
|
53
|
+
text = result.text ?? '';
|
|
54
|
+
pages = result.total ?? 1;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await parser.destroy();
|
|
58
|
+
}
|
|
59
|
+
const charsPerPage = text.replace(/\s/g, '').length / Math.max(pages, 1);
|
|
60
|
+
if (charsPerPage >= MIN_CHARS_PER_PAGE) {
|
|
61
|
+
return { text, method: 'pdf-parse', meta: { pages, charsPerPage: Math.round(charsPerPage) } };
|
|
62
|
+
}
|
|
63
|
+
// 스캔본 → Mathpix OCR
|
|
64
|
+
const { mathpixPdfToMarkdown } = await import('./mathpix.js');
|
|
65
|
+
const md = await mathpixPdfToMarkdown(buffer);
|
|
66
|
+
return {
|
|
67
|
+
text: md,
|
|
68
|
+
method: 'pdf→mathpix-ocr',
|
|
69
|
+
meta: { pages, charsPerPage: Math.round(charsPerPage), ocr: true },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// 5. PowerPoint .pptx → officeparser (슬라이드 텍스트)
|
|
73
|
+
// v7 parseOffice 는 OfficeParserAST 반환 → markdown(.to('md')) 우선, 실패 시 toText().
|
|
74
|
+
if (mimeType.includes('presentationml')) {
|
|
75
|
+
const { parseOffice } = await import('officeparser');
|
|
76
|
+
const buffer = await downloadBuffer(drive, fileId);
|
|
77
|
+
const ast = (await parseOffice(buffer));
|
|
78
|
+
let text = '';
|
|
79
|
+
try {
|
|
80
|
+
const md = await ast.to('md');
|
|
81
|
+
text = md?.value ?? '';
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* md 변환 실패 → toText fallback */
|
|
85
|
+
}
|
|
86
|
+
if (!text.trim())
|
|
87
|
+
text = ast.toText();
|
|
88
|
+
return { text, method: 'pptx→officeparser' };
|
|
89
|
+
}
|
|
90
|
+
// 6. Excel .xlsx → SheetJS (시트별 csv)
|
|
91
|
+
if (mimeType.includes('spreadsheetml')) {
|
|
92
|
+
const XLSX = await import('xlsx');
|
|
93
|
+
const buffer = await downloadBuffer(drive, fileId);
|
|
94
|
+
const wb = XLSX.read(buffer, { type: 'buffer' });
|
|
95
|
+
const text = wb.SheetNames.map((n) => `## ${n}\n${XLSX.utils.sheet_to_csv(wb.Sheets[n])}`).join('\n\n');
|
|
96
|
+
return { text, method: 'xlsx→sheetjs' };
|
|
97
|
+
}
|
|
98
|
+
// 7. 이미지 → Mathpix OCR (v3/text, 즉시)
|
|
99
|
+
if (mimeType.startsWith('image/')) {
|
|
100
|
+
const buffer = await downloadBuffer(drive, fileId);
|
|
101
|
+
const { mathpixImageToMarkdown } = await import('./mathpix.js');
|
|
102
|
+
const md = await mathpixImageToMarkdown(buffer, mimeType);
|
|
103
|
+
return { text: md, method: 'image→mathpix' };
|
|
104
|
+
}
|
|
105
|
+
// 8. 미지원
|
|
106
|
+
return { text: '', method: `unsupported:${mimeType}`, needsOcr: true };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=extract_text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract_text.js","sourceRoot":"","sources":["../../../src/plugins/drive/extract_text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google OAuth Refresh Token 발급 자동화.
|
|
3
|
+
*
|
|
4
|
+
* 사용법:
|
|
5
|
+
* 1. .env 에 GOOGLE_OAUTH_CLIENT_ID + GOOGLE_OAUTH_CLIENT_SECRET 채워둠
|
|
6
|
+
* 2. (OAuth Client type 이 Web 이면) Cloud Console → Credentials →
|
|
7
|
+
* OAuth Client → Authorized redirect URIs 에 추가:
|
|
8
|
+
* http://localhost:3500/callback
|
|
9
|
+
* 3. knowledge-mcp drive get-token
|
|
10
|
+
* 4. browser opens -> sign in with your Google account + allow
|
|
11
|
+
* 5. callback 받으면 콘솔에 refresh token 출력
|
|
12
|
+
* 6. .env 에 GOOGLE_OAUTH_REFRESH_TOKEN= 라인 추가
|
|
13
|
+
*/
|
|
14
|
+
import { google } from 'googleapis';
|
|
15
|
+
import http from 'http';
|
|
16
|
+
import { URL } from 'url';
|
|
17
|
+
import { execFile } from 'child_process';
|
|
18
|
+
const PORT = 3500;
|
|
19
|
+
const REDIRECT_URI = `http://localhost:${PORT}/callback`;
|
|
20
|
+
const SCOPE = 'https://www.googleapis.com/auth/drive.readonly';
|
|
21
|
+
/**
|
|
22
|
+
* `knowledge-mcp drive get-token` — opens Google sign-in and prints a Drive refresh token.
|
|
23
|
+
* The token is written with process.stdout.write: console output is masked and would hide it.
|
|
24
|
+
*/
|
|
25
|
+
export async function runGetToken() {
|
|
26
|
+
const clientId = process.env.GOOGLE_OAUTH_CLIENT_ID;
|
|
27
|
+
const clientSecret = process.env.GOOGLE_OAUTH_CLIENT_SECRET;
|
|
28
|
+
if (!clientId || !clientSecret) {
|
|
29
|
+
console.error('❌ GOOGLE_OAUTH_CLIENT_ID / CLIENT_SECRET 가 .env 에 없습니다.');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
const oauth = new google.auth.OAuth2(clientId, clientSecret, REDIRECT_URI);
|
|
33
|
+
const authUrl = oauth.generateAuthUrl({
|
|
34
|
+
access_type: 'offline',
|
|
35
|
+
prompt: 'consent', // refresh_token 강제 발급
|
|
36
|
+
scope: [SCOPE],
|
|
37
|
+
});
|
|
38
|
+
console.log('\n========================================');
|
|
39
|
+
console.log(' OAuth Refresh Token 발급');
|
|
40
|
+
console.log('========================================\n');
|
|
41
|
+
console.log('1. Local callback server: http://localhost:' + PORT);
|
|
42
|
+
console.log('2. 브라우저 자동 열림 (또는 아래 URL 수동 접속):');
|
|
43
|
+
console.log('\n' + authUrl + '\n');
|
|
44
|
+
console.log('3. Sign in with your Google account and allow access');
|
|
45
|
+
console.log('4. 자동 redirect 후 콘솔에 refresh token 출력\n');
|
|
46
|
+
const server = http.createServer(async (req, res) => {
|
|
47
|
+
if (!req.url?.startsWith('/callback')) {
|
|
48
|
+
res.writeHead(404);
|
|
49
|
+
res.end();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
53
|
+
const code = url.searchParams.get('code');
|
|
54
|
+
const error = url.searchParams.get('error');
|
|
55
|
+
if (error) {
|
|
56
|
+
res.writeHead(400, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
57
|
+
res.end(`OAuth error: ${error}`);
|
|
58
|
+
console.error('\n❌ OAuth error:', error);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
if (!code) {
|
|
62
|
+
res.writeHead(400);
|
|
63
|
+
res.end('No code received');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const { tokens } = await oauth.getToken(code);
|
|
68
|
+
const refreshToken = tokens.refresh_token;
|
|
69
|
+
if (!refreshToken) {
|
|
70
|
+
console.error('\n❌ refresh_token 미발급. 이미 권한 부여한 경우 일 수 있음.');
|
|
71
|
+
console.error(' 해결: https://myaccount.google.com/connections 에서');
|
|
72
|
+
console.error(' client 제거 후 다시 시도.\n');
|
|
73
|
+
res.writeHead(400);
|
|
74
|
+
res.end('No refresh_token in response');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
console.log('\n========================================');
|
|
78
|
+
console.log(' ✅ 발급 성공');
|
|
79
|
+
console.log('========================================\n');
|
|
80
|
+
console.log('.env 에 다음 라인 추가:\n');
|
|
81
|
+
process.stdout.write(`GOOGLE_OAUTH_REFRESH_TOKEN=${refreshToken}\n\n`);
|
|
82
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
83
|
+
res.end(`<!doctype html><html><body style="font-family:sans-serif;padding:40px;">
|
|
84
|
+
<h2>✅ Refresh Token 발급 완료</h2>
|
|
85
|
+
<p>터미널에서 token 을 확인하고 <code>.env</code> 에 추가하세요.</p>
|
|
86
|
+
<p>이 창은 닫으셔도 됩니다.</p>
|
|
87
|
+
</body></html>`);
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
server.close();
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}, 1000);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
95
|
+
console.error('\n❌ Token exchange failed:', msg);
|
|
96
|
+
res.writeHead(500);
|
|
97
|
+
res.end(`Error: ${msg}`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
server.listen(PORT, () => {
|
|
102
|
+
console.log(`✓ Server listening on :${PORT}\n`);
|
|
103
|
+
// 브라우저 자동 열기 (macOS open, Linux xdg-open, Windows start)
|
|
104
|
+
const opener = process.platform === 'darwin' ? ['open', [authUrl]] : process.platform === 'win32' ? ['cmd', ['/c', 'start', '', authUrl]] : ['xdg-open', [authUrl]];
|
|
105
|
+
execFile(opener[0], opener[1], (err) => {
|
|
106
|
+
if (err) {
|
|
107
|
+
console.log('(브라우저 자동 열기 실패. 위 URL 을 수동 복사하세요)');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
await new Promise(() => { }); // 콜백이 process.exit 로 끝낸다
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=get_token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_token.js","sourceRoot":"","sources":["../../../src/plugins/drive/get_token.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Drive API credentials present. Matches client.ts. */
|
|
2
|
+
export declare function driveConfigured(): boolean;
|
|
3
|
+
/** semantic_search_drive — Qdrant (vectors) and OpenAI (embeddings). Independent of the Drive API credentials. */
|
|
4
|
+
export declare function semanticConfigured(): boolean;
|
|
5
|
+
export declare const drivePlugin: import("../../plugin/define.js").Plugin;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Drive plugin — keyword search, read, folder listing, and semantic (vector) search.
|
|
3
|
+
*
|
|
4
|
+
* Credentials (any one):
|
|
5
|
+
* GOOGLE_SERVICE_ACCOUNT_KEY (JSON) | GOOGLE_APPLICATION_CREDENTIALS (file path)
|
|
6
|
+
* | GOOGLE_OAUTH_CLIENT_ID + GOOGLE_OAUTH_CLIENT_SECRET + GOOGLE_OAUTH_REFRESH_TOKEN
|
|
7
|
+
* Semantic search also needs QDRANT_URL and OPENAI_API_KEY, and an index (`knowledge-mcp drive reindex`).
|
|
8
|
+
* Scope comes from the config file: drive.roots (folders to search) and drive.excludeFolders.
|
|
9
|
+
*/
|
|
10
|
+
import { definePlugin } from '../../plugin/define.js';
|
|
11
|
+
import { isSet as has } from '../../core/env.js';
|
|
12
|
+
import { searchDriveTool } from './tools/search_drive.js';
|
|
13
|
+
import { readDriveFileTool } from './tools/read_drive_file.js';
|
|
14
|
+
import { listDriveFolderTool } from './tools/list_drive_folder.js';
|
|
15
|
+
import { semanticSearchDriveTool } from './tools/semantic_search_drive.js';
|
|
16
|
+
/** Drive API credentials present. Matches client.ts. */
|
|
17
|
+
export function driveConfigured() {
|
|
18
|
+
if (has(process.env.GOOGLE_SERVICE_ACCOUNT_KEY))
|
|
19
|
+
return true;
|
|
20
|
+
if (has(process.env.GOOGLE_APPLICATION_CREDENTIALS))
|
|
21
|
+
return true;
|
|
22
|
+
const id = process.env.GOOGLE_OAUTH_CLIENT_ID || process.env.DRIVE_CLIENT_ID;
|
|
23
|
+
const secret = process.env.GOOGLE_OAUTH_CLIENT_SECRET || process.env.DRIVE_CLIENT_SECRET;
|
|
24
|
+
const refresh = process.env.GOOGLE_OAUTH_REFRESH_TOKEN || process.env.DRIVE_REFRESH_TOKEN;
|
|
25
|
+
return has(id) && has(secret) && has(refresh);
|
|
26
|
+
}
|
|
27
|
+
/** semantic_search_drive — Qdrant (vectors) and OpenAI (embeddings). Independent of the Drive API credentials. */
|
|
28
|
+
export function semanticConfigured() {
|
|
29
|
+
return has(process.env.QDRANT_URL) && has(process.env.OPENAI_API_KEY);
|
|
30
|
+
}
|
|
31
|
+
const DRIVE_CREDS = 'set GOOGLE_SERVICE_ACCOUNT_KEY, GOOGLE_APPLICATION_CREDENTIALS or GOOGLE_OAUTH_CLIENT_ID/SECRET/REFRESH_TOKEN';
|
|
32
|
+
const driveOnly = () => driveConfigured() || DRIVE_CREDS;
|
|
33
|
+
export const drivePlugin = definePlugin({
|
|
34
|
+
id: 'drive',
|
|
35
|
+
description: 'Google Drive search, read and semantic search',
|
|
36
|
+
// On when either half works: the Drive API tools, or semantic search over an existing index.
|
|
37
|
+
enabled: () => driveConfigured() || semanticConfigured() || `${DRIVE_CREDS} (or QDRANT_URL + OPENAI_API_KEY)`,
|
|
38
|
+
tools: [
|
|
39
|
+
{ ...searchDriveTool, enabled: driveOnly },
|
|
40
|
+
{ ...readDriveFileTool, enabled: driveOnly },
|
|
41
|
+
{ ...listDriveFolderTool, enabled: driveOnly },
|
|
42
|
+
{ ...semanticSearchDriveTool, enabled: () => semanticConfigured() || 'missing env QDRANT_URL, OPENAI_API_KEY' },
|
|
43
|
+
],
|
|
44
|
+
instructions: 'Drive: meaning/concept questions → semantic_search_drive; keyword or file name → search_drive; ' +
|
|
45
|
+
'"list all" / folder contents → list_drive_folder(folderName). When a chunk lacks context, read_drive_file with the File ID ' +
|
|
46
|
+
'(fileIds=[...] reads several at once).',
|
|
47
|
+
async start({ log }) {
|
|
48
|
+
// Incremental Drive → Qdrant sync. Needs both halves and is skipped with DRIVE_SYNC_ENABLED=false.
|
|
49
|
+
if (!process.env.QDRANT_URL || process.env.DRIVE_SYNC_ENABLED === 'false' || !driveConfigured())
|
|
50
|
+
return;
|
|
51
|
+
const { ensureCollection } = await import('./qdrant.js');
|
|
52
|
+
const { startDriveSyncScheduler } = await import('./sync.js');
|
|
53
|
+
try {
|
|
54
|
+
await ensureCollection(); // a fresh deploy otherwise fails its first sync silently
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
log('ensureCollection failed (sync keeps trying):', e);
|
|
58
|
+
}
|
|
59
|
+
startDriveSyncScheduler(parseInt(process.env.DRIVE_SYNC_INTERVAL_MIN || '30', 10));
|
|
60
|
+
},
|
|
61
|
+
commands: {
|
|
62
|
+
reindex: {
|
|
63
|
+
description: 'full Drive → Qdrant index (--dry-run, --recreate, --root <id>, --dev-only, --biz-only)',
|
|
64
|
+
run: async (args) => (await import('./reindex.js')).runReindex(args),
|
|
65
|
+
},
|
|
66
|
+
'get-token': {
|
|
67
|
+
description: 'sign in with Google and print a Drive refresh token (GOOGLE_OAUTH_CLIENT_ID/SECRET)',
|
|
68
|
+
run: async () => (await import('./get_token.js')).runGetToken(),
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/drive/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drive 파일 1개 → Qdrant 색인/삭제 공통 로직.
|
|
3
|
+
* 전체 reindex (reindex.ts) 와 증분 sync (sync.ts) 가 공유.
|
|
4
|
+
*/
|
|
5
|
+
import type { drive_v3 } from 'googleapis';
|
|
6
|
+
import { type RawChunk } from './chunker.js';
|
|
7
|
+
import { type ChunkPayload } from './qdrant.js';
|
|
8
|
+
import { DRIVE_ROOTS, MAX_FILE_BYTES } from './settings.js';
|
|
9
|
+
export { DRIVE_ROOTS, MAX_FILE_BYTES };
|
|
10
|
+
/** 추출 지원 mimeType (extract_text.ts 와 일치). 스캔 PDF/이미지는 Mathpix OCR. 풀 reindex·증분 sync 공용 SSOT. */
|
|
11
|
+
export declare const SUPPORTED_MIMES: Set<string>;
|
|
12
|
+
/** 점진적 chunk ID — file_id + index 면 항상 같은 ID (idempotent upsert). 색인 전 경로 공용. */
|
|
13
|
+
export declare function makeChunkId(fileId: string, chunkIndex: number): number;
|
|
14
|
+
/** path + source -> file_type / cluster. cluster = top-level folder (generic). */
|
|
15
|
+
export declare function classifyFile(path: string, source: 'dev' | 'biz'): {
|
|
16
|
+
type: ChunkPayload['file_type'];
|
|
17
|
+
cluster: string | null;
|
|
18
|
+
};
|
|
19
|
+
export interface IndexableFile {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
path: string;
|
|
23
|
+
modifiedTime: string;
|
|
24
|
+
source: 'dev' | 'biz';
|
|
25
|
+
mimeType: string;
|
|
26
|
+
/** Drive 메타의 바이트 크기. Google 문서는 없음. */
|
|
27
|
+
size?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 청크의 임베딩 입력 텍스트 — heading breadcrumb(상위>하위 섹션 맥락)를 본문 앞에 붙인다.
|
|
31
|
+
* (contextual chunk header) 부모 heading 은 청크 본문에 없어(다른 섹션) 벡터가 섹션 맥락을 잃는데,
|
|
32
|
+
* 이를 임베딩에 포함하면 recall 이 오른다. 저장·표시용 content(payload)는 그대로 두고 임베딩 입력에만 적용.
|
|
33
|
+
* '문서 시작'(첫 heading 이전 placeholder)은 의미 없어 skip. ★증분(indexFile)·전체(reindex.ts) 공용 SSOT —
|
|
34
|
+
* 두 경로가 반드시 같은 입력을 임베딩해야 같은 청크가 같은 벡터를 가진다(벡터 공간 정합).
|
|
35
|
+
*/
|
|
36
|
+
export declare function embedInputForChunk(chunk: RawChunk): string;
|
|
37
|
+
/** 추출 텍스트 → sha256 (무변경 재색인 skip 판정용). */
|
|
38
|
+
export declare function contentHash(text: string): string;
|
|
39
|
+
export interface BizMeta {
|
|
40
|
+
doc_category: string | null;
|
|
41
|
+
doc_customer: string | null;
|
|
42
|
+
path_tags: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* biz 소스(PDF/docx — frontmatter 없음)의 경로/파일명에서 메타 파생.
|
|
46
|
+
* EXTRACTED — 사람이 폴더로 분류한 사실(LLM 추론 아님). dev 소스는 frontmatter 가 SSOT 라 빈 값.
|
|
47
|
+
* doc_category : 최상위 폴더(NN_ 제거) 예) "01_고객사/…" → "고객사"
|
|
48
|
+
* doc_customer : 01_고객사/{name} 예) "01_고객사/Acme/…" → "Acme"
|
|
49
|
+
* path_tags : 폴더 세그먼트(NN_ 제거) + 파일명 토큰 (검색 태그)
|
|
50
|
+
*/
|
|
51
|
+
export declare function deriveBizMeta(path: string, source: 'dev' | 'biz'): BizMeta;
|
|
52
|
+
/**
|
|
53
|
+
* chunk + 파일/분류/경로 메타 → ChunkPayload. reindex(reindex.ts)·증분(indexFile) 공유 SSOT.
|
|
54
|
+
* dev 메타는 chunk(frontmatter 파싱)에, biz 메타는 bizMeta(경로 파싱)에 담겨 들어온다.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildChunkPayload(chunk: RawChunk, file: IndexableFile, idx: number, chunkCount: number, classification: {
|
|
57
|
+
type: ChunkPayload['file_type'];
|
|
58
|
+
cluster: string | null;
|
|
59
|
+
}, bizMeta: BizMeta, hash: string): ChunkPayload;
|
|
60
|
+
/**
|
|
61
|
+
* 파일 1개 형식별 추출 → chunk → embed → Qdrant upsert. 색인된 chunk 수 반환 (skip 시 0).
|
|
62
|
+
*
|
|
63
|
+
* - EFF-1: 추출 텍스트 sha256 이 기존 색인과 동일하면 embed/upsert 생략(무변경 skip).
|
|
64
|
+
* - B-1: 재색인 시 청크 수가 줄면 옛 청크(chunk_index >= 새 수)를 삭제해 유령 청크(폐기된 사실) 잔류 방지.
|
|
65
|
+
* - B-9: 증분 경로는 wait:true 로 색인 직후 검색 가시성 + 실패 인지.
|
|
66
|
+
*/
|
|
67
|
+
export declare function indexFile(drive: drive_v3.Drive, file: IndexableFile): Promise<number>;
|
|
68
|
+
/** 특정 파일의 모든 chunk 를 Qdrant 에서 삭제 (파일 삭제·trashed 시). */
|
|
69
|
+
export declare function deleteFileVectors(fileId: string): Promise<void>;
|