@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.
Files changed (259) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.env.example +7 -0
  3. package/.eslintrc.json +20 -0
  4. package/.github/workflows/build.yml +39 -0
  5. package/.github/workflows/release.yml +34 -0
  6. package/.github/workflows/test.yml +35 -0
  7. package/.mcp-config.json +14 -0
  8. package/.prettierrc.json +10 -0
  9. package/LICENSE +17 -0
  10. package/Makefile +26 -0
  11. package/README.md +57 -172
  12. package/config.example.json +8 -0
  13. package/dist/backend/api/search-engine.d.ts +40 -0
  14. package/dist/backend/api/search-engine.d.ts.map +1 -0
  15. package/dist/backend/api/search-engine.js +227 -0
  16. package/dist/backend/api/search-engine.js.map +1 -0
  17. package/dist/backend/core/block-impl.d.ts +32 -0
  18. package/dist/backend/core/block-impl.d.ts.map +1 -0
  19. package/dist/backend/core/block-impl.js +33 -0
  20. package/dist/backend/core/block-impl.js.map +1 -0
  21. package/dist/backend/core/config-loader.d.ts +68 -0
  22. package/dist/backend/core/config-loader.d.ts.map +1 -0
  23. package/dist/backend/core/config-loader.js +234 -0
  24. package/dist/backend/core/config-loader.js.map +1 -0
  25. package/dist/backend/core/constants.d.ts +39 -0
  26. package/dist/backend/core/constants.d.ts.map +1 -0
  27. package/dist/backend/core/constants.js +57 -0
  28. package/dist/backend/core/constants.js.map +1 -0
  29. package/dist/backend/core/enums.d.ts +54 -0
  30. package/dist/backend/core/enums.d.ts.map +1 -0
  31. package/dist/backend/core/enums.js +61 -0
  32. package/dist/backend/core/enums.js.map +1 -0
  33. package/dist/backend/core/errors.d.ts +83 -0
  34. package/dist/backend/core/errors.d.ts.map +1 -0
  35. package/dist/backend/core/errors.js +151 -0
  36. package/dist/backend/core/errors.js.map +1 -0
  37. package/dist/backend/core/logger.d.ts +68 -0
  38. package/dist/backend/core/logger.d.ts.map +1 -0
  39. package/dist/backend/core/logger.js +151 -0
  40. package/dist/backend/core/logger.js.map +1 -0
  41. package/dist/backend/core/models.d.ts +332 -0
  42. package/dist/backend/core/models.d.ts.map +1 -0
  43. package/dist/backend/core/models.js +6 -0
  44. package/dist/backend/core/models.js.map +1 -0
  45. package/dist/backend/core/service-types.d.ts +184 -0
  46. package/dist/backend/core/service-types.d.ts.map +1 -0
  47. package/dist/backend/core/service-types.js +7 -0
  48. package/dist/backend/core/service-types.js.map +1 -0
  49. package/dist/backend/core/types.d.ts +219 -0
  50. package/dist/backend/core/types.d.ts.map +1 -0
  51. package/dist/backend/core/types.js +109 -0
  52. package/dist/backend/core/types.js.map +1 -0
  53. package/dist/backend/index.d.ts +5 -0
  54. package/dist/backend/index.d.ts.map +1 -0
  55. package/dist/backend/index.js +13 -0
  56. package/dist/backend/index.js.map +1 -0
  57. package/dist/backend/indexing/block-extractor.d.ts +22 -0
  58. package/dist/backend/indexing/block-extractor.d.ts.map +1 -0
  59. package/dist/backend/indexing/block-extractor.js +52 -0
  60. package/dist/backend/indexing/block-extractor.js.map +1 -0
  61. package/dist/backend/indexing/index-builder.d.ts +26 -0
  62. package/dist/backend/indexing/index-builder.d.ts.map +1 -0
  63. package/dist/backend/indexing/index-builder.js +71 -0
  64. package/dist/backend/indexing/index-builder.js.map +1 -0
  65. package/dist/backend/parsers/base-file-parser.d.ts +134 -0
  66. package/dist/backend/parsers/base-file-parser.d.ts.map +1 -0
  67. package/dist/backend/parsers/base-file-parser.js +149 -0
  68. package/dist/backend/parsers/base-file-parser.js.map +1 -0
  69. package/dist/backend/parsers/javascript-parser.d.ts +36 -0
  70. package/dist/backend/parsers/javascript-parser.d.ts.map +1 -0
  71. package/dist/backend/parsers/javascript-parser.js +194 -0
  72. package/dist/backend/parsers/javascript-parser.js.map +1 -0
  73. package/dist/backend/parsers/json-parser.d.ts +15 -0
  74. package/dist/backend/parsers/json-parser.d.ts.map +1 -0
  75. package/dist/backend/parsers/json-parser.js +75 -0
  76. package/dist/backend/parsers/json-parser.js.map +1 -0
  77. package/dist/backend/parsers/markdown-parser.d.ts +17 -0
  78. package/dist/backend/parsers/markdown-parser.d.ts.map +1 -0
  79. package/dist/backend/parsers/markdown-parser.js +94 -0
  80. package/dist/backend/parsers/markdown-parser.js.map +1 -0
  81. package/dist/backend/parsers/parser-factory.d.ts +43 -0
  82. package/dist/backend/parsers/parser-factory.d.ts.map +1 -0
  83. package/dist/backend/parsers/parser-factory.js +149 -0
  84. package/dist/backend/parsers/parser-factory.js.map +1 -0
  85. package/dist/backend/parsers/python-parser.d.ts +21 -0
  86. package/dist/backend/parsers/python-parser.d.ts.map +1 -0
  87. package/dist/backend/parsers/python-parser.js +185 -0
  88. package/dist/backend/parsers/python-parser.js.map +1 -0
  89. package/dist/backend/parsers/yaml-parser.d.ts +16 -0
  90. package/dist/backend/parsers/yaml-parser.d.ts.map +1 -0
  91. package/dist/backend/parsers/yaml-parser.js +81 -0
  92. package/dist/backend/parsers/yaml-parser.js.map +1 -0
  93. package/dist/backend/repositories/implementations/lancedb-block-repository.d.ts +125 -0
  94. package/dist/backend/repositories/implementations/lancedb-block-repository.d.ts.map +1 -0
  95. package/dist/backend/repositories/implementations/lancedb-block-repository.js +505 -0
  96. package/dist/backend/repositories/implementations/lancedb-block-repository.js.map +1 -0
  97. package/dist/backend/repositories/implementations/lancedb-metadata-repository.d.ts +107 -0
  98. package/dist/backend/repositories/implementations/lancedb-metadata-repository.d.ts.map +1 -0
  99. package/dist/backend/repositories/implementations/lancedb-metadata-repository.js +275 -0
  100. package/dist/backend/repositories/implementations/lancedb-metadata-repository.js.map +1 -0
  101. package/dist/backend/repositories/implementations/memory-cache.d.ts +18 -0
  102. package/dist/backend/repositories/implementations/memory-cache.d.ts.map +1 -0
  103. package/dist/backend/repositories/implementations/memory-cache.js +53 -0
  104. package/dist/backend/repositories/implementations/memory-cache.js.map +1 -0
  105. package/dist/backend/repositories/repository.interface.d.ts +334 -0
  106. package/dist/backend/repositories/repository.interface.d.ts.map +1 -0
  107. package/dist/backend/repositories/repository.interface.js +7 -0
  108. package/dist/backend/repositories/repository.interface.js.map +1 -0
  109. package/dist/backend/search/context-extractor.d.ts +29 -0
  110. package/dist/backend/search/context-extractor.d.ts.map +1 -0
  111. package/dist/backend/search/context-extractor.js +106 -0
  112. package/dist/backend/search/context-extractor.js.map +1 -0
  113. package/dist/backend/search/multi-index-searcher.d.ts +28 -0
  114. package/dist/backend/search/multi-index-searcher.d.ts.map +1 -0
  115. package/dist/backend/search/multi-index-searcher.js +81 -0
  116. package/dist/backend/search/multi-index-searcher.js.map +1 -0
  117. package/dist/backend/search/query-parser.d.ts +37 -0
  118. package/dist/backend/search/query-parser.d.ts.map +1 -0
  119. package/dist/backend/search/query-parser.js +145 -0
  120. package/dist/backend/search/query-parser.js.map +1 -0
  121. package/dist/backend/search/ranking-engine.d.ts +31 -0
  122. package/dist/backend/search/ranking-engine.d.ts.map +1 -0
  123. package/dist/backend/search/ranking-engine.js +165 -0
  124. package/dist/backend/search/ranking-engine.js.map +1 -0
  125. package/dist/backend/search/result-formatter.d.ts +29 -0
  126. package/dist/backend/search/result-formatter.d.ts.map +1 -0
  127. package/dist/backend/search/result-formatter.js +70 -0
  128. package/dist/backend/search/result-formatter.js.map +1 -0
  129. package/dist/backend/service-types.d.ts +184 -0
  130. package/dist/backend/service-types.d.ts.map +1 -0
  131. package/dist/backend/service-types.js +7 -0
  132. package/dist/backend/service-types.js.map +1 -0
  133. package/dist/backend/services/embedding-service.d.ts +75 -0
  134. package/dist/backend/services/embedding-service.d.ts.map +1 -0
  135. package/dist/backend/services/embedding-service.js +298 -0
  136. package/dist/backend/services/embedding-service.js.map +1 -0
  137. package/dist/backend/services/file-watcher.d.ts +17 -0
  138. package/dist/backend/services/file-watcher.d.ts.map +1 -0
  139. package/dist/backend/services/file-watcher.js +92 -0
  140. package/dist/backend/services/file-watcher.js.map +1 -0
  141. package/dist/backend/services/index-information-service.d.ts +114 -0
  142. package/dist/backend/services/index-information-service.d.ts.map +1 -0
  143. package/dist/backend/services/index-information-service.js +104 -0
  144. package/dist/backend/services/index-information-service.js.map +1 -0
  145. package/dist/backend/services/ngao-search-service.d.ts +107 -0
  146. package/dist/backend/services/ngao-search-service.d.ts.map +1 -0
  147. package/dist/backend/services/ngao-search-service.js +384 -0
  148. package/dist/backend/services/ngao-search-service.js.map +1 -0
  149. package/dist/backend/services/quantization-service.d.ts +53 -0
  150. package/dist/backend/services/quantization-service.d.ts.map +1 -0
  151. package/dist/backend/services/quantization-service.js +84 -0
  152. package/dist/backend/services/quantization-service.js.map +1 -0
  153. package/dist/backend/services/reindex-manager.d.ts +25 -0
  154. package/dist/backend/services/reindex-manager.d.ts.map +1 -0
  155. package/dist/backend/services/reindex-manager.js +78 -0
  156. package/dist/backend/services/reindex-manager.js.map +1 -0
  157. package/dist/backend/services/session-manager.d.ts +115 -0
  158. package/dist/backend/services/session-manager.d.ts.map +1 -0
  159. package/dist/backend/services/session-manager.js +150 -0
  160. package/dist/backend/services/session-manager.js.map +1 -0
  161. package/dist/backend/services/vector-search-service.d.ts +81 -0
  162. package/dist/backend/services/vector-search-service.d.ts.map +1 -0
  163. package/dist/backend/services/vector-search-service.js +143 -0
  164. package/dist/backend/services/vector-search-service.js.map +1 -0
  165. package/dist/backend/utils/file-utils.d.ts +92 -0
  166. package/dist/backend/utils/file-utils.d.ts.map +1 -0
  167. package/dist/backend/utils/file-utils.js +247 -0
  168. package/dist/backend/utils/file-utils.js.map +1 -0
  169. package/dist/cli/setup.d.ts +4 -0
  170. package/dist/cli/setup.d.ts.map +1 -0
  171. package/dist/cli/setup.js +138 -0
  172. package/dist/cli/setup.js.map +1 -0
  173. package/dist/index.d.ts +6 -0
  174. package/dist/index.d.ts.map +1 -0
  175. package/dist/index.js +22 -0
  176. package/dist/index.js.map +1 -0
  177. package/dist/main.d.ts +14 -0
  178. package/dist/main.d.ts.map +1 -0
  179. package/dist/main.js +7 -67075
  180. package/dist/main.js.map +1 -0
  181. package/dist/mcp/tool-schemas.d.ts +205 -0
  182. package/dist/mcp/tool-schemas.d.ts.map +1 -0
  183. package/dist/mcp/tool-schemas.js +391 -0
  184. package/dist/mcp/tool-schemas.js.map +1 -0
  185. package/dist/server/logger.d.ts +50 -0
  186. package/dist/server/logger.d.ts.map +1 -0
  187. package/dist/server/logger.js +77 -0
  188. package/dist/server/logger.js.map +1 -0
  189. package/dist/server/tool-registry.d.ts +64 -0
  190. package/dist/server/tool-registry.d.ts.map +1 -0
  191. package/dist/server/tool-registry.js +93 -0
  192. package/dist/server/tool-registry.js.map +1 -0
  193. package/dist/server/transports/mcp-transport.d.ts +31 -0
  194. package/dist/server/transports/mcp-transport.d.ts.map +1 -0
  195. package/dist/server/transports/mcp-transport.js +331 -0
  196. package/dist/server/transports/mcp-transport.js.map +1 -0
  197. package/dist/server/transports/rest-transport.d.ts +36 -0
  198. package/dist/server/transports/rest-transport.d.ts.map +1 -0
  199. package/dist/server/transports/rest-transport.js +250 -0
  200. package/dist/server/transports/rest-transport.js.map +1 -0
  201. package/docs/API.md +116 -0
  202. package/docs/ARCHITECTURE.md +101 -0
  203. package/docs/FILE_WATCHING.md +120 -0
  204. package/docs/INSTALLATION.md +87 -0
  205. package/docs/MCP_INTEGRATION.md +108 -0
  206. package/docs/README.md +288 -0
  207. package/docs/USAGE.md +123 -0
  208. package/docs/architecture-design-standards/01_ARCHITECTURE.md +863 -0
  209. package/docs/architecture-design-standards/02_SEARCH_ENGINE_DESIGN.md +958 -0
  210. package/docs/architecture-design-standards/03_DATAFLOW.md +1000 -0
  211. package/docs/architecture-design-standards/04_VISUAL_GUIDE.md +922 -0
  212. package/docs/architecture-design-standards/05_REPOSITORY_PATTERN_GUIDE.md +503 -0
  213. package/docs/architecture-design-standards/06_IMPLEMENTATION_PATTERNS.md +1026 -0
  214. package/docs/architecture-design-standards/07_TYPESCRIPT_GUIDE.md +1027 -0
  215. package/docs/architecture-design-standards/08_CODING_STANDARDS.md +1274 -0
  216. package/docs/reference/01_START_HERE.md +108 -0
  217. package/docs/reference/02_QUICK_REFERENCE.md +363 -0
  218. package/docs/reference/03_DOCUMENTATION_INDEX.md +293 -0
  219. package/docs/reference/04_DELIVERY_SUMMARY.md +463 -0
  220. package/docs/reference/05_IMPLEMENTATION_OVERVIEW.md +319 -0
  221. package/docs/reference/06_RESEARCH_SUMMARY.md +519 -0
  222. package/docs/tracking/03_IMPLEMENTATION_ROADMAP.md +788 -0
  223. package/jest.config.json +12 -0
  224. package/package.json +46 -53
  225. package/prepend-shebang.js +18 -0
  226. package/scripts/setup-mcp.sh +66 -0
  227. package/src/backend/index.ts +5 -0
  228. package/src/backend/service-types.ts +219 -0
  229. package/src/backend/services/file-watcher.ts +79 -0
  230. package/src/backend/services/ngao-search-service.ts +430 -0
  231. package/src/backend/services/reindex-manager.ts +90 -0
  232. package/src/backend/services/session-manager.ts +214 -0
  233. package/src/cli/setup.ts +122 -0
  234. package/src/index.ts +6 -0
  235. package/src/main.ts +225 -0
  236. package/src/mcp/tool-schemas.ts +439 -0
  237. package/src/server/logger.ts +88 -0
  238. package/src/server/tool-registry.ts +117 -0
  239. package/src/server/transports/mcp-transport.ts +374 -0
  240. package/src/server/transports/rest-transport.ts +258 -0
  241. package/tests/unit/agent-tools.test.ts +454 -0
  242. package/tests/unit/file-watcher.test.d.ts +2 -0
  243. package/tests/unit/file-watcher.test.d.ts.map +1 -0
  244. package/tests/unit/file-watcher.test.js +9 -0
  245. package/tests/unit/file-watcher.test.js.map +1 -0
  246. package/tests/unit/file-watcher.test.ts +7 -0
  247. package/tests/unit/search-integration.test.ts +256 -0
  248. package/tests/unit/services.test.d.ts +2 -0
  249. package/tests/unit/services.test.d.ts.map +1 -0
  250. package/tests/unit/services.test.js +9 -0
  251. package/tests/unit/services.test.js.map +1 -0
  252. package/tests/unit/services.test.ts +7 -0
  253. package/tsconfig.json +23 -0
  254. package/webpack.backend.config.js +60 -0
  255. package/webpack.config.js +34 -0
  256. package/models/Xenova/all-MiniLM-L6-v2/config.json +0 -25
  257. package/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  258. package/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +0 -30686
  259. 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
+ }