@ngao/search 0.1.0 → 0.1.2
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/.claude/settings.local.json +10 -0
- package/.env.example +7 -0
- package/.eslintrc.json +20 -0
- package/.github/workflows/build.yml +39 -0
- package/.github/workflows/release.yml +34 -0
- package/.github/workflows/test.yml +35 -0
- package/.mcp-config.json +14 -0
- package/.prettierrc.json +10 -0
- package/LICENSE +17 -0
- package/Makefile +26 -0
- package/README.md +57 -172
- package/config.example.json +8 -0
- package/dist/backend/api/search-engine.d.ts +40 -0
- package/dist/backend/api/search-engine.d.ts.map +1 -0
- package/dist/backend/api/search-engine.js +227 -0
- package/dist/backend/api/search-engine.js.map +1 -0
- package/dist/backend/core/block-impl.d.ts +32 -0
- package/dist/backend/core/block-impl.d.ts.map +1 -0
- package/dist/backend/core/block-impl.js +33 -0
- package/dist/backend/core/block-impl.js.map +1 -0
- package/dist/backend/core/config-loader.d.ts +68 -0
- package/dist/backend/core/config-loader.d.ts.map +1 -0
- package/dist/backend/core/config-loader.js +234 -0
- package/dist/backend/core/config-loader.js.map +1 -0
- package/dist/backend/core/constants.d.ts +39 -0
- package/dist/backend/core/constants.d.ts.map +1 -0
- package/dist/backend/core/constants.js +57 -0
- package/dist/backend/core/constants.js.map +1 -0
- package/dist/backend/core/enums.d.ts +54 -0
- package/dist/backend/core/enums.d.ts.map +1 -0
- package/dist/backend/core/enums.js +61 -0
- package/dist/backend/core/enums.js.map +1 -0
- package/dist/backend/core/errors.d.ts +83 -0
- package/dist/backend/core/errors.d.ts.map +1 -0
- package/dist/backend/core/errors.js +151 -0
- package/dist/backend/core/errors.js.map +1 -0
- package/dist/backend/core/logger.d.ts +68 -0
- package/dist/backend/core/logger.d.ts.map +1 -0
- package/dist/backend/core/logger.js +151 -0
- package/dist/backend/core/logger.js.map +1 -0
- package/dist/backend/core/models.d.ts +332 -0
- package/dist/backend/core/models.d.ts.map +1 -0
- package/dist/backend/core/models.js +6 -0
- package/dist/backend/core/models.js.map +1 -0
- package/dist/backend/core/service-types.d.ts +184 -0
- package/dist/backend/core/service-types.d.ts.map +1 -0
- package/dist/backend/core/service-types.js +7 -0
- package/dist/backend/core/service-types.js.map +1 -0
- package/dist/backend/core/types.d.ts +219 -0
- package/dist/backend/core/types.d.ts.map +1 -0
- package/dist/backend/core/types.js +109 -0
- package/dist/backend/core/types.js.map +1 -0
- package/dist/backend/index.d.ts +5 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +13 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/indexing/block-extractor.d.ts +22 -0
- package/dist/backend/indexing/block-extractor.d.ts.map +1 -0
- package/dist/backend/indexing/block-extractor.js +52 -0
- package/dist/backend/indexing/block-extractor.js.map +1 -0
- package/dist/backend/indexing/index-builder.d.ts +26 -0
- package/dist/backend/indexing/index-builder.d.ts.map +1 -0
- package/dist/backend/indexing/index-builder.js +71 -0
- package/dist/backend/indexing/index-builder.js.map +1 -0
- package/dist/backend/parsers/base-file-parser.d.ts +134 -0
- package/dist/backend/parsers/base-file-parser.d.ts.map +1 -0
- package/dist/backend/parsers/base-file-parser.js +149 -0
- package/dist/backend/parsers/base-file-parser.js.map +1 -0
- package/dist/backend/parsers/javascript-parser.d.ts +36 -0
- package/dist/backend/parsers/javascript-parser.d.ts.map +1 -0
- package/dist/backend/parsers/javascript-parser.js +194 -0
- package/dist/backend/parsers/javascript-parser.js.map +1 -0
- package/dist/backend/parsers/json-parser.d.ts +15 -0
- package/dist/backend/parsers/json-parser.d.ts.map +1 -0
- package/dist/backend/parsers/json-parser.js +75 -0
- package/dist/backend/parsers/json-parser.js.map +1 -0
- package/dist/backend/parsers/markdown-parser.d.ts +17 -0
- package/dist/backend/parsers/markdown-parser.d.ts.map +1 -0
- package/dist/backend/parsers/markdown-parser.js +94 -0
- package/dist/backend/parsers/markdown-parser.js.map +1 -0
- package/dist/backend/parsers/parser-factory.d.ts +43 -0
- package/dist/backend/parsers/parser-factory.d.ts.map +1 -0
- package/dist/backend/parsers/parser-factory.js +149 -0
- package/dist/backend/parsers/parser-factory.js.map +1 -0
- package/dist/backend/parsers/python-parser.d.ts +21 -0
- package/dist/backend/parsers/python-parser.d.ts.map +1 -0
- package/dist/backend/parsers/python-parser.js +185 -0
- package/dist/backend/parsers/python-parser.js.map +1 -0
- package/dist/backend/parsers/yaml-parser.d.ts +16 -0
- package/dist/backend/parsers/yaml-parser.d.ts.map +1 -0
- package/dist/backend/parsers/yaml-parser.js +81 -0
- package/dist/backend/parsers/yaml-parser.js.map +1 -0
- package/dist/backend/repositories/implementations/lancedb-block-repository.d.ts +125 -0
- package/dist/backend/repositories/implementations/lancedb-block-repository.d.ts.map +1 -0
- package/dist/backend/repositories/implementations/lancedb-block-repository.js +505 -0
- package/dist/backend/repositories/implementations/lancedb-block-repository.js.map +1 -0
- package/dist/backend/repositories/implementations/lancedb-metadata-repository.d.ts +107 -0
- package/dist/backend/repositories/implementations/lancedb-metadata-repository.d.ts.map +1 -0
- package/dist/backend/repositories/implementations/lancedb-metadata-repository.js +275 -0
- package/dist/backend/repositories/implementations/lancedb-metadata-repository.js.map +1 -0
- package/dist/backend/repositories/implementations/memory-cache.d.ts +18 -0
- package/dist/backend/repositories/implementations/memory-cache.d.ts.map +1 -0
- package/dist/backend/repositories/implementations/memory-cache.js +53 -0
- package/dist/backend/repositories/implementations/memory-cache.js.map +1 -0
- package/dist/backend/repositories/repository.interface.d.ts +334 -0
- package/dist/backend/repositories/repository.interface.d.ts.map +1 -0
- package/dist/backend/repositories/repository.interface.js +7 -0
- package/dist/backend/repositories/repository.interface.js.map +1 -0
- package/dist/backend/search/context-extractor.d.ts +29 -0
- package/dist/backend/search/context-extractor.d.ts.map +1 -0
- package/dist/backend/search/context-extractor.js +106 -0
- package/dist/backend/search/context-extractor.js.map +1 -0
- package/dist/backend/search/multi-index-searcher.d.ts +28 -0
- package/dist/backend/search/multi-index-searcher.d.ts.map +1 -0
- package/dist/backend/search/multi-index-searcher.js +81 -0
- package/dist/backend/search/multi-index-searcher.js.map +1 -0
- package/dist/backend/search/query-parser.d.ts +37 -0
- package/dist/backend/search/query-parser.d.ts.map +1 -0
- package/dist/backend/search/query-parser.js +145 -0
- package/dist/backend/search/query-parser.js.map +1 -0
- package/dist/backend/search/ranking-engine.d.ts +31 -0
- package/dist/backend/search/ranking-engine.d.ts.map +1 -0
- package/dist/backend/search/ranking-engine.js +165 -0
- package/dist/backend/search/ranking-engine.js.map +1 -0
- package/dist/backend/search/result-formatter.d.ts +29 -0
- package/dist/backend/search/result-formatter.d.ts.map +1 -0
- package/dist/backend/search/result-formatter.js +70 -0
- package/dist/backend/search/result-formatter.js.map +1 -0
- package/dist/backend/service-types.d.ts +184 -0
- package/dist/backend/service-types.d.ts.map +1 -0
- package/dist/backend/service-types.js +7 -0
- package/dist/backend/service-types.js.map +1 -0
- package/dist/backend/services/embedding-service.d.ts +75 -0
- package/dist/backend/services/embedding-service.d.ts.map +1 -0
- package/dist/backend/services/embedding-service.js +298 -0
- package/dist/backend/services/embedding-service.js.map +1 -0
- package/dist/backend/services/file-watcher.d.ts +17 -0
- package/dist/backend/services/file-watcher.d.ts.map +1 -0
- package/dist/backend/services/file-watcher.js +92 -0
- package/dist/backend/services/file-watcher.js.map +1 -0
- package/dist/backend/services/index-information-service.d.ts +114 -0
- package/dist/backend/services/index-information-service.d.ts.map +1 -0
- package/dist/backend/services/index-information-service.js +104 -0
- package/dist/backend/services/index-information-service.js.map +1 -0
- package/dist/backend/services/ngao-search-service.d.ts +107 -0
- package/dist/backend/services/ngao-search-service.d.ts.map +1 -0
- package/dist/backend/services/ngao-search-service.js +384 -0
- package/dist/backend/services/ngao-search-service.js.map +1 -0
- package/dist/backend/services/quantization-service.d.ts +53 -0
- package/dist/backend/services/quantization-service.d.ts.map +1 -0
- package/dist/backend/services/quantization-service.js +84 -0
- package/dist/backend/services/quantization-service.js.map +1 -0
- package/dist/backend/services/reindex-manager.d.ts +25 -0
- package/dist/backend/services/reindex-manager.d.ts.map +1 -0
- package/dist/backend/services/reindex-manager.js +78 -0
- package/dist/backend/services/reindex-manager.js.map +1 -0
- package/dist/backend/services/session-manager.d.ts +115 -0
- package/dist/backend/services/session-manager.d.ts.map +1 -0
- package/dist/backend/services/session-manager.js +150 -0
- package/dist/backend/services/session-manager.js.map +1 -0
- package/dist/backend/services/vector-search-service.d.ts +81 -0
- package/dist/backend/services/vector-search-service.d.ts.map +1 -0
- package/dist/backend/services/vector-search-service.js +143 -0
- package/dist/backend/services/vector-search-service.js.map +1 -0
- package/dist/backend/utils/file-utils.d.ts +92 -0
- package/dist/backend/utils/file-utils.d.ts.map +1 -0
- package/dist/backend/utils/file-utils.js +247 -0
- package/dist/backend/utils/file-utils.js.map +1 -0
- package/dist/cli/setup.d.ts +4 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +138 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +14 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +7 -67075
- package/dist/main.js.map +1 -0
- package/dist/mcp/tool-schemas.d.ts +205 -0
- package/dist/mcp/tool-schemas.d.ts.map +1 -0
- package/dist/mcp/tool-schemas.js +391 -0
- package/dist/mcp/tool-schemas.js.map +1 -0
- package/dist/server/logger.d.ts +50 -0
- package/dist/server/logger.d.ts.map +1 -0
- package/dist/server/logger.js +77 -0
- package/dist/server/logger.js.map +1 -0
- package/dist/server/tool-registry.d.ts +64 -0
- package/dist/server/tool-registry.d.ts.map +1 -0
- package/dist/server/tool-registry.js +93 -0
- package/dist/server/tool-registry.js.map +1 -0
- package/dist/server/transports/mcp-transport.d.ts +31 -0
- package/dist/server/transports/mcp-transport.d.ts.map +1 -0
- package/dist/server/transports/mcp-transport.js +331 -0
- package/dist/server/transports/mcp-transport.js.map +1 -0
- package/dist/server/transports/rest-transport.d.ts +36 -0
- package/dist/server/transports/rest-transport.d.ts.map +1 -0
- package/dist/server/transports/rest-transport.js +250 -0
- package/dist/server/transports/rest-transport.js.map +1 -0
- package/docs/API.md +116 -0
- package/docs/ARCHITECTURE.md +101 -0
- package/docs/FILE_WATCHING.md +120 -0
- package/docs/INSTALLATION.md +87 -0
- package/docs/MCP_INTEGRATION.md +108 -0
- package/docs/README.md +288 -0
- package/docs/USAGE.md +123 -0
- package/docs/architecture-design-standards/01_ARCHITECTURE.md +863 -0
- package/docs/architecture-design-standards/02_SEARCH_ENGINE_DESIGN.md +958 -0
- package/docs/architecture-design-standards/03_DATAFLOW.md +1000 -0
- package/docs/architecture-design-standards/04_VISUAL_GUIDE.md +922 -0
- package/docs/architecture-design-standards/05_REPOSITORY_PATTERN_GUIDE.md +503 -0
- package/docs/architecture-design-standards/06_IMPLEMENTATION_PATTERNS.md +1026 -0
- package/docs/architecture-design-standards/07_TYPESCRIPT_GUIDE.md +1027 -0
- package/docs/architecture-design-standards/08_CODING_STANDARDS.md +1274 -0
- package/docs/reference/01_START_HERE.md +108 -0
- package/docs/reference/02_QUICK_REFERENCE.md +363 -0
- package/docs/reference/03_DOCUMENTATION_INDEX.md +293 -0
- package/docs/reference/04_DELIVERY_SUMMARY.md +463 -0
- package/docs/reference/05_IMPLEMENTATION_OVERVIEW.md +319 -0
- package/docs/reference/06_RESEARCH_SUMMARY.md +519 -0
- package/docs/tracking/03_IMPLEMENTATION_ROADMAP.md +788 -0
- package/jest.config.json +12 -0
- package/package.json +46 -53
- package/prepend-shebang.js +18 -0
- package/scripts/setup-mcp.sh +66 -0
- package/src/backend/index.ts +5 -0
- package/src/backend/service-types.ts +219 -0
- package/src/backend/services/file-watcher.ts +79 -0
- package/src/backend/services/ngao-search-service.ts +430 -0
- package/src/backend/services/reindex-manager.ts +90 -0
- package/src/backend/services/session-manager.ts +214 -0
- package/src/cli/setup.ts +122 -0
- package/src/index.ts +6 -0
- package/src/main.ts +225 -0
- package/src/mcp/tool-schemas.ts +439 -0
- package/src/server/logger.ts +88 -0
- package/src/server/tool-registry.ts +117 -0
- package/src/server/transports/mcp-transport.ts +374 -0
- package/src/server/transports/rest-transport.ts +258 -0
- package/tests/unit/agent-tools.test.ts +454 -0
- package/tests/unit/file-watcher.test.d.ts +2 -0
- package/tests/unit/file-watcher.test.d.ts.map +1 -0
- package/tests/unit/file-watcher.test.js +9 -0
- package/tests/unit/file-watcher.test.js.map +1 -0
- package/tests/unit/file-watcher.test.ts +7 -0
- package/tests/unit/search-integration.test.ts +256 -0
- package/tests/unit/services.test.d.ts +2 -0
- package/tests/unit/services.test.d.ts.map +1 -0
- package/tests/unit/services.test.js +9 -0
- package/tests/unit/services.test.js.map +1 -0
- package/tests/unit/services.test.ts +7 -0
- package/tsconfig.json +23 -0
- package/webpack.backend.config.js +60 -0
- package/webpack.config.js +34 -0
- package/models/Xenova/all-MiniLM-L6-v2/config.json +0 -25
- package/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
- package/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +0 -30686
- package/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +0 -15
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core NGAO Search Service
|
|
3
|
+
* Centralizes all business logic for search operations
|
|
4
|
+
* This service is used by both REST API and MCP transports
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
SearchEngine,
|
|
9
|
+
LanceBlockRepository,
|
|
10
|
+
LanceMetadataRepository,
|
|
11
|
+
IndexInformationService,
|
|
12
|
+
type SearchResult,
|
|
13
|
+
type IndexStats,
|
|
14
|
+
type Block,
|
|
15
|
+
type SearchOptions,
|
|
16
|
+
type IndexOptions,
|
|
17
|
+
type IBlockRepository,
|
|
18
|
+
type IMetadataRepository,
|
|
19
|
+
} from '@ngao/search-core';
|
|
20
|
+
import { SessionManager } from './session-manager';
|
|
21
|
+
import { ReindexManager } from './reindex-manager';
|
|
22
|
+
import { FileWatcher } from './file-watcher';
|
|
23
|
+
import * as ServiceTypes from '../service-types';
|
|
24
|
+
import * as path from 'path';
|
|
25
|
+
import * as fs from 'fs';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* NgaoSearchService is the central business logic facade
|
|
29
|
+
* All transport layers (REST, MCP) delegate to this service
|
|
30
|
+
*
|
|
31
|
+
* Uses SearchEngine from @ngao/search-core
|
|
32
|
+
*/
|
|
33
|
+
export class NgaoSearchService {
|
|
34
|
+
private _searchEngine: SearchEngine;
|
|
35
|
+
private _sessionManager: SessionManager;
|
|
36
|
+
private _reindexManager: ReindexManager;
|
|
37
|
+
private _indexInformationService: IndexInformationService;
|
|
38
|
+
|
|
39
|
+
// Store project configuration
|
|
40
|
+
private _projectDir: string;
|
|
41
|
+
private _includePaths: string[];
|
|
42
|
+
private _excludePaths: string[];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Initialize service with SearchEngine from core
|
|
46
|
+
* Loads configuration from project directory
|
|
47
|
+
*
|
|
48
|
+
* @param projectDir Optional project directory to load .ngao-search.json from (default: current directory)
|
|
49
|
+
*/
|
|
50
|
+
constructor(projectDir?: string) {
|
|
51
|
+
const resolvedProjectDir = projectDir || process.env.NGAO_SEARCH_PROJECT || process.cwd();
|
|
52
|
+
this._projectDir = resolvedProjectDir;
|
|
53
|
+
|
|
54
|
+
// Load configuration from project
|
|
55
|
+
const configPath = path.join(resolvedProjectDir, '.ngao-search.json');
|
|
56
|
+
const defaultConfig = { projectId: '', databasePath: '', includePaths: [], excludePaths: [] };
|
|
57
|
+
let config = defaultConfig;
|
|
58
|
+
|
|
59
|
+
if (fs.existsSync(configPath)) {
|
|
60
|
+
try {
|
|
61
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
62
|
+
const parsed = JSON.parse(configContent);
|
|
63
|
+
config = { ...defaultConfig, ...parsed };
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.warn(`Failed to load config from ${configPath}, using defaults`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Load include/exclude paths with sensible defaults
|
|
70
|
+
this._includePaths = config.includePaths && config.includePaths.length > 0
|
|
71
|
+
? config.includePaths
|
|
72
|
+
: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.py', '**/*.md'];
|
|
73
|
+
this._excludePaths = config.excludePaths && config.excludePaths.length > 0
|
|
74
|
+
? config.excludePaths
|
|
75
|
+
: ['node_modules/**', 'dist/**', '.git/**'];
|
|
76
|
+
|
|
77
|
+
// Initialize repositories for SearchEngine
|
|
78
|
+
const dataDir = config.databasePath || path.join(resolvedProjectDir, '.ngao');
|
|
79
|
+
const projectId = config.projectId || '';
|
|
80
|
+
|
|
81
|
+
const blockRepository: IBlockRepository = new LanceBlockRepository(dataDir, projectId);
|
|
82
|
+
const metadataRepository: IMetadataRepository = new LanceMetadataRepository(dataDir, projectId);
|
|
83
|
+
|
|
84
|
+
// Initialize search engine with repositories
|
|
85
|
+
this._searchEngine = new SearchEngine(
|
|
86
|
+
blockRepository,
|
|
87
|
+
metadataRepository,
|
|
88
|
+
undefined,
|
|
89
|
+
{ enableVectorSearch: true }
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// Initialize index information service - will be set after SearchEngine is created
|
|
93
|
+
// (done below after _searchEngine is assigned)
|
|
94
|
+
|
|
95
|
+
// Initialize services
|
|
96
|
+
this._sessionManager = new SessionManager();
|
|
97
|
+
this._reindexManager = new ReindexManager(this._searchEngine);
|
|
98
|
+
|
|
99
|
+
// Now initialize index information service with metadataRepository and SearchEngine
|
|
100
|
+
this._indexInformationService = new IndexInformationService(metadataRepository, this._searchEngine);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Eagerly initialize database components (but not embedding model)
|
|
105
|
+
* Call this during setup or startup to pre-initialize storage
|
|
106
|
+
* The embedding model will lazy-load on first search (requires network)
|
|
107
|
+
*
|
|
108
|
+
* @throws Error if database initialization fails
|
|
109
|
+
*/
|
|
110
|
+
async ensureInitialized(): Promise<void> {
|
|
111
|
+
// Core engine handles initialization internally
|
|
112
|
+
// This method is kept for compatibility
|
|
113
|
+
return Promise.resolve();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get the project directory
|
|
118
|
+
*/
|
|
119
|
+
getProjectDir(): string {
|
|
120
|
+
return this._projectDir;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get the include paths patterns
|
|
125
|
+
*/
|
|
126
|
+
getIncludePaths(): string[] {
|
|
127
|
+
return this._includePaths;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get the exclude paths patterns
|
|
132
|
+
*/
|
|
133
|
+
getExcludePaths(): string[] {
|
|
134
|
+
return this._excludePaths;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Perform a search operation
|
|
139
|
+
*/
|
|
140
|
+
async search(
|
|
141
|
+
params: ServiceTypes.SearchParams
|
|
142
|
+
): Promise<ServiceTypes.SearchOperationResult> {
|
|
143
|
+
try {
|
|
144
|
+
const options: SearchOptions | undefined = params.maxResults ? { maxResults: params.maxResults } : undefined;
|
|
145
|
+
|
|
146
|
+
const startTime = Date.now();
|
|
147
|
+
const results = await this._searchEngine.search(params.query, options);
|
|
148
|
+
const executionTime = Date.now() - startTime;
|
|
149
|
+
|
|
150
|
+
// Track search in session history if sessionId provided
|
|
151
|
+
if (params.sessionId) {
|
|
152
|
+
this._sessionManager.addSearchToHistory(params.sessionId, {
|
|
153
|
+
id: crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(),
|
|
154
|
+
query: params.query,
|
|
155
|
+
timestamp: Date.now(),
|
|
156
|
+
resultCount: results.length,
|
|
157
|
+
executionTimeMs: executionTime,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
resultCount: results.length,
|
|
164
|
+
executionTimeMs: executionTime,
|
|
165
|
+
results: results.map((r) => ({
|
|
166
|
+
rank: r.rank,
|
|
167
|
+
score: r.relevanceScore,
|
|
168
|
+
type: r.block.itemType,
|
|
169
|
+
name: r.block.name,
|
|
170
|
+
file: r.block.filePath,
|
|
171
|
+
lineRange: `${r.block.location.startLine}:${r.block.location.endLine}`,
|
|
172
|
+
scope: r.block.scopeHierarchy.join('.'),
|
|
173
|
+
content: r.block.content.substring(0, 200),
|
|
174
|
+
})),
|
|
175
|
+
};
|
|
176
|
+
} catch (error) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: String(error),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Index a directory
|
|
186
|
+
*/
|
|
187
|
+
async index(
|
|
188
|
+
params: ServiceTypes.IndexParams
|
|
189
|
+
): Promise<ServiceTypes.IndexOperationResult> {
|
|
190
|
+
try {
|
|
191
|
+
const options: Partial<IndexOptions & { includePaths?: string[]; excludePaths?: string[] }> = {
|
|
192
|
+
includePaths: this._includePaths,
|
|
193
|
+
excludePaths: this._excludePaths,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const stats = await this._searchEngine.indexDirectory(params.dirPath, options as IndexOptions & { includePaths?: string[]; excludePaths?: string[] });
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
success: true,
|
|
200
|
+
message: `Successfully indexed directory: ${params.dirPath}`,
|
|
201
|
+
stats: {
|
|
202
|
+
totalFiles: stats.totalFiles,
|
|
203
|
+
totalBlocks: stats.totalBlocks,
|
|
204
|
+
lastUpdated: new Date(stats.lastUpdatedAt).toISOString(),
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
} catch (error) {
|
|
208
|
+
return {
|
|
209
|
+
success: false,
|
|
210
|
+
error: String(error),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Auto-index the current project directory during setup
|
|
217
|
+
* Used by the setup process to initialize the index
|
|
218
|
+
* Respects the includePaths and excludePaths from project configuration
|
|
219
|
+
*
|
|
220
|
+
* @param projectDir The project directory to index
|
|
221
|
+
* @throws Error if indexing fails critically (non-fatal errors are logged and continue)
|
|
222
|
+
*/
|
|
223
|
+
async autoIndexProjectDirectory(projectDir: string): Promise<{ success: boolean; message: string; stats?: { totalFiles: number; totalBlocks: number; lastUpdated: string }; error?: string }> {
|
|
224
|
+
try {
|
|
225
|
+
const options: Partial<IndexOptions & { includePaths?: string[]; excludePaths?: string[] }> = {
|
|
226
|
+
includePaths: this._includePaths,
|
|
227
|
+
excludePaths: this._excludePaths,
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const stats = await this._searchEngine.indexDirectory(projectDir, options as IndexOptions & { includePaths?: string[]; excludePaths?: string[] });
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
success: true,
|
|
234
|
+
message: `Successfully indexed project directory: ${projectDir}`,
|
|
235
|
+
stats: {
|
|
236
|
+
totalFiles: stats.totalFiles,
|
|
237
|
+
totalBlocks: stats.totalBlocks,
|
|
238
|
+
lastUpdated: new Date(stats.lastUpdatedAt).toISOString(),
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
} catch (error) {
|
|
242
|
+
// Return error but don't throw - setup should continue even if indexing fails
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
message: `Indexing may have encountered issues: ${String(error)}`,
|
|
246
|
+
error: String(error),
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Get global indexing statistics
|
|
253
|
+
*/
|
|
254
|
+
async getStats(): Promise<ServiceTypes.StatsOperationResult> {
|
|
255
|
+
try {
|
|
256
|
+
const stats = await this._searchEngine.getStats();
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
success: true,
|
|
260
|
+
stats: {
|
|
261
|
+
totalFiles: stats.totalFiles,
|
|
262
|
+
totalBlocks: stats.totalBlocks,
|
|
263
|
+
indexedFiles: stats.indexedFiles,
|
|
264
|
+
lastUpdated: new Date(stats.lastUpdatedAt).toISOString(),
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
} catch (error) {
|
|
268
|
+
return {
|
|
269
|
+
success: false,
|
|
270
|
+
error: String(error),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get detailed index information
|
|
277
|
+
*/
|
|
278
|
+
async getIndexInfo(): Promise<ServiceTypes.IndexInfoOperationResult> {
|
|
279
|
+
try {
|
|
280
|
+
const info = await this._indexInformationService.getDetailedIndexInfo();
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
success: true,
|
|
284
|
+
data: info,
|
|
285
|
+
};
|
|
286
|
+
} catch (error) {
|
|
287
|
+
return {
|
|
288
|
+
success: false,
|
|
289
|
+
error: String(error),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Get file statistics
|
|
296
|
+
*/
|
|
297
|
+
async getFileStatistics(
|
|
298
|
+
params: ServiceTypes.FileStatisticsParams
|
|
299
|
+
): Promise<ServiceTypes.FileStatisticsOperationResult> {
|
|
300
|
+
try {
|
|
301
|
+
const stats = await this._indexInformationService.getFileStatistics(
|
|
302
|
+
params.filePath
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
success: true,
|
|
307
|
+
data: stats,
|
|
308
|
+
};
|
|
309
|
+
} catch (error) {
|
|
310
|
+
return {
|
|
311
|
+
success: false,
|
|
312
|
+
error: String(error),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get search history for a session
|
|
319
|
+
*/
|
|
320
|
+
getSearchHistory(
|
|
321
|
+
params: ServiceTypes.SearchHistoryParams
|
|
322
|
+
): ServiceTypes.SearchHistoryOperationResult {
|
|
323
|
+
try {
|
|
324
|
+
const history = this._sessionManager.getSearchHistory(params.sessionId);
|
|
325
|
+
|
|
326
|
+
if (!history) {
|
|
327
|
+
return {
|
|
328
|
+
success: false,
|
|
329
|
+
error: `Session not found: ${params.sessionId}`,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
success: true,
|
|
335
|
+
data: history,
|
|
336
|
+
};
|
|
337
|
+
} catch (error) {
|
|
338
|
+
return {
|
|
339
|
+
success: false,
|
|
340
|
+
error: String(error),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Start a reindex operation
|
|
347
|
+
*/
|
|
348
|
+
async startReindex(
|
|
349
|
+
params: ServiceTypes.StartReindexParams
|
|
350
|
+
): Promise<ServiceTypes.StartReindexOperationResult> {
|
|
351
|
+
try {
|
|
352
|
+
// startReindex only takes dirPath as string, not an object
|
|
353
|
+
const stats = await this._reindexManager.startReindex(params.dirPath);
|
|
354
|
+
|
|
355
|
+
// Generate a simple reindexId
|
|
356
|
+
const reindexId = `reindex-${Date.now()}`;
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
data: {
|
|
361
|
+
reindexId,
|
|
362
|
+
dirPath: params.dirPath,
|
|
363
|
+
mode: params.mode || 'incremental',
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
} catch (error) {
|
|
367
|
+
return {
|
|
368
|
+
success: false,
|
|
369
|
+
error: String(error),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Get reindex operation status
|
|
376
|
+
*/
|
|
377
|
+
getReindexStatus(
|
|
378
|
+
params: ServiceTypes.GetReindexStatusParams
|
|
379
|
+
): ServiceTypes.GetReindexStatusOperationResult {
|
|
380
|
+
try {
|
|
381
|
+
// Get basic progress information
|
|
382
|
+
const progress = this._reindexManager.getProgress();
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
success: true,
|
|
386
|
+
data: {
|
|
387
|
+
reindexId: params.reindexId,
|
|
388
|
+
status: this._reindexManager.isReindexingNow() ? 'in_progress' : 'completed',
|
|
389
|
+
filesProcessed: progress.filesProcessed,
|
|
390
|
+
totalFiles: progress.totalFiles,
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
} catch (error) {
|
|
394
|
+
return {
|
|
395
|
+
success: false,
|
|
396
|
+
error: String(error),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* List all indexed directories
|
|
403
|
+
*/
|
|
404
|
+
async listIndexedDirs(): Promise<ServiceTypes.ListIndexedDirsOperationResult> {
|
|
405
|
+
try {
|
|
406
|
+
// TODO: Implement proper directory listing
|
|
407
|
+
// For now, return the project directory
|
|
408
|
+
const dirs = [this._projectDir];
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
success: true,
|
|
412
|
+
data: dirs,
|
|
413
|
+
};
|
|
414
|
+
} catch (error) {
|
|
415
|
+
return {
|
|
416
|
+
success: false,
|
|
417
|
+
error: String(error),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Create a new session
|
|
424
|
+
*/
|
|
425
|
+
createSession(): ServiceTypes.CreateSessionResponse {
|
|
426
|
+
return {
|
|
427
|
+
sessionId: this._sessionManager.createSession(),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { SearchEngine, type IndexStats } from '@ngao/search-core';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
|
|
4
|
+
export interface ReindexEvent {
|
|
5
|
+
status: 'started' | 'in_progress' | 'completed' | 'error'
|
|
6
|
+
filesProcessed: number
|
|
7
|
+
totalFiles: number
|
|
8
|
+
currentFile?: string
|
|
9
|
+
error?: Error
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ReindexManager extends EventEmitter {
|
|
13
|
+
private isReindexing = false
|
|
14
|
+
private filesProcessed = 0
|
|
15
|
+
private totalFiles = 0
|
|
16
|
+
|
|
17
|
+
constructor(private searchEngine: SearchEngine) {
|
|
18
|
+
super()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async startReindex(dirPath: string): Promise<IndexStats> {
|
|
22
|
+
if (this.isReindexing) {
|
|
23
|
+
throw new Error('Reindexing already in progress')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.isReindexing = true
|
|
27
|
+
this.filesProcessed = 0
|
|
28
|
+
this.totalFiles = 0
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
this.emit('reindex', {
|
|
32
|
+
status: 'started',
|
|
33
|
+
filesProcessed: 0,
|
|
34
|
+
totalFiles: 0,
|
|
35
|
+
} as ReindexEvent)
|
|
36
|
+
|
|
37
|
+
const stats = await this.searchEngine.indexDirectory(dirPath)
|
|
38
|
+
|
|
39
|
+
this.filesProcessed = stats.totalFiles
|
|
40
|
+
this.totalFiles = stats.totalFiles
|
|
41
|
+
|
|
42
|
+
this.emit('reindex', {
|
|
43
|
+
status: 'completed',
|
|
44
|
+
filesProcessed: this.filesProcessed,
|
|
45
|
+
totalFiles: this.totalFiles,
|
|
46
|
+
} as ReindexEvent)
|
|
47
|
+
|
|
48
|
+
return stats
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.emit('reindex', {
|
|
51
|
+
status: 'error',
|
|
52
|
+
filesProcessed: this.filesProcessed,
|
|
53
|
+
totalFiles: this.totalFiles,
|
|
54
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
55
|
+
} as ReindexEvent)
|
|
56
|
+
throw error
|
|
57
|
+
} finally {
|
|
58
|
+
this.isReindexing = false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async reindexFile(filePath: string): Promise<void> {
|
|
63
|
+
try {
|
|
64
|
+
// TODO: @ngao/search-core doesn't have reindexFile method
|
|
65
|
+
// await this.searchEngine.reindexFile(filePath)
|
|
66
|
+
// For now, reindex the parent directory
|
|
67
|
+
const path = require('path');
|
|
68
|
+
const dirPath = path.dirname(filePath);
|
|
69
|
+
await this.searchEngine.indexDirectory(dirPath);
|
|
70
|
+
this.emit('file-reindexed', { filePath })
|
|
71
|
+
} catch (error) {
|
|
72
|
+
this.emit('file-reindex-error', {
|
|
73
|
+
filePath,
|
|
74
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
75
|
+
})
|
|
76
|
+
throw error
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
isReindexingNow(): boolean {
|
|
81
|
+
return this.isReindexing
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getProgress(): { filesProcessed: number; totalFiles: number } {
|
|
85
|
+
return {
|
|
86
|
+
filesProcessed: this.filesProcessed,
|
|
87
|
+
totalFiles: this.totalFiles,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|