ken-jo/local-indexer
v0.7.0
Local Indexer 문서 파일 자동 인덱싱 및 문서 검색 익스텐션. 폴더 감시(chokidar), PDF/Markdown 파싱, 한국어 형태소 분석(kiwi), FTS5 기반 검색. 인덱스 위치: 익스텐션 데이터 디렉터리의 index/
plugin.json
- name
- local-indexer
- version
- 0.7.0
- description
- Local Indexer 문서 파일 자동 인덱싱 및 문서 검색 익스텐션. 폴더 감시(chokidar), PDF/Markdown 파싱, 한국어 형태소 분석(kiwi), FTS5 기반 검색. 인덱스 위치: 익스텐션 데이터 디렉터리의 index/
- extensions
- xyz.lvisai
plugin.json
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "local-indexer",
"version": "0.7.0",
"description": "Local Indexer 문서 파일 자동 인덱싱 및 문서 검색 익스텐션. 폴더 감시(chokidar), PDF/Markdown 파싱, 한국어 형태소 분석(kiwi), FTS5 기반 검색. 인덱스 위치: 익스텐션 데이터 디렉터리의 index/",
"extensions": {
"xyz.lvisai": {
"displayName": "Ave Local Indexer",
"icon": "Database",
"llmKeySource": "host",
"entry": "dist/hostPlugin.js",
"onboarding": {
"firstTask": {
"priority": 20,
"locales": {
"en": {
"headline": "Search your local documents",
"body": "Add a folder to index PDFs and Markdown files, then ask questions across their contents.",
"actionLabel": "Set up document search",
"composerPrompt": "Help me add a folder and search my local documents"
},
"ko": {
"headline": "로컬 문서를 검색해 보세요",
"body": "폴더를 추가해 PDF와 Markdown 파일을 인덱싱한 뒤 문서 내용에 관해 질문할 수 있습니다.",
"actionLabel": "문서 검색 설정",
"composerPrompt": "폴더를 추가하고 로컬 문서를 검색하는 방법을 알려줘"
}
}
}
},
"python": {
"managedBy": "ave",
"requirementsLock": "python-requirements.lock"
},
"tools": [
{
"name": "index_search",
"description": "인덱싱된 문서를 검색합니다 (파일/이미지 찾기). mode 로 동작이 갈립니다: vector/hybrid(기본 hybrid) → 정밀 검색 결과 청크 목록을 반환: { query, mode, topK, hits: [{ chunkId, docId, docName, page, score, source, path, snippet, rawText }] } (source 는 'bm25'|'vector'|'hybrid' 로 정규화). bm25 → 빠른 키워드 1차 스크린 + 사람이 읽을 미리보기 문자열을 반환: { question, documentCount, results, preview } (topK 무시, 최대 5건). 정밀도가 필요하면 hybrid, 짧은 미리보기 문자열만 필요하면 bm25 를 쓰세요.",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "검색 질의어 (자연어 또는 키워드). 최대 2000자."
},
"mode": {
"type": "string",
"enum": [
"bm25",
"vector",
"hybrid"
],
"default": "hybrid",
"description": "검색 방식. bm25=키워드 전용 미리보기(documentCount/preview 문자열 반환, topK 무시·최대 5건), vector=의미 검색(임베딩 설정 필요, hits 반환), hybrid=둘을 RRF로 결합(hits 반환)."
},
"topK": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"default": 10,
"description": "반환할 최대 청크 수 (1~50)."
}
},
"required": [
"query"
],
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"model"
]
}
}
},
{
"name": "index_scan",
"description": "문서를 인덱싱합니다. 세 가지 모드를 인자로 구분합니다: (1) 인자 없음 → 등록된 모든 폴더를 즉시 스캔해 새/변경 파일을 인덱싱 (사용자가 '문서 다시 인덱싱해줘', '방금 추가한 파일 반영해줘' 같이 최신화를 요청할 때, 또는 index_search 결과가 부족해 보일 때). 반환: { indexed, totalIndexed, message }. (2) folder 지정 → 등록된 그 폴더 하나만 증분 갱신(새/변경/삭제 파일만 조정, 전체 재스캔보다 가벼움). 반환: { folder, indexed, removed, failed, message }. (3) paths 지정 → 등록 폴더에 추가하지 않고 지정한 절대 경로 파일/폴더를 즉시 인덱싱(드래그앤드롭 등 이번 대화 한정 자료). 반환: { indexed, failed, jobId, message }. folder 와 paths 를 동시에 주지 마세요 — paths 가 우선합니다.",
"inputSchema": {
"type": "object",
"properties": {
"folder": {
"type": "string",
"minLength": 1,
"maxLength": 4096,
"description": "증분 갱신할 등록 폴더의 절대 경로. index_folders 결과에 포함된 경로를 전달하세요. 미지정 시 모든 등록 폴더를 스캔합니다."
},
"paths": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 4096
},
"minItems": 1,
"maxItems": 200,
"description": "등록 폴더에 추가하지 않고 즉시 인덱싱할 파일 또는 폴더의 절대 경로 목록 (1~200개). NUL 바이트와 시스템 경로는 호스트 측에서 차단됩니다."
}
},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"model",
"app"
]
},
"ave/pathFields": [
"folder",
"paths"
]
}
},
{
"name": "index_folders",
"description": "인덱싱 대상 폴더를 관리합니다. action 으로 동작을 구분합니다: (1) action 'list'(기본, 인자 생략 가능) → 현재 등록된 폴더 목록/상태를 반환 ('어떤 폴더가 인덱싱되고 있지?'). 반환: { folders, summaries }. (2) action 'add' + folder(단일) 또는 folders(다중 배열) → 인덱싱 대상 폴더 추가. 시스템/민감 경로(~/.ssh, /etc 등)와 다른 사용자 홈은 차단됩니다. 추가 후 index_scan 으로 인덱싱을 트리거하세요. 단일 추가 반환: { folders, added: boolean, message, summary }; 다중 추가 반환: { folders, added: string[], skipped, failures }. (3) action 'remove' + folder → 인덱싱 대상에서 폴더 제거(해당 폴더 문서는 검색에서 빠짐). 반환: { folders, removed: boolean, message }. 사용 안 함: 문서 목록은 index_documents.",
"inputSchema": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"list",
"add",
"remove"
],
"default": "list",
"description": "수행할 동작. list=등록 폴더 조회(기본), add=폴더 추가(folder 또는 folders 필요), remove=폴더 제거(folder 필요)."
},
"folder": {
"type": "string",
"minLength": 1,
"maxLength": 4096,
"pattern": "^([A-Za-z]:[\\\\/]|/|~|\\.)",
"description": "add(단일) 또는 remove 대상 폴더의 절대 경로 또는 ~ / 상대 경로 (예: /Users/ken/Documents). NUL 바이트는 호스트 측에서 거부됩니다."
},
"folders": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 4096
},
"minItems": 1,
"maxItems": 200,
"description": "action 'add' 다중 추가용 폴더 절대 경로 배열 (1~200개). N개를 한 번에 추가해도 rebuild 는 1회만 수행합니다."
}
},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"model",
"app"
]
},
"ave/pathFields": [
"folder",
"folders"
]
}
},
{
"name": "index_documents",
"description": "인덱싱된 문서 메타데이터 목록을 페이지 단위로 반환합니다. 사용 시기: 검색 대상 문서 목록을 확인하거나 특정 문서를 선택하기 전. 사용 안 함: 내용·키워드 검색은 index_search를 사용하세요 (mode 'hybrid'/'vector'는 구조화된 hits, mode 'bm25'는 짧은 키워드 미리보기). 특정 docId의 메타데이터나 페이지 본문은 index_get_document를 사용하세요. 인자: { limit?: integer (1~100, 기본 100), offset?: integer (≥0, 기본 0), full?: boolean (기본 false) }. 응답 (기본, LLM 용): { documents: Array<{doc_id, doc_name, type, path, status, content_state}>, total: number, hasMore: boolean }. status 는 항상 'indexed'(목록에 보이는 문서). content_state 는 내용 품질을 구분: 'ok'(텍스트+벡터 정상), 'empty'(파싱은 됐으나 추출 텍스트 없음), 'embed_failed'(텍스트는 색인됐으나 임베딩 누락 → 의미 검색 불가, 키워드 검색만 가능). 'empty'/'embed_failed' 문서가 보이면 사용자에게 재색인이나 본문 부재를 안내하세요. 응답 (full=true, UI 표시용): documents 항목에 page_count, line_count 가 추가됨. hasMore=true 이면 offset 을 증가시켜 다음 페이지를 호출하세요. 서버측 hard cap(limit≤100) 이 있으므로 큰 limit 도 잘려 반환됩니다.",
"inputSchema": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 100,
"description": "이번 페이지에 포함할 최대 문서 수 (1~100, 기본 100). 서버측 hard cap 100 이라 더 큰 값을 보내도 잘립니다."
},
"offset": {
"type": "integer",
"minimum": 0,
"default": 0,
"description": "건너뛸 문서 수 (페이지네이션 커서). 첫 호출은 0, hasMore=true 이면 이전 호출의 offset + documents.length 를 다음 호출의 offset 으로 사용."
},
"full": {
"type": "boolean",
"default": false,
"description": "true 이면 응답 documents 항목에 page_count, line_count 가 추가됩니다. UI 의 카운트 표시용 — LLM function call 은 보통 인자를 생략해 page_count/line_count 가 없는 lean shape 을 받습니다 (응답 토큰 절감)."
}
},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"model",
"app"
]
}
}
},
{
"name": "index_get_document",
"description": "doc_id로 인덱싱된 문서의 메타데이터와 (옵션) 페이지 본문·인덱스 구조를 반환합니다. 사용 시기: 검색 히트(index_search)에서 받은 docId의 본문/페이지가 필요하거나, UI 결과 클릭 시 미리보기를 표시할 때 — 파일 재파싱 없이 인덱스 DB에서 바로 조회. 긴 문서라면 먼저 includeStructure로 실제 인덱싱된 페이지 번호만 받아 읽을 범위를 고른 뒤 pages로 그 범위만 요청하세요. 사용 안 함: 전체 문서 목록은 index_documents. 반환: { doc: { docId, docName, type, path, pageCount, lineCount, indexedAt, status, contentState }, pages: [{ page, content }], structure? }. structure 는 includeStructure=true 일 때만 포함되며 { doc_id, doc_name, doc_type, page_count, line_count, pages: number[] } — pages 는 인덱스에 본문 청크가 존재하는 페이지 번호 목록이라 pageCount 보다 적을 수 있습니다(파싱되지 않은 페이지는 빠짐). contentState 는 'ok' | 'empty' | 'embed_failed' — 'empty'(추출 텍스트 없음) 또는 'embed_failed'(임베딩 누락, 의미 검색 불가)이면 사용자에게 본문 부재/재색인을 안내하세요.",
"inputSchema": {
"type": "object",
"properties": {
"docId": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"description": "조회할 문서의 doc_id (index_documents/index_search 결과에서 얻은 값)."
},
"pages": {
"type": "string",
"maxLength": 200,
"pattern": "^[0-9,\\-\\s]{1,200}$",
"description": "조회할 페이지 범위. 예: '1', '1-3', '1-3,5'. 미지정 시 includeContent에 따름. 워커의 _PAGES_RE 와 동일 패턴."
},
"includeContent": {
"type": "boolean",
"default": false,
"description": "true이고 pages 미지정이면 처음 50페이지까지 본문을 함께 반환합니다."
},
"includeStructure": {
"type": "boolean",
"default": false,
"description": "true이면 본문 청크가 존재하는 페이지 번호 목록을 structure 로 함께 반환합니다. 본문은 포함하지 않으므로, 어느 페이지를 pages 로 요청할지 고르는 용도로 쓰세요."
}
},
"required": [
"docId"
],
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"model"
]
}
}
},
{
"name": "index_scan_status",
"description": "현재 진행 중이거나 마지막으로 실행된 문서 스캔 상태를 반환합니다. 사용 시기: UI 진행률 표시, 사용자의 '인덱싱 어디까지 됐어?' 질문, index_scan(전체 스캔·등록 폴더 증분 갱신·지정 경로 즉시 인덱싱) 호출 직후 상태 확인. 사용 안 함: 문서 목록은 index_documents. 반환: { status: 'idle'|'running'|'done'|'failed'|'canceled', total, processed, indexed, failed, currentPath?, message?, byFolder?: Record<folder, { total, processed, indexed, failed }>, warnings?: Array<{ kind, message, path?, docId?, error?, reason? }> }.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"model",
"app"
]
}
}
},
{
"name": "index_scan_cancel",
"description": "진행 중인 문서 스캔에 대해 중단을 요청합니다. 사용 시기: 사용자가 스캔 중 중단 버튼을 누르거나 '인덱싱 멈춰줘'라고 요청했을 때. 사용 안 함: 스캔 상태만 확인하려면 index_scan_status. 반환: { canceled, message }. 실제 중단은 worker가 현재 파일 처리를 마친 뒤 반영될 수 있습니다.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
}
}
},
{
"name": "index_clear_warnings",
"description": "Local Indexer UI에 표시 중인 최근 인덱싱 경고 버퍼를 비웁니다. 사용 시기: 사용자가 '인덱싱 경고' 섹션을 수동으로 비우거나 새 스캔 시작 전에 이전 경고를 초기화할 때. 반환: { cleared: true }.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
}
}
},
{
"name": "index_folders_purge_orphans",
"description": "등록된 인덱스 폴더 기준으로 더 이상 존재하지 않는 고아(orphan) 문서 인덱스 항목을 정리합니다. 사용 시기: 폴더 구조를 크게 바꿨거나 삭제된 파일이 검색 결과에 남아 있을 때 UI에서 정리 작업을 실행할 때. 인자 없음. 반환: { folders, summaries, purged }.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
}
}
},
{
"name": "index_pick_folder",
"description": "OS 네이티브 폴더 선택 다이얼로그(다중 선택 허용)를 띄워 사용자가 고른 폴더 경로 배열을 반환합니다. UI '폴더 추가' 버튼 전용 — webview 샌드박스가 dialog.showOpenDialog를 직접 호출하지 못하므로 호스트가 대신 띄웁니다. 인자 없음. 반환: { folders: string[], canceled: boolean }.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
}
}
},
{
"name": "index_preview_folder",
"description": "주어진 폴더를 walk 해 인덱싱 대상 파일들의 통계를 반환합니다. UI 폴더 추가 확인 모달용 — host 가 띄운 OS 폴더 선택 결과를 등록 전에 사용자에게 보여줄 때 사용. 반환: { folder, total, byType: {pdf:N,docx:M,...}, sample: string[] (basename, 최대 5개), error?: string }.",
"inputSchema": {
"type": "object",
"properties": {
"folder": {
"type": "string",
"minLength": 1,
"maxLength": 4096,
"description": "미리볼 폴더의 절대 경로"
}
},
"required": [
"folder"
],
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
},
"ave/pathFields": [
"folder"
]
}
},
{
"name": "index_get_settings",
"description": "Local Indexer 의 현재 설정(텍스트 임베딩/이미지 캡션) 스냅샷을 반환합니다. UI 토글 초기값 로딩 전용. 반환: { imageEmbeddingEnabled, imageCaptionProvider, imageCaptionModel, embeddingProvider, embeddingModel, hasApiKey }.",
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
}
}
},
{
"name": "index_set_image_embedding",
"description": "이미지 캡션 파이프라인 (이미지→캡션→텍스트 임베딩) 을 토글합니다. provider/model/endpoint/apiKey 는 호스트 익스텐션 설정에서만 변경 가능 — 이 도구는 enabled 토글만 받습니다. 변경된 설정은 다음 스캔부터 적용됩니다.",
"inputSchema": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "이미지 캡션 활성화 여부 (벡터화 자체는 텍스트 임베딩이며 이 토글은 이미지→캡션 단계의 on/off)"
}
},
"required": [
"enabled"
],
"additionalProperties": false
},
"_meta": {
"ui": {
"visibility": [
"app"
]
}
}
}
],
"capabilities": [
"knowledge-index",
"document-indexer",
"external-auth-consumer",
"host:overlay",
"lifecycle-observer"
],
"startupTimeoutMs": 30000,
"eventSubscriptions": [
{
"type": "host.theme.changed"
}
],
"alerts": {
"reasoning": "Index scans and registered folder changes can be useful in the alert summary when the user opts in.",
"suggestions": [
"overlay:local-indexer-nightly-rescan"
],
"kinds": [
{
"id": "index-scan-completed",
"label": {
"en": "Index scan finished",
"ko": "문서 스캔 종료"
},
"defaultEnabled": false,
"visibility": "summary-only",
"summary": {
"en": "A local document scan finished.",
"ko": "로컬 문서 스캔이 끝났습니다."
},
"prompt": {
"en": "A local document scan finished. Use index_scan_status to check its result if needed.",
"ko": "로컬 문서 스캔이 끝났습니다. 필요하면 index_scan_status로 결과를 확인하세요."
}
},
{
"id": "index-folders-changed",
"label": {
"en": "Index folders changed",
"ko": "인덱싱 폴더 변경"
},
"defaultEnabled": false,
"visibility": "summary-only",
"summary": {
"en": "Registered index folders changed.",
"ko": "등록된 인덱싱 폴더가 변경되었습니다."
},
"prompt": {
"en": "Registered index folders changed. Use index_folders to inspect the current list if needed.",
"ko": "등록된 인덱싱 폴더가 변경되었습니다. 필요하면 index_folders로 현재 목록을 확인하세요."
}
}
]
},
"ui": [
{
"id": "local-indexer-control",
"slot": "sidebar",
"kind": "embedded-module",
"displayName": "로컬 인덱서",
"title": "Local Indexer",
"description": "Local Indexer 문서 스캔/목록 확인과 채팅창 질문 전송을 제공합니다.",
"entry": "dist/ui/indexer-control.js",
"exportName": "mount"
}
],
"configSchema": {
"properties": {
"embeddingProvider": {
"type": "string",
"title": "[임베딩] 프로바이더",
"description": "임베딩 API 프로바이더. openai=OpenAI(또는 OpenAI-호환 endpoint), azure=Azure OpenAI Service 의 임베딩 deployment.",
"enum": [
"openai",
"azure"
],
"default": "openai"
},
"embeddingModel": {
"type": "string",
"title": "[임베딩] 모델",
"description": "임베딩 모델명. openai→모델 ID (예: text-embedding-3-small), azure→deployment 이름.",
"default": ""
},
"embeddingEndpoint": {
"type": "string",
"title": "[임베딩] endpoint URL",
"description": "Azure 리소스의 루트 URL 만 입력 — 예: https://<resource>.openai.azure.com/ 또는 https://<resource>.cognitiveservices.azure.com/. 워커가 /openai/deployments/<model>/embeddings 경로를 SDK 로 합성합니다. full URL 을 붙여 넣어도 path/query 는 자동 제거. openai 일 때는 OpenAI-호환 base URL (비워두면 api.openai.com 기본).",
"format": "uri",
"default": ""
},
"embeddingApiVersion": {
"type": "string",
"title": "[임베딩] api-version (Azure)",
"description": "Azure embeddings api-version 쿼리값 (예: 2023-05-15). 비워두면 워커 디폴트를 사용하고, full embedding URL을 붙여 넣은 경우 query의 api-version을 자동 추출합니다.",
"default": ""
},
"embeddingApiKey": {
"type": "string",
"title": "[임베딩] API 키",
"description": "임베딩 API 호출에 사용하는 키. Azure OpenAI 의 경우 리소스의 API 키.",
"format": "secret",
"default": ""
},
"imageEmbeddingEnabled": {
"type": "boolean",
"title": "[캡션] 이미지 캡션 활성화",
"description": "PPTX/PDF/DOCX/XLSX 내부 이미지와 단독 .jpg/.jpeg/.png 를 캡션 모델로 텍스트화한 뒤 텍스트 임베딩 파이프라인에 포함합니다. (벡터 자체는 텍스트 임베딩이며, 이 토글은 이미지→캡션 변환 단계의 활성화 여부입니다.) cloud provider 사용 시 API 호출 비용이 발생합니다.",
"default": false
},
"imageCaptionProvider": {
"type": "string",
"title": "[캡션] provider",
"description": "이미지 캡셔닝에 사용할 provider. openai=OpenAI Vision API. azure-openai-chat=Azure OpenAI 의 vision-capable deployment (gpt-4o-mini, gpt-5.4-mini 등) — 사내 Azure 사용자 권장.",
"enum": [
"openai",
"azure-openai-chat",
"azure-openai-responses"
],
"default": "openai"
},
"imageCaptionModel": {
"type": "string",
"title": "[캡션] 모델",
"description": "캡션 모델명. 빈 값이면 provider 별 디폴트 사용 (openai→gpt-4.1-mini, azure→provider 기본값).",
"default": ""
},
"imageCaptionEndpoint": {
"type": "string",
"title": "[캡션] endpoint URL",
"description": "Azure 리소스의 루트 URL 만 입력 — 예: https://<resource>.openai.azure.com/. 워커가 /openai/deployments/<model>/chat/completions 경로를 자동 합성. full URL 을 붙여 넣어도 path/query 는 자동 제거. openai 일 때는 OpenAI-호환 base URL (비워두면 api.openai.com 기본).",
"format": "uri",
"default": ""
},
"imageCaptionApiVersion": {
"type": "string",
"title": "[캡션] api-version (Azure)",
"description": "Azure OpenAI chat completions api-version 쿼리값 (예: 2024-08-01-preview). 비워두면 워커 디폴트 적용 (vision-capable chat 의 안정 버전). openai provider 에서는 무시.",
"default": ""
},
"imageCaptionApiKey": {
"type": "string",
"title": "[캡션] API 키",
"description": "이미지 캡셔닝 호출에 사용하는 키. Azure AI Vision 의 경우 리소스의 'Ocp-Apim-Subscription-Key' 값.",
"format": "secret",
"default": ""
},
"realtimeWatch": {
"type": "boolean",
"title": "실시간 파일 감시 활성화",
"description": "chokidar 파일 감시자를 사용해 등록 폴더의 변경을 실시간으로 감지합니다.",
"default": false
},
"scanFolders": {
"type": "array",
"title": "자동 스캔 폴더 목록",
"description": "익스텐션 시작 시 자동으로 인덱싱할 폴더 경로 목록 (hostRoot 기준 상대 경로 또는 절대 경로).",
"default": [],
"items": {
"type": "string"
}
},
"allowedUncRoots": {
"type": "array",
"title": "UNC 네트워크 공유 허용 목록",
"description": "기본적으로 UNC 경로(\\\\server\\share\\...)는 보안상 인덱싱이 차단됩니다. 회사 네트워크 드라이브나 클라우드 PC 사용자 홈처럼 신뢰할 수 있는 UNC prefix 만 여기 명시적으로 등록하세요. 예: \\\\nas01.example.com\\users$. 등록된 prefix 로 시작하는 경로만 차단이 해제되며, \\\\?\\ / \\\\.\\ 장치 namespace 는 등록 여부와 무관하게 항상 차단됩니다. 각 항목은 런타임 normalizeUncRoot 로 정규화/검증되며 형태가 부적절한 항목(blanket \\\\, server-only, NUL 포함, 4096 자 초과 등)은 silent 하게 drop 됩니다.",
"default": [],
"items": {
"type": "string"
}
},
"apiKeySource": {
"type": "string",
"title": "API 키 소스",
"description": "OpenAI 호출 (embedding + image captioning) 에 사용할 API 키 출처. 'host' = Ave host 의 active LLM vendor 키 사용 (사용자 입력 불필요), 'plugin' = 본 익스텐션의 own apiKey 필드 사용.",
"enum": [
"host",
"plugin"
],
"default": "host"
},
"maxFileSize": {
"type": "integer",
"title": "최대 파일 크기 (바이트)",
"description": "이 크기를 초과하는 파일은 파싱 없이 status='failed' 로 기록됩니다 (무시/silent skip 아님 — 사용자에게 명시적 실패로 표면화). 기본값 52428800 = 50 MB. 0 으로 설정하면 제한 없음.",
"default": 52428800,
"minimum": 0
},
"maxChunksPerDoc": {
"type": "integer",
"title": "문서당 최대 청크 수",
"description": "단일 문서에서 생성할 수 있는 최대 청크 수. 초과 시 앞쪽 청크를 유지하고 나머지를 잘라냅니다 (IndexResult.errors[] 에 경고 기록, 인덱싱은 계속). 기본값 2000.",
"default": 2000,
"minimum": 1
},
"workerPort": {
"type": "integer",
"title": "워커 포트",
"description": "색인 워커가 127.0.0.1 에서 listen 할 TCP 포트. 기본값 43129. 같은 PC 에서 Ave 를 두 개 이상 실행하면 두 번째 인스턴스는 이 포트를 잡지 못해 로컬 색인이 아예 켜지지 않으므로, 그런 경우 인스턴스마다 다른 값을 지정하십시오. 다른 프로그램이 43129 를 쓰고 있을 때도 마찬가지입니다.",
"default": 43129,
"minimum": 1024,
"maximum": 65535
},
"indexStorageRoot": {
"type": "string",
"title": "인덱스 저장 경로",
"description": "승인된 경로 안의 인덱스 저장 디렉터리. 비워 두면 익스텐션 기본 경로를 사용합니다.",
"default": ""
},
"workspace": {
"type": "string",
"title": "워커 작업 경로",
"description": "승인된 경로 안의 워커 임시 작업 디렉터리. 비워 두면 기본 경로를 사용합니다.",
"default": ""
}
}
},
"requires": {
"minAppVersion": "0.14.0",
"hostProtocol": "3"
},
"hostSecrets": {
"read": [
"llm.apiKey.openai",
"llm.apiKey.azure-foundry"
]
},
"networkAccess": {
"allowedDomains": [
"api.openai.com",
"openai.azure.com",
"cognitiveservices.azure.com",
"localhost",
"127.0.0.1",
"::1"
],
"reasoning": "워커의 임베딩/비전 캡셔닝 egress. 이 정적 allow-list는 디폴트 OpenAI/Azure 호스트(api.openai.com, *.openai.azure.com, *.cognitiveservices.azure.com — dot-boundary suffix-match)만 커버한다. host-mediated egress broker(P3 ⑬, src/egressBroker.ts) 도입 후, 워커는 provider 키를 보유하지 않고 broker(<base>/egress/embedding, <base>/egress/caption)로만 egress하며, 실제 provider 호출은 호스트-측 broker가 hostApi.hostFetch chokepoint를 통해 수행한다. 따라서 provider egress는 이 manifest networkAccess.allowedDomains, HTTPS-only, SSRF guard, effect-boundary audit를 모두 통과한다. 워커는 임의 host를 지정할 수 없고, suffix에 맞지 않는 사용자-설정 커스텀 OpenAI-호환 endpoint는 hostFetch 단계에서 hard-deny된다. 루프백 리터럴(localhost / 127.0.0.1 / ::1)은 embeddingProvider=\"openai\" 일 때 사용자가 embeddingEndpoint 설정에 직접 적어 넣는 로컬 추론 서버(LM Studio, LiteLLM, 사내 프록시)를 위한 선언이다. 이 선언이 없으면 해당 설정은 hostFetch에서 항상 거부되어 조작할 수 없는 설정이 된다. 호스트는 이 리터럴에 한해 http cleartext를 허용하되(바이트가 기기 밖으로 나가지 않으므로 https 규칙이 보호할 대상이 없다) 이름이 실제로 루프백으로만 resolve되는지 증명한 뒤에만 허용하며, 이 선언은 LAN(RFC1918)이나 다른 어떤 host도 열지 않는다."
},
"emittedEvents": [
"index.document.updated",
"index.folders.changed",
"index.scan.progress",
"index.scan.completed",
"index.warning"
],
"sandbox": {
"read": [
{
"kind": "hostDirectory",
"segments": [
"runtime"
],
"why": "the Python interpreter the worker executes"
},
{
"kind": "hostDirectory",
"segments": [
"certs"
],
"why": "the corporate CA bundle used by the worker"
}
],
"write": [
{
"kind": "userChosenDirectory",
"configKey": "indexStorageRoot",
"why": "where the local index is written"
},
{
"kind": "userChosenDirectory",
"configKey": "workspace",
"why": "the workers scratch and state directory"
}
]
}
}
}
}
Client extensions
Data this package carries for particular clients. The directory lists the clients named and never reads what is addressed to them.
- xyz.lvisai