@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,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager for NGAO Search
|
|
3
|
+
* Manages user sessions and tracks search history
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { v4 as uuid } from 'uuid';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents a user session with search history
|
|
10
|
+
*/
|
|
11
|
+
export interface Session {
|
|
12
|
+
/** Unique session identifier */
|
|
13
|
+
sessionId: string;
|
|
14
|
+
/** Unix timestamp when session was created */
|
|
15
|
+
startedAt: number;
|
|
16
|
+
/** Unix timestamp of last activity */
|
|
17
|
+
lastActivity: number;
|
|
18
|
+
/** Search history entries for this session */
|
|
19
|
+
searchHistory: SearchHistoryEntry[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Represents a single search query in history
|
|
24
|
+
*/
|
|
25
|
+
export interface SearchHistoryEntry {
|
|
26
|
+
/** Unique identifier for this history entry */
|
|
27
|
+
id: string;
|
|
28
|
+
/** Original search query string */
|
|
29
|
+
query: string;
|
|
30
|
+
/** Unix timestamp when search was performed */
|
|
31
|
+
timestamp: number;
|
|
32
|
+
/** Number of results returned */
|
|
33
|
+
resultCount: number;
|
|
34
|
+
/** Execution time in milliseconds */
|
|
35
|
+
executionTimeMs: number;
|
|
36
|
+
/** Optional filters applied to search */
|
|
37
|
+
filters?: Record<string, unknown>;
|
|
38
|
+
/** Item types queried */
|
|
39
|
+
itemTypesQueried?: string[];
|
|
40
|
+
/** File types queried */
|
|
41
|
+
fileTypesQueried?: string[];
|
|
42
|
+
/** Minimum relevance threshold applied */
|
|
43
|
+
minRelevanceApplied?: number;
|
|
44
|
+
/** Brief explanation of why results matched */
|
|
45
|
+
explanation?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Manages user sessions and search history
|
|
50
|
+
* Provides session lifecycle management and history tracking
|
|
51
|
+
*/
|
|
52
|
+
export class SessionManager {
|
|
53
|
+
/** In-memory store of active sessions */
|
|
54
|
+
private _sessions: Map<string, Session> = new Map();
|
|
55
|
+
|
|
56
|
+
/** Cleanup interval timer */
|
|
57
|
+
private _cleanupTimer: ReturnType<typeof setInterval> | null = null;
|
|
58
|
+
|
|
59
|
+
/** Session timeout in milliseconds (30 minutes) */
|
|
60
|
+
private readonly SESSION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
61
|
+
|
|
62
|
+
/** Cleanup interval in milliseconds (1 minute) */
|
|
63
|
+
private readonly CLEANUP_INTERVAL_MS = 60 * 1000;
|
|
64
|
+
|
|
65
|
+
/** Maximum search history size per session */
|
|
66
|
+
private readonly MAX_HISTORY_SIZE = 100;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Initialize SessionManager and start cleanup timer
|
|
70
|
+
*/
|
|
71
|
+
public constructor() {
|
|
72
|
+
this._startCleanupTimer();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create a new session
|
|
77
|
+
* @returns New session ID
|
|
78
|
+
*/
|
|
79
|
+
public createSession(): string {
|
|
80
|
+
const sessionId = uuid();
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
|
|
83
|
+
this._sessions.set(sessionId, {
|
|
84
|
+
sessionId,
|
|
85
|
+
startedAt: now,
|
|
86
|
+
lastActivity: now,
|
|
87
|
+
searchHistory: [],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return sessionId;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Retrieve an existing session
|
|
95
|
+
* @param sessionId - Session ID to retrieve
|
|
96
|
+
* @returns Session object or null if not found
|
|
97
|
+
*/
|
|
98
|
+
public getSession(sessionId: string): Session | null {
|
|
99
|
+
return this._sessions.get(sessionId) || null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Add a search entry to session history
|
|
104
|
+
* @param sessionId - Session ID
|
|
105
|
+
* @param entry - Search history entry to add
|
|
106
|
+
*/
|
|
107
|
+
public addSearchToHistory(sessionId: string, entry: SearchHistoryEntry): void {
|
|
108
|
+
const session = this._sessions.get(sessionId);
|
|
109
|
+
if (!session) {
|
|
110
|
+
return; // Silently fail if session not found
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Add to history
|
|
114
|
+
session.searchHistory.push(entry);
|
|
115
|
+
|
|
116
|
+
// Enforce max history size (keep most recent)
|
|
117
|
+
if (session.searchHistory.length > this.MAX_HISTORY_SIZE) {
|
|
118
|
+
session.searchHistory = session.searchHistory.slice(-this.MAX_HISTORY_SIZE);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Update last activity
|
|
122
|
+
session.lastActivity = Date.now();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Retrieve search history for a session
|
|
127
|
+
* @param sessionId - Session ID
|
|
128
|
+
* @returns Array of search history entries or null if session not found
|
|
129
|
+
*/
|
|
130
|
+
public getSearchHistory(sessionId: string): SearchHistoryEntry[] | null {
|
|
131
|
+
const session = this._sessions.get(sessionId);
|
|
132
|
+
if (!session) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Update last activity
|
|
137
|
+
session.lastActivity = Date.now();
|
|
138
|
+
|
|
139
|
+
return session.searchHistory;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* End a session and remove it
|
|
144
|
+
* @param sessionId - Session ID to end
|
|
145
|
+
*/
|
|
146
|
+
public endSession(sessionId: string): void {
|
|
147
|
+
this._sessions.delete(sessionId);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get all active sessions
|
|
152
|
+
* @returns Array of all active session IDs
|
|
153
|
+
*/
|
|
154
|
+
public getActiveSessions(): string[] {
|
|
155
|
+
return Array.from(this._sessions.keys());
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Cleanup expired sessions
|
|
160
|
+
* @private
|
|
161
|
+
*/
|
|
162
|
+
private _cleanupExpiredSessions(): void {
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
const expiredSessionIds: string[] = [];
|
|
165
|
+
|
|
166
|
+
// Find expired sessions
|
|
167
|
+
for (const [sessionId, session] of this._sessions.entries()) {
|
|
168
|
+
if (now - session.lastActivity > this.SESSION_TIMEOUT_MS) {
|
|
169
|
+
expiredSessionIds.push(sessionId);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Remove expired sessions
|
|
174
|
+
for (const sessionId of expiredSessionIds) {
|
|
175
|
+
this._sessions.delete(sessionId);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Start the cleanup timer
|
|
181
|
+
* @private
|
|
182
|
+
*/
|
|
183
|
+
private _startCleanupTimer(): void {
|
|
184
|
+
this._cleanupTimer = setInterval(() => {
|
|
185
|
+
this._cleanupExpiredSessions();
|
|
186
|
+
}, this.CLEANUP_INTERVAL_MS);
|
|
187
|
+
|
|
188
|
+
// Unref timer so it doesn't prevent process exit
|
|
189
|
+
if (this._cleanupTimer.unref) {
|
|
190
|
+
this._cleanupTimer.unref();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Stop the cleanup timer
|
|
196
|
+
* @private
|
|
197
|
+
*/
|
|
198
|
+
private _stopCleanupTimer(): void {
|
|
199
|
+
if (this._cleanupTimer) {
|
|
200
|
+
clearInterval(this._cleanupTimer);
|
|
201
|
+
this._cleanupTimer = null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Destroy the session manager (cleanup resources)
|
|
207
|
+
*/
|
|
208
|
+
public destroy(): void {
|
|
209
|
+
this._stopCleanupTimer();
|
|
210
|
+
this._sessions.clear();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
package/src/cli/setup.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as readline from 'readline';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
import * as os from 'os';
|
|
7
|
+
import { NgaoSearchService } from '../backend/services/ngao-search-service';
|
|
8
|
+
|
|
9
|
+
const rl = readline.createInterface({
|
|
10
|
+
input: process.stdin,
|
|
11
|
+
output: process.stdout,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function question(prompt: string): Promise<string> {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
rl.question(prompt, (answer) => {
|
|
17
|
+
resolve(answer);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function setupMCP(): Promise<{ projectDir: string }> {
|
|
23
|
+
console.log('\nš§ NGAO Search - MCP Setup for Claude Code\n');
|
|
24
|
+
|
|
25
|
+
// Ask for project directory
|
|
26
|
+
const projectDir = await question('š Enter your project directory path (or press Enter for current): ');
|
|
27
|
+
const resolvedProjectDir = projectDir.trim() || process.cwd();
|
|
28
|
+
|
|
29
|
+
// Create .ngao-search config in project
|
|
30
|
+
const projectConfigPath = path.join(resolvedProjectDir, '.ngao-search.json');
|
|
31
|
+
if (!fs.existsSync(projectConfigPath)) {
|
|
32
|
+
// Generate UUID for this project to isolate its database
|
|
33
|
+
const projectUUID = uuidv4();
|
|
34
|
+
const projectConfig = {
|
|
35
|
+
projectId: projectUUID,
|
|
36
|
+
includePaths: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.py', '**/*.md'],
|
|
37
|
+
excludePaths: ['node_modules/**', 'dist/**', '.git/**'],
|
|
38
|
+
};
|
|
39
|
+
fs.writeFileSync(projectConfigPath, JSON.stringify(projectConfig, null, 2));
|
|
40
|
+
console.log(`ā
Project config created: ${projectConfigPath}`);
|
|
41
|
+
console.log(`š Project ID: ${projectUUID}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Create .mcp-config.json in project for reference
|
|
45
|
+
const mcpConfigPath = path.join(resolvedProjectDir, '.mcp-config.json');
|
|
46
|
+
const mcpConfig = {
|
|
47
|
+
mcpServers: {
|
|
48
|
+
'ngao-search': {
|
|
49
|
+
command: 'npx',
|
|
50
|
+
args: ['ngao-search'],
|
|
51
|
+
env: {
|
|
52
|
+
NGAO_SEARCH_PROJECT: resolvedProjectDir,
|
|
53
|
+
MCP_TRANSPORT: 'stdio',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
|
|
59
|
+
console.log(`ā
MCP config created: ${mcpConfigPath}`);
|
|
60
|
+
|
|
61
|
+
// Register with Claude Code CLI using `claude mcp add`
|
|
62
|
+
try {
|
|
63
|
+
console.log('\nš” Registering with Claude Code CLI...');
|
|
64
|
+
execSync(
|
|
65
|
+
`cd "${resolvedProjectDir}" && claude mcp add -e NGAO_SEARCH_PROJECT="${resolvedProjectDir}" -e MCP_TRANSPORT=stdio -- ngao-search npx ngao-search`,
|
|
66
|
+
{ stdio: 'pipe' }
|
|
67
|
+
);
|
|
68
|
+
console.log('ā
MCP server registered with Claude Code CLI');
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.log('ā ļø Could not auto-register with Claude Code CLI.');
|
|
71
|
+
console.log(' Please run this command manually in your project directory:');
|
|
72
|
+
console.log(`\n cd "${resolvedProjectDir}"`);
|
|
73
|
+
console.log(' claude mcp add -e NGAO_SEARCH_PROJECT="' + resolvedProjectDir + '" -e MCP_TRANSPORT=stdio -- ngao-search npx ngao-search\n');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Initialize database (embedding model will lazy-load on first search)
|
|
77
|
+
console.log('\nāļø Initializing database...');
|
|
78
|
+
let searchService: NgaoSearchService | null = null;
|
|
79
|
+
try {
|
|
80
|
+
searchService = new NgaoSearchService(resolvedProjectDir);
|
|
81
|
+
await searchService.ensureInitialized();
|
|
82
|
+
console.log('ā
Database initialized');
|
|
83
|
+
console.log(' Embedding model will load on first search');
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.warn('ā ļø Warning: Could not initialize database');
|
|
86
|
+
console.warn(` Error: ${String(error)}`);
|
|
87
|
+
console.log(' Database will be initialized on first use instead.\n');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Auto-index the project directory
|
|
91
|
+
if (searchService) {
|
|
92
|
+
console.log('\nš Auto-indexing project directory...');
|
|
93
|
+
try {
|
|
94
|
+
const indexResult = await searchService.autoIndexProjectDirectory(resolvedProjectDir);
|
|
95
|
+
if (indexResult.success && indexResult.stats) {
|
|
96
|
+
console.log('ā
Auto-indexing completed');
|
|
97
|
+
console.log(` š Indexed ${indexResult.stats.totalFiles} files with ${indexResult.stats.totalBlocks} code blocks`);
|
|
98
|
+
} else {
|
|
99
|
+
console.warn(`ā ļø Auto-indexing encountered issues: ${indexResult.error || 'Unknown error'}`);
|
|
100
|
+
console.log(' You can manually index later using the search tools\n');
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.warn('ā ļø Warning: Could not auto-index project directory');
|
|
104
|
+
console.warn(` Error: ${String(error)}`);
|
|
105
|
+
console.log(' You can manually index later using the search tools\n');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Show setup instructions
|
|
110
|
+
console.log('\nš Setup Complete!\n');
|
|
111
|
+
console.log('⨠NGAO Search is now integrated with Claude Code');
|
|
112
|
+
console.log('\nā¹ļø Configuration Details:');
|
|
113
|
+
console.log('š Project directory: ' + resolvedProjectDir);
|
|
114
|
+
console.log('š Server port: Automatically assigned');
|
|
115
|
+
console.log('š Project config: ' + projectConfigPath);
|
|
116
|
+
console.log('š MCP config: ' + mcpConfigPath + '\n');
|
|
117
|
+
console.log('š You can now use NGAO Search in Claude Code!\n');
|
|
118
|
+
|
|
119
|
+
rl.close();
|
|
120
|
+
return { projectDir: resolvedProjectDir };
|
|
121
|
+
}
|
|
122
|
+
|
package/src/index.ts
ADDED
package/src/main.ts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Entry Point for NGAO Search
|
|
3
|
+
* Supports multiple transport modes: stdio (MCP) or http (REST)
|
|
4
|
+
*
|
|
5
|
+
* Transport selection via environment variable:
|
|
6
|
+
* - MCP_TRANSPORT=stdio - Start MCP stdio server only (for Claude Desktop)
|
|
7
|
+
* - MCP_TRANSPORT=http - Start REST HTTP server only (default)
|
|
8
|
+
* - --setup - Run interactive MCP setup for Claude
|
|
9
|
+
* - --help, -h - Show help documentation with tool descriptions
|
|
10
|
+
*
|
|
11
|
+
* All transports share the same NgaoSearchService instance
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { NgaoSearchService } from './backend/services/ngao-search-service';
|
|
15
|
+
import { McpTransport } from './server/transports/mcp-transport';
|
|
16
|
+
import { RestTransport } from './server/transports/rest-transport';
|
|
17
|
+
import { createLogger } from './server/logger';
|
|
18
|
+
|
|
19
|
+
// Check for --setup flag for interactive setup
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
const setupMode = args.includes('--setup') || process.env.NGAO_SETUP;
|
|
22
|
+
const helpMode = args.includes('--help') || args.includes('-h') || process.env.NGAO_HELP;
|
|
23
|
+
|
|
24
|
+
// Show help if requested (check early before anything else)
|
|
25
|
+
if (helpMode) {
|
|
26
|
+
console.log(`
|
|
27
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
28
|
+
ā NGAO Search - Model Context Protocol Server ā
|
|
29
|
+
ā Local Code/Document Search with LLM-Friendly Output ā
|
|
30
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
31
|
+
|
|
32
|
+
š USAGE
|
|
33
|
+
ngao-search [COMMAND] [OPTIONS]
|
|
34
|
+
OR with npx:
|
|
35
|
+
npx ngao-search -- --help
|
|
36
|
+
OR with environment variable:
|
|
37
|
+
NGAO_HELP=true npx ngao-search
|
|
38
|
+
|
|
39
|
+
š§ SETUP
|
|
40
|
+
ngao-search --setup
|
|
41
|
+
OR: npx ngao-search -- --setup
|
|
42
|
+
OR: NGAO_SETUP=true npx ngao-search
|
|
43
|
+
Interactively configure NGAO Search for a project.
|
|
44
|
+
Creates .ngao-search.json with a unique projectId and database isolation.
|
|
45
|
+
|
|
46
|
+
š START SERVER
|
|
47
|
+
Default: Start HTTP REST API on a random available port
|
|
48
|
+
MCP_TRANSPORT=stdio ngao-search
|
|
49
|
+
OR: MCP_TRANSPORT=stdio npx ngao-search
|
|
50
|
+
Start MCP stdio server for Claude Code/Desktop integration
|
|
51
|
+
|
|
52
|
+
š” AVAILABLE TOOLS (for LLMs)
|
|
53
|
+
|
|
54
|
+
1. search [REQUIRED]
|
|
55
|
+
Search through indexed code and documentation
|
|
56
|
+
Parameters:
|
|
57
|
+
- query: string (required) - Search query
|
|
58
|
+
- maxResults: number (optional) - Max results to return (default: 100)
|
|
59
|
+
- sessionId: string (optional) - Session ID for history tracking
|
|
60
|
+
|
|
61
|
+
2. index [REQUIRED]
|
|
62
|
+
Index a directory for searching
|
|
63
|
+
Parameters:
|
|
64
|
+
- dirPath: string (required) - Directory path to index
|
|
65
|
+
|
|
66
|
+
3. list_indexed_dirs
|
|
67
|
+
List all indexed directories
|
|
68
|
+
No parameters required
|
|
69
|
+
|
|
70
|
+
4. get_stats
|
|
71
|
+
Get indexing statistics
|
|
72
|
+
No parameters required
|
|
73
|
+
|
|
74
|
+
5. get_index_info
|
|
75
|
+
Get detailed index information with file breakdown
|
|
76
|
+
No parameters required
|
|
77
|
+
|
|
78
|
+
6. get_file_statistics
|
|
79
|
+
Get per-file index statistics
|
|
80
|
+
Parameters:
|
|
81
|
+
- filePath: string (optional) - Specific file path
|
|
82
|
+
|
|
83
|
+
7. get_search_history
|
|
84
|
+
Get search history for a session
|
|
85
|
+
Parameters:
|
|
86
|
+
- sessionId: string (required) - Session ID
|
|
87
|
+
|
|
88
|
+
8. start_reindex
|
|
89
|
+
Start a reindex operation
|
|
90
|
+
Parameters:
|
|
91
|
+
- dirPath: string (required) - Directory to reindex
|
|
92
|
+
- mode: string (optional) - 'incremental' or 'full' (default: 'incremental')
|
|
93
|
+
|
|
94
|
+
9. get_reindex_status
|
|
95
|
+
Get reindex operation status
|
|
96
|
+
Parameters:
|
|
97
|
+
- reindexId: string (required) - Reindex operation ID
|
|
98
|
+
|
|
99
|
+
š KEY FEATURES
|
|
100
|
+
|
|
101
|
+
⢠š Multi-Language Support
|
|
102
|
+
Supports TypeScript, JavaScript, Python, Markdown, YAML, JSON, and more
|
|
103
|
+
|
|
104
|
+
⢠š§ Semantic Search
|
|
105
|
+
Uses vector embeddings for intelligent code/doc search
|
|
106
|
+
|
|
107
|
+
⢠šļø Project Isolation
|
|
108
|
+
Each project gets a unique database stored in ~/.ngao/ directory
|
|
109
|
+
|
|
110
|
+
⢠š¾ Persistent Storage
|
|
111
|
+
Uses LanceDB for reliable vector storage
|
|
112
|
+
|
|
113
|
+
⢠š Session Tracking
|
|
114
|
+
Track search history within sessions for context awareness
|
|
115
|
+
|
|
116
|
+
⢠š Reindexing
|
|
117
|
+
Incremental or full reindex support for keeping index up-to-date
|
|
118
|
+
|
|
119
|
+
āļø CONFIGURATION
|
|
120
|
+
|
|
121
|
+
Project config stored in .ngao-search.json:
|
|
122
|
+
{
|
|
123
|
+
"projectId": "unique-uuid-for-database-isolation",
|
|
124
|
+
"includePaths": ["**/*.ts", "**/*.js", "**/*.py", "**/*.md"],
|
|
125
|
+
"excludePaths": ["node_modules/**", "dist/**", ".git/**"]
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Database Location: ~/.ngao/{projectId}.lancedb
|
|
129
|
+
Metadata Location: ~/.ngao/{projectId}.metadata.json
|
|
130
|
+
|
|
131
|
+
šÆ WORKFLOW FOR LLMs
|
|
132
|
+
|
|
133
|
+
1. Call index() with your project directory
|
|
134
|
+
2. Call search() to find relevant code/docs
|
|
135
|
+
3. Use get_stats() to check indexing progress
|
|
136
|
+
4. Use get_index_info() to understand code structure
|
|
137
|
+
5. Call start_reindex() when code changes
|
|
138
|
+
6. Track session history with sessionId for context
|
|
139
|
+
|
|
140
|
+
š MORE INFO
|
|
141
|
+
github.com/ngao-team/ngao-search
|
|
142
|
+
|
|
143
|
+
`);
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// When setup completes, auto-start in MCP stdio mode for Claude
|
|
148
|
+
if (setupMode) {
|
|
149
|
+
process.env.MCP_TRANSPORT = 'stdio';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const transport = (process.env.MCP_TRANSPORT || 'http').toLowerCase();
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Main async function
|
|
156
|
+
*/
|
|
157
|
+
async function main(): Promise<void> {
|
|
158
|
+
// Run setup first if requested, then continue to start server
|
|
159
|
+
if (setupMode) {
|
|
160
|
+
try {
|
|
161
|
+
const { setupMCP } = await import('./cli/setup');
|
|
162
|
+
const { projectDir } = await setupMCP();
|
|
163
|
+
// Set environment vars for server startup
|
|
164
|
+
process.env.NGAO_SEARCH_PROJECT = projectDir;
|
|
165
|
+
console.log('\nš Starting NGAO Search MCP server...\n');
|
|
166
|
+
// Continue to server startup below
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error('Setup failed:', error);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Create shared service instance
|
|
175
|
+
const service = new NgaoSearchService();
|
|
176
|
+
|
|
177
|
+
// Eagerly initialize database on startup
|
|
178
|
+
// (embedding model will lazy-load on first search to avoid network dependency)
|
|
179
|
+
try {
|
|
180
|
+
await service.ensureInitialized();
|
|
181
|
+
} catch (error) {
|
|
182
|
+
// Log database initialization errors
|
|
183
|
+
console.warn('Warning: Could not initialize database:', String(error));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
switch (transport) {
|
|
187
|
+
case 'stdio': {
|
|
188
|
+
const logger = createLogger('stdio');
|
|
189
|
+
logger.info('Transport: MCP stdio (Claude Desktop)');
|
|
190
|
+
logger.info('Initializing NgaoSearchService');
|
|
191
|
+
|
|
192
|
+
const mcpTransport = new McpTransport(service, logger);
|
|
193
|
+
await mcpTransport.start();
|
|
194
|
+
|
|
195
|
+
logger.info('NGAO Search server started successfully');
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
case 'http': {
|
|
200
|
+
const logger = createLogger('http');
|
|
201
|
+
logger.info('Transport: HTTP REST API');
|
|
202
|
+
logger.info('Initializing NgaoSearchService');
|
|
203
|
+
|
|
204
|
+
const restTransport = new RestTransport(service, logger);
|
|
205
|
+
restTransport.start(0); // 0 = randomly assigned available port
|
|
206
|
+
|
|
207
|
+
logger.info('NGAO Search server started successfully');
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
default:
|
|
212
|
+
console.error(`ā Unknown transport: ${transport}`);
|
|
213
|
+
console.error(' Valid options: stdio, http');
|
|
214
|
+
console.error(' Default: http');
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error('ā Failed to start NGAO Search server:');
|
|
219
|
+
console.error(error);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Start the server
|
|
225
|
+
main();
|