codesearch-mcp 0.2.3-alpha → 0.3.0-alpha
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/CHANGELOG.md +31 -1
- package/README.md +46 -26
- package/dist/app.js +5 -19
- package/dist/src/chunking/AstChunker.d.ts +12 -0
- package/dist/src/chunking/AstChunker.js +30 -0
- package/dist/src/chunking/CharacterChunkStrategy.d.ts +8 -0
- package/dist/src/chunking/CharacterChunkStrategy.js +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.d.ts +15 -0
- package/dist/src/chunking/DeclarationChunkStrategy.js +87 -0
- package/dist/src/chunking/FragmentMerger.d.ts +11 -0
- package/dist/src/chunking/FragmentMerger.js +61 -0
- package/dist/src/chunking/ImportOnlyFilter.d.ts +5 -0
- package/dist/src/chunking/ImportOnlyFilter.js +14 -0
- package/dist/src/chunking/LangchainTextSplitter.d.ts +21 -0
- package/dist/src/chunking/LangchainTextSplitter.js +133 -0
- package/dist/src/chunking/MinSizeSplitPolicy.d.ts +9 -0
- package/dist/src/chunking/MinSizeSplitPolicy.js +18 -0
- package/dist/src/chunking/RunPacker.d.ts +12 -0
- package/dist/src/chunking/RunPacker.js +84 -0
- package/dist/src/chunking/create-chunker.d.ts +3 -0
- package/dist/src/chunking/create-chunker.js +15 -0
- package/dist/src/chunking/interfaces.d.ts +27 -0
- package/dist/src/chunking/interfaces.js +2 -0
- package/dist/src/commands/ConfigCommand.js +1 -9
- package/dist/src/commands/EvalCommand.d.ts +4 -3
- package/dist/src/commands/EvalCommand.js +85 -52
- package/dist/src/commands/IndexCommand.js +0 -22
- package/dist/src/commands/McpCommand.js +2 -8
- package/dist/src/commands/WebCommand.js +2 -5
- package/dist/src/config-error.d.ts +0 -4
- package/dist/src/config-error.js +0 -4
- package/dist/src/config-store.d.ts +1 -54
- package/dist/src/config-store.js +8 -69
- package/dist/src/config.d.ts +8 -17
- package/dist/src/config.js +35 -34
- package/dist/src/constants.d.ts +2 -28
- package/dist/src/constants.js +6 -28
- package/dist/src/container.d.ts +6 -0
- package/dist/src/container.js +12 -3
- package/dist/src/db/schema.d.ts +17 -0
- package/dist/src/db/schema.js +1 -6
- package/dist/src/declarations/DeclarationTree.d.ts +19 -0
- package/dist/src/declarations/DeclarationTree.js +66 -0
- package/dist/src/declarations/DeclarationTreeBuilder.d.ts +22 -0
- package/dist/src/declarations/DeclarationTreeBuilder.js +179 -0
- package/dist/src/declarations/SourceLines.d.ts +37 -0
- package/dist/src/declarations/SourceLines.js +415 -0
- package/dist/src/dependency-traversal.d.ts +0 -6
- package/dist/src/dependency-traversal.js +0 -6
- package/dist/src/enriched-prompt.d.ts +0 -6
- package/dist/src/enriched-prompt.js +0 -6
- package/dist/src/error-record.d.ts +12 -0
- package/dist/src/error-record.js +248 -0
- package/dist/src/eval-corpus.d.ts +16 -0
- package/dist/src/eval-corpus.js +169 -0
- package/dist/src/eval-results.d.ts +6 -3
- package/dist/src/eval-results.js +309 -26
- package/dist/src/file-utils.d.ts +0 -5
- package/dist/src/file-utils.js +0 -5
- package/dist/src/graph.d.ts +0 -25
- package/dist/src/graph.js +0 -28
- package/dist/src/hnsw-settings.d.ts +3 -0
- package/dist/src/hnsw-settings.js +24 -0
- package/dist/src/interfaces/IAstParser.d.ts +2 -39
- package/dist/src/interfaces/IChunker.d.ts +3 -12
- package/dist/src/interfaces/ICorpusInspector.d.ts +7 -0
- package/dist/src/interfaces/ICorpusInspector.js +2 -0
- package/dist/src/interfaces/IDatabase.d.ts +2 -22
- package/dist/src/interfaces/IEmbedder.d.ts +0 -9
- package/dist/src/interfaces/ILogger.d.ts +1 -11
- package/dist/src/interfaces/IMcpToolHandler.d.ts +0 -5
- package/dist/src/interfaces/IMonorepoResolver.d.ts +0 -22
- package/dist/src/interfaces/IProjectDiscovery.d.ts +0 -17
- package/dist/src/interfaces/IRetrievalEvaluator.d.ts +134 -12
- package/dist/src/interfaces/ISearcher.d.ts +16 -5
- package/dist/src/interrupt.js +0 -2
- package/dist/src/owner-path.d.ts +9 -10
- package/dist/src/owner-path.js +11 -23
- package/dist/src/project-scope.d.ts +0 -12
- package/dist/src/project-scope.js +0 -12
- package/dist/src/project-selector.d.ts +0 -5
- package/dist/src/project-selector.js +0 -11
- package/dist/src/retrieval-eval.d.ts +14 -6
- package/dist/src/retrieval-eval.js +345 -59
- package/dist/src/search/result-shaping.d.ts +4 -0
- package/dist/src/search/result-shaping.js +19 -0
- package/dist/src/services/AstParserService.d.ts +2 -62
- package/dist/src/services/AstParserService.js +25 -137
- package/dist/src/services/DatabaseService.d.ts +2 -7
- package/dist/src/services/DatabaseService.js +42 -29
- package/dist/src/services/EmbedderFactory.d.ts +0 -4
- package/dist/src/services/EmbedderFactory.js +0 -5
- package/dist/src/services/IndexerService.d.ts +0 -16
- package/dist/src/services/IndexerService.js +16 -45
- package/dist/src/services/InfinityEmbedder.d.ts +0 -21
- package/dist/src/services/InfinityEmbedder.js +0 -15
- package/dist/src/services/LoggerService.d.ts +7 -5
- package/dist/src/services/LoggerService.js +37 -41
- package/dist/src/services/McpServer.d.ts +22 -14
- package/dist/src/services/McpServer.js +70 -37
- package/dist/src/services/MonorepoAwareDiscoveryService.d.ts +1 -45
- package/dist/src/services/MonorepoAwareDiscoveryService.js +1 -51
- package/dist/src/services/NxMonorepoResolver.d.ts +0 -29
- package/dist/src/services/NxMonorepoResolver.js +5 -56
- package/dist/src/services/OpenAICompatibleEmbedder.d.ts +0 -6
- package/dist/src/services/OpenAICompatibleEmbedder.js +0 -14
- package/dist/src/services/ProjectDiscoveryService.d.ts +0 -4
- package/dist/src/services/ProjectDiscoveryService.js +0 -4
- package/dist/src/services/SearcherService.d.ts +9 -116
- package/dist/src/services/SearcherService.js +95 -176
- package/dist/src/services/VoyageEmbedder.d.ts +0 -6
- package/dist/src/services/VoyageEmbedder.js +0 -6
- package/dist/src/services/WebServerService.d.ts +1 -53
- package/dist/src/services/WebServerService.js +11 -57
- package/dist/src/services/http-retry.d.ts +0 -7
- package/dist/src/services/http-retry.js +1 -10
- package/dist/src/services/infinity-provisioning.d.ts +0 -74
- package/dist/src/services/infinity-provisioning.js +5 -88
- package/dist/src/services/legacy-ollama-index.d.ts +0 -16
- package/dist/src/services/legacy-ollama-index.js +0 -23
- package/dist/src/services/reranker.d.ts +0 -9
- package/dist/src/services/reranker.js +46 -12
- package/dist/src/setup.d.ts +11 -23
- package/dist/src/setup.js +98 -71
- package/dist/src/symbol-name.d.ts +0 -12
- package/dist/src/symbol-name.js +0 -13
- package/dist/src/symbol-rows.d.ts +0 -14
- package/dist/src/symbol-rows.js +0 -14
- package/dist/src/tool-call-log.d.ts +2 -0
- package/dist/src/tool-call-log.js +24 -0
- package/dist/src/tools/GetDependenciesTool.js +1 -1
- package/dist/src/tools/GetDependentsTool.js +1 -1
- package/dist/src/tools/SearchCodebaseTool.js +6 -3
- package/dist/src/tools/format-helpers.d.ts +0 -6
- package/dist/src/tools/format-helpers.js +87 -14
- package/dist/src/web/dashboard.d.ts +0 -8
- package/dist/src/web/dashboard.js +7 -10
- package/package.json +2 -2
- package/dist/src/services/AstChunker.d.ts +0 -42
- package/dist/src/services/AstChunker.js +0 -158
- package/docs/web-dashboard.md +0 -206
|
@@ -1,19 +1,30 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
1
2
|
import type { Config } from '../config';
|
|
2
3
|
import type { ISearcher } from '../interfaces/ISearcher';
|
|
3
4
|
import type { ILogger } from '../interfaces/ILogger';
|
|
4
5
|
import type { IMcpToolHandler, ToolResponse } from '../interfaces/IMcpToolHandler';
|
|
5
|
-
/**
|
|
6
|
-
* The dispatch logic behind `CallToolRequestSchema` — pulled out so it is testable
|
|
7
|
-
* without a live stdio transport. A rejecting handler becomes `Tool error: <message>`.
|
|
8
|
-
*/
|
|
9
6
|
export declare function dispatchTool(tools: Map<string, IMcpToolHandler>, name: string, args: Record<string, unknown>, logger: ILogger): Promise<ToolResponse>;
|
|
7
|
+
export interface ToolCallRequest {
|
|
8
|
+
name: string;
|
|
9
|
+
arguments?: Record<string, unknown>;
|
|
10
|
+
_meta?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export interface ToolCaller {
|
|
13
|
+
callId: number;
|
|
14
|
+
session: string | null;
|
|
15
|
+
client: {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
} | null;
|
|
19
|
+
startupError?: Error;
|
|
20
|
+
}
|
|
21
|
+
export declare function handleToolCall(tools: Map<string, IMcpToolHandler>, req: ToolCallRequest, signal: AbortSignal, caller: ToolCaller, logger: ILogger): Promise<ToolResponse>;
|
|
22
|
+
export declare function createToolCallHandler(tools: Map<string, IMcpToolHandler>, server: Pick<Server, 'getClientVersion'>, identity: Pick<ToolCaller, 'session' | 'startupError'>, logger: ILogger): (req: {
|
|
23
|
+
params: ToolCallRequest;
|
|
24
|
+
}, extra: {
|
|
25
|
+
signal: AbortSignal;
|
|
26
|
+
}) => Promise<ToolResponse>;
|
|
10
27
|
export declare function buildInstructions(t: number): string;
|
|
11
|
-
/**
|
|
12
|
-
* McpServer — thin orchestration layer that delegates tool handling
|
|
13
|
-
* to individual IMcpToolHandler implementations (Open/Closed Principle).
|
|
14
|
-
*
|
|
15
|
-
* To add a new tool: implement IMcpToolHandler and register it in createTools().
|
|
16
|
-
*/
|
|
17
28
|
export declare class McpServer {
|
|
18
29
|
private searcher;
|
|
19
30
|
private config;
|
|
@@ -22,9 +33,6 @@ export declare class McpServer {
|
|
|
22
33
|
private readonly tools;
|
|
23
34
|
constructor(searcher: ISearcher, config: Config, logger: ILogger);
|
|
24
35
|
start(startupError?: Error): Promise<void>;
|
|
25
|
-
|
|
26
|
-
* Factory method: creates and registers all tool handlers.
|
|
27
|
-
* New tools are added here without modifying the dispatch logic above.
|
|
28
|
-
*/
|
|
36
|
+
createServer(startupError?: Error): Server;
|
|
29
37
|
private createTools;
|
|
30
38
|
}
|
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.McpServer = void 0;
|
|
37
37
|
exports.dispatchTool = dispatchTool;
|
|
38
|
+
exports.handleToolCall = handleToolCall;
|
|
39
|
+
exports.createToolCallHandler = createToolCallHandler;
|
|
38
40
|
exports.buildInstructions = buildInstructions;
|
|
39
41
|
const fs = __importStar(require("fs"));
|
|
40
42
|
const path = __importStar(require("path"));
|
|
@@ -42,6 +44,8 @@ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
|
42
44
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
43
45
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
44
46
|
const tools_1 = require("../tools");
|
|
47
|
+
const tool_call_log_1 = require("../tool-call-log");
|
|
48
|
+
const error_record_1 = require("../error-record");
|
|
45
49
|
function readPackageVersion() {
|
|
46
50
|
try {
|
|
47
51
|
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8')).version ?? '0.0.0';
|
|
@@ -50,10 +54,6 @@ function readPackageVersion() {
|
|
|
50
54
|
return '0.0.0';
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
|
-
/**
|
|
54
|
-
* The dispatch logic behind `CallToolRequestSchema` — pulled out so it is testable
|
|
55
|
-
* without a live stdio transport. A rejecting handler becomes `Tool error: <message>`.
|
|
56
|
-
*/
|
|
57
57
|
async function dispatchTool(tools, name, args, logger) {
|
|
58
58
|
const handler = tools.get(name);
|
|
59
59
|
if (!handler) {
|
|
@@ -63,11 +63,63 @@ async function dispatchTool(tools, name, args, logger) {
|
|
|
63
63
|
return await handler.handle(args);
|
|
64
64
|
}
|
|
65
65
|
catch (err) {
|
|
66
|
+
logger.error('McpServer: tool handler error', { tool: name, err });
|
|
66
67
|
const reason = err instanceof Error ? err.message : String(err);
|
|
67
|
-
logger.error('McpServer: tool handler error', { tool: name, reason });
|
|
68
68
|
return { isError: true, content: [{ type: 'text', text: `Tool error: ${reason}` }] };
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
function unavailableResponse(startupError) {
|
|
72
|
+
return {
|
|
73
|
+
isError: true,
|
|
74
|
+
content: [{
|
|
75
|
+
type: 'text',
|
|
76
|
+
text: `MCP server is unavailable: ${(0, error_record_1.errorMessage)(startupError)}\n\nCheck the log file and fix the issue, then restart the MCP server.`,
|
|
77
|
+
}],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function metaForLog(meta) {
|
|
81
|
+
if (!meta)
|
|
82
|
+
return null;
|
|
83
|
+
const { progressToken: _, ...rest } = meta;
|
|
84
|
+
return Object.keys(rest).length ? (0, tool_call_log_1.truncateForLog)(rest) : null;
|
|
85
|
+
}
|
|
86
|
+
async function handleToolCall(tools, req, signal, caller, logger) {
|
|
87
|
+
const t0 = Date.now();
|
|
88
|
+
const toolUseId = req._meta?.['claudecode/toolUseId'];
|
|
89
|
+
const context = typeof toolUseId === 'string' ? { callId: caller.callId, toolUseId } : { callId: caller.callId };
|
|
90
|
+
return logger.withContext(context, async () => {
|
|
91
|
+
const args = req.arguments ?? {};
|
|
92
|
+
const response = caller.startupError
|
|
93
|
+
? unavailableResponse(caller.startupError)
|
|
94
|
+
: await dispatchTool(tools, req.name, args, logger);
|
|
95
|
+
const ms = Date.now() - t0;
|
|
96
|
+
if (!response.isError)
|
|
97
|
+
logger.debug('McpServer: tool handled', { tool: req.name, ms });
|
|
98
|
+
logger.info('tool call', {
|
|
99
|
+
tool: req.name,
|
|
100
|
+
args: (0, tool_call_log_1.truncateForLog)(args),
|
|
101
|
+
isError: response.isError ?? false,
|
|
102
|
+
responseChars: response.content.reduce((n, c) => n + (typeof c.text === 'string' ? c.text.length : 0), 0),
|
|
103
|
+
ms,
|
|
104
|
+
client: caller.client,
|
|
105
|
+
session: caller.session,
|
|
106
|
+
meta: metaForLog(req._meta),
|
|
107
|
+
...(signal.aborted ? { cancelled: true } : {}),
|
|
108
|
+
});
|
|
109
|
+
return response;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function createToolCallHandler(tools, server, identity, logger) {
|
|
113
|
+
let nextCallId = 1;
|
|
114
|
+
return (req, extra) => {
|
|
115
|
+
const client = server.getClientVersion();
|
|
116
|
+
return handleToolCall(tools, req.params, extra.signal, {
|
|
117
|
+
...identity,
|
|
118
|
+
callId: nextCallId++,
|
|
119
|
+
client: client ? { name: client.name, version: client.version } : null,
|
|
120
|
+
}, logger);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
71
123
|
function buildInstructions(t) {
|
|
72
124
|
return `
|
|
73
125
|
You have access to a local code intelligence server. Use these tools to search codebases by meaning, navigate import graphs, look up symbol definitions, and read source files.
|
|
@@ -91,7 +143,7 @@ Pick one workflow based on what you need:
|
|
|
91
143
|
Every file or directory argument (\`file_path\`, \`callee_file\`, \`path\`) is workspace-relative, exactly as printed by search_codebase (e.g. \`my-app/src/index.ts\`; \`.\` is the workspace root) — copy paths between tools unchanged.
|
|
92
144
|
|
|
93
145
|
- **list_projects** — call this first to see what projects are indexed, their exact names and their directories (\`path:\`).
|
|
94
|
-
- **search_codebase** — semantic search across indexed source files. Returns file path, line number, and a code chunk. **Pass \`project\` whenever the target project is known or guessable from the question** — this workspace indexes many projects at once, and an unscoped query competes against all of them, which \`rerank\` cannot fix (reranking only reorders whatever the vector search already retrieved). Pass \`rerank: false\` for "what does X do" / "where is X" lookups described without an exact name — measurement shows reranking hurts these (-0.
|
|
146
|
+
- **search_codebase** — semantic search across indexed source files. Returns file path, line number, and a code chunk. **Pass \`project\` whenever the target project is known or guessable from the question** — this workspace indexes many projects at once, and an unscoped query competes against all of them, which \`rerank\` cannot fix (reranking only reorders whatever the vector search already retrieved). Pass \`rerank: false\` for "what does X do" / "where is X" lookups described without an exact name — measurement shows reranking hurts these (-0.13 MRR@10, hit@5 68% → 50%). If you already know the exact symbol name, use \`find_symbol\` instead, not \`search_codebase\` — it is faster and exact, and the rerank setting does not matter there. For conceptual/architectural queries reranking is roughly neutral (-0.05 MRR@10, not significant), so omitting \`rerank\` is fine.
|
|
95
147
|
- **read_file_range** — read a specific line range from any file under the workspace, indexed or not.
|
|
96
148
|
- **get_dependencies** — show what files a given file imports (direct or transitive). Use to understand what a file depends on.
|
|
97
149
|
- **get_dependents** — show which files import a given file (reverse graph). Use before refactoring to find all callers.
|
|
@@ -106,7 +158,7 @@ Every file or directory argument (\`file_path\`, \`callee_file\`, \`path\`) is w
|
|
|
106
158
|
1. Use \`list_projects\` to discover available projects before filtering by \`project\`.
|
|
107
159
|
2. Use \`search_codebase\` to find relevant code by meaning. **Always pass \`project\` when the question names or implies one** — an unscoped search ranks candidates across every indexed project together, so an unrelated project's weak match can outrank the right project's real one. If your query uses an ambiguous term (e.g. "subscription" could mean pub/sub or billing), pass a lower \`threshold\` (e.g. \`0.40–0.45\`) to filter out weak matches.
|
|
108
160
|
3. If a result looks **truncated or incomplete**, call \`read_file_range\` with the returned \`file_path\` and \`start_line\`.
|
|
109
|
-
4. For exploratory searches where results span chunk boundaries, pass \`include_neighbors: true\`.
|
|
161
|
+
4. For exploratory searches where results span chunk boundaries, pass \`include_neighbors: true\`. Results hold at most 2 chunks per file by default; pass \`per_file\` (e.g. \`5\`) when several answers are expected in one file, such as several methods of one class.
|
|
110
162
|
5. To immediately see a file's imports and callers without extra tool calls, pass \`include_graph_context: true\` to \`search_codebase\`. Use this when doing a quick structural survey; switch to \`get_dependencies\`/\`get_dependents\` for full transitive graphs.
|
|
111
163
|
6. Use \`find_symbol\` when you know the exact name — faster and exact, unlike semantic search. Use a qualified name (\`Class.method\`) to disambiguate same-named methods of different classes; a bare name searches every container. When you also want surrounding context (callers' intent, nearby helpers, how it's described elsewhere), call \`search_codebase\` in parallel rather than after — the two tools answer different questions and neither blocks the other. Hits marked \`(grep — not in index; may be stale or imprecise)\` come from a fallback text search, not the index — treat them as less reliable. After locating a symbol, use \`get_callers\` to find all call sites — faster and more precise than grep. For a NestJS GraphQL operation, resolve field or type, pass the matching \`graphql_query\`/\`graphql_mutation\`/\`graphql_subscription\`/\`graphql_field\`/\`graphql_type\` kind to look it up by the name the schema exposes, not the TypeScript declaration name.
|
|
112
164
|
7. Use \`list_files\` to explore project structure before diving into files. Use \`read_file\` to read a complete file.
|
|
@@ -135,7 +187,7 @@ Every file or directory argument (\`file_path\`, \`callee_file\`, \`path\`) is w
|
|
|
135
187
|
|
|
136
188
|
## Dependency graph
|
|
137
189
|
|
|
138
|
-
\`get_dependencies\` and \`get_dependents\` take \`file_path\` alone and list edges in every project. A path that names no file is an error, never an empty result. Pass \`transitive: true\` for the full dependency chain.
|
|
190
|
+
\`get_dependencies\` and \`get_dependents\` take \`file_path\` alone and list edges in every project. A path that names no file is an error, never an empty result. Pass \`transitive: true\` for the full dependency chain. The direct section prints one line per file, with the names imported from/by it (\`default\` / \`* as namespace\` / \`side-effect\` standing in for a nameless import, re-exports grouped after plain imports under one \`re-export \` prefix, \`export *\` for a namespace re-export); \`get_dependents\` also lists the enclosing declarations (\`· in \`PlansPage\`\`) that use the import — only those resolved unambiguously (a binding used in 2+ declarations yields none), so the list can be partial or absent.
|
|
139
191
|
|
|
140
192
|
If \`get_dependents\` returns 0 results, add \`symbol\` (the exported name you care about) — this triggers a grep fallback that finds runtime usages in DI containers, string references, and dynamic lookups that the import graph misses.
|
|
141
193
|
|
|
@@ -144,12 +196,6 @@ If \`get_dependents\` returns 0 results, add \`symbol\` (the exported name you c
|
|
|
144
196
|
Lower score = better match (cosine distance). Results above the configured threshold are filtered out automatically. Treat scores above 0.50 as weak hints — verify with \`read_file_range\` or \`Grep\`. Pass \`threshold\` to \`search_codebase\` to override per-query: \`0.40–0.45\` for precise technical queries (known term, exact concept); \`${t}\` default (broad but reliable). Avoid \`0.35\` — too strict for DSL files (GraphQL, Prisma) and infrastructure code.
|
|
145
197
|
`.trim();
|
|
146
198
|
}
|
|
147
|
-
/**
|
|
148
|
-
* McpServer — thin orchestration layer that delegates tool handling
|
|
149
|
-
* to individual IMcpToolHandler implementations (Open/Closed Principle).
|
|
150
|
-
*
|
|
151
|
-
* To add a new tool: implement IMcpToolHandler and register it in createTools().
|
|
152
|
-
*/
|
|
153
199
|
class McpServer {
|
|
154
200
|
searcher;
|
|
155
201
|
config;
|
|
@@ -165,35 +211,22 @@ class McpServer {
|
|
|
165
211
|
}
|
|
166
212
|
async start(startupError) {
|
|
167
213
|
if (startupError) {
|
|
168
|
-
this.logger.error('McpServer: startup failed, server will report error on every tool call', {
|
|
214
|
+
this.logger.error('McpServer: startup failed, server will report error on every tool call', { err: startupError });
|
|
169
215
|
}
|
|
216
|
+
await this.createServer(startupError).connect(new stdio_js_1.StdioServerTransport());
|
|
217
|
+
this.logger.info('McpServer: started', { version: this.version });
|
|
218
|
+
}
|
|
219
|
+
createServer(startupError) {
|
|
170
220
|
const server = new index_js_1.Server({ name: 'local-rag', version: this.version }, { capabilities: { tools: {} }, instructions: buildInstructions(this.config.search.similarityThreshold) });
|
|
171
221
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
172
222
|
tools: [...this.tools.values()].map(t => t.definition()),
|
|
173
223
|
}));
|
|
174
|
-
server.setRequestHandler(types_js_1.CallToolRequestSchema,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
type: 'text',
|
|
180
|
-
text: `MCP server is unavailable: ${startupError.message}\n\nCheck the log file and fix the issue, then restart the MCP server.`,
|
|
181
|
-
}],
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
const t0 = Date.now();
|
|
185
|
-
const result = await dispatchTool(this.tools, req.params.name, (req.params.arguments ?? {}), this.logger);
|
|
186
|
-
if (!result.isError)
|
|
187
|
-
this.logger.debug('McpServer: tool handled', { tool: req.params.name, ms: Date.now() - t0 });
|
|
188
|
-
return result;
|
|
189
|
-
});
|
|
190
|
-
await server.connect(new stdio_js_1.StdioServerTransport());
|
|
191
|
-
this.logger.info('McpServer: started', { version: this.version });
|
|
224
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, createToolCallHandler(this.tools, server, {
|
|
225
|
+
session: (0, tool_call_log_1.resolveSession)(process.env),
|
|
226
|
+
startupError,
|
|
227
|
+
}, this.logger));
|
|
228
|
+
return server;
|
|
192
229
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Factory method: creates and registers all tool handlers.
|
|
195
|
-
* New tools are added here without modifying the dispatch logic above.
|
|
196
|
-
*/
|
|
197
230
|
createTools() {
|
|
198
231
|
const handlers = [
|
|
199
232
|
new tools_1.ListProjectsTool(this.searcher),
|
|
@@ -6,57 +6,13 @@ export interface WorkspaceInfo {
|
|
|
6
6
|
rootTsConfigPath: string | null;
|
|
7
7
|
projects: DiscoveredProject[];
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Expand discovery units into the leaf projects to index: a nested monorepo
|
|
11
|
-
* unit (with `children`) becomes its sub-projects; an ordinary project stays
|
|
12
|
-
* itself. Shared by IndexCommand (indexing loop) and SearcherService (name→path
|
|
13
|
-
* resolution) so both agree on the leaf set.
|
|
14
|
-
*/
|
|
15
9
|
export declare function toLeafProjects(projects: DiscoveredProject[]): DiscoveredProject[];
|
|
16
|
-
/**
|
|
17
|
-
* Project discovery that is monorepo-aware.
|
|
18
|
-
*
|
|
19
|
-
* When a monorepo is detected (via the resolver), it uses the resolver
|
|
20
|
-
* to discover projects. Otherwise, it falls back to the original
|
|
21
|
-
* flat-workspace discovery (directories with package.json). Cross-project
|
|
22
|
-
* import resolution relies on the tsconfig `paths` attached via
|
|
23
|
-
* `rootTsConfigPath` — no separate scope map is built.
|
|
24
|
-
*
|
|
25
|
-
* Single Responsibility: only discovers projects and workspace metadata.
|
|
26
|
-
* Does not index or search.
|
|
27
|
-
*
|
|
28
|
-
* Implements {@link IProjectDiscovery} so it can be wired as the default
|
|
29
|
-
* discovery in the container. `discover()` returns one entry per top-level
|
|
30
|
-
* project: when the root itself is a monorepo, each entry carries the
|
|
31
|
-
* workspace-wide `rootTsConfigPath`; under a flat root, an ordinary project
|
|
32
|
-
* gets `rootTsConfigPath: null`, while a top-level directory that is itself a
|
|
33
|
-
* nested monorepo is returned as a single unit with expanded `children` (see
|
|
34
|
-
* `toLeafProjects`). `analyzeWorkspace()` exposes the full workspace metadata
|
|
35
|
-
* (monorepo flag, root tsconfig, project list).
|
|
36
|
-
*/
|
|
37
10
|
export declare class MonorepoAwareDiscoveryService implements IProjectDiscovery {
|
|
38
11
|
private resolvers;
|
|
39
12
|
private logger;
|
|
40
|
-
/** Discovery used when no monorepo is detected. Defaults to flat package.json scan. */
|
|
41
13
|
private flatDiscovery;
|
|
42
|
-
constructor(resolvers: IMonorepoResolver[], logger: ILogger,
|
|
43
|
-
/** Discovery used when no monorepo is detected. Defaults to flat package.json scan. */
|
|
44
|
-
flatDiscovery?: IProjectDiscovery);
|
|
45
|
-
/**
|
|
46
|
-
* IProjectDiscovery contract: enumerate projects in the workspace.
|
|
47
|
-
* Attaches the workspace-wide root tsconfig to every project so the
|
|
48
|
-
* indexer can resolve cross-project path aliases.
|
|
49
|
-
*/
|
|
14
|
+
constructor(resolvers: IMonorepoResolver[], logger: ILogger, flatDiscovery?: IProjectDiscovery);
|
|
50
15
|
discover(rootDir: string): DiscoveredProject[];
|
|
51
|
-
/**
|
|
52
|
-
* If `project`'s directory is itself a monorepo (resolver detects it),
|
|
53
|
-
* return it with expanded `children` named `<repo>/<sub-project>`, each
|
|
54
|
-
* carrying the repo's workspace-wide tsconfig. Otherwise return it unchanged.
|
|
55
|
-
*/
|
|
56
16
|
private expandIfNestedMonorepo;
|
|
57
|
-
/**
|
|
58
|
-
* Analyze the workspace root and return full workspace information:
|
|
59
|
-
* monorepo detection flag, root tsconfig path, and project list.
|
|
60
|
-
*/
|
|
61
17
|
analyzeWorkspace(rootDir: string): WorkspaceInfo;
|
|
62
18
|
}
|
|
@@ -3,71 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MonorepoAwareDiscoveryService = void 0;
|
|
4
4
|
exports.toLeafProjects = toLeafProjects;
|
|
5
5
|
const ProjectDiscoveryService_1 = require("./ProjectDiscoveryService");
|
|
6
|
-
/**
|
|
7
|
-
* Expand discovery units into the leaf projects to index: a nested monorepo
|
|
8
|
-
* unit (with `children`) becomes its sub-projects; an ordinary project stays
|
|
9
|
-
* itself. Shared by IndexCommand (indexing loop) and SearcherService (name→path
|
|
10
|
-
* resolution) so both agree on the leaf set.
|
|
11
|
-
*/
|
|
12
6
|
function toLeafProjects(projects) {
|
|
13
7
|
return projects.flatMap(p => (p.children && p.children.length > 0 ? p.children : [p]));
|
|
14
8
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Project discovery that is monorepo-aware.
|
|
17
|
-
*
|
|
18
|
-
* When a monorepo is detected (via the resolver), it uses the resolver
|
|
19
|
-
* to discover projects. Otherwise, it falls back to the original
|
|
20
|
-
* flat-workspace discovery (directories with package.json). Cross-project
|
|
21
|
-
* import resolution relies on the tsconfig `paths` attached via
|
|
22
|
-
* `rootTsConfigPath` — no separate scope map is built.
|
|
23
|
-
*
|
|
24
|
-
* Single Responsibility: only discovers projects and workspace metadata.
|
|
25
|
-
* Does not index or search.
|
|
26
|
-
*
|
|
27
|
-
* Implements {@link IProjectDiscovery} so it can be wired as the default
|
|
28
|
-
* discovery in the container. `discover()` returns one entry per top-level
|
|
29
|
-
* project: when the root itself is a monorepo, each entry carries the
|
|
30
|
-
* workspace-wide `rootTsConfigPath`; under a flat root, an ordinary project
|
|
31
|
-
* gets `rootTsConfigPath: null`, while a top-level directory that is itself a
|
|
32
|
-
* nested monorepo is returned as a single unit with expanded `children` (see
|
|
33
|
-
* `toLeafProjects`). `analyzeWorkspace()` exposes the full workspace metadata
|
|
34
|
-
* (monorepo flag, root tsconfig, project list).
|
|
35
|
-
*/
|
|
36
9
|
class MonorepoAwareDiscoveryService {
|
|
37
10
|
resolvers;
|
|
38
11
|
logger;
|
|
39
12
|
flatDiscovery;
|
|
40
|
-
constructor(resolvers, logger,
|
|
41
|
-
/** Discovery used when no monorepo is detected. Defaults to flat package.json scan. */
|
|
42
|
-
flatDiscovery = new ProjectDiscoveryService_1.ProjectDiscoveryService()) {
|
|
13
|
+
constructor(resolvers, logger, flatDiscovery = new ProjectDiscoveryService_1.ProjectDiscoveryService()) {
|
|
43
14
|
this.resolvers = resolvers;
|
|
44
15
|
this.logger = logger;
|
|
45
16
|
this.flatDiscovery = flatDiscovery;
|
|
46
17
|
}
|
|
47
|
-
/**
|
|
48
|
-
* IProjectDiscovery contract: enumerate projects in the workspace.
|
|
49
|
-
* Attaches the workspace-wide root tsconfig to every project so the
|
|
50
|
-
* indexer can resolve cross-project path aliases.
|
|
51
|
-
*/
|
|
52
18
|
discover(rootDir) {
|
|
53
19
|
const workspace = this.analyzeWorkspace(rootDir);
|
|
54
|
-
// Case A: workspaceRoot itself is a monorepo — attach the workspace-wide
|
|
55
|
-
// tsconfig to every project (original behavior).
|
|
56
20
|
if (workspace.isMonorepo) {
|
|
57
21
|
return workspace.projects.map(p => ({ ...p, rootTsConfigPath: workspace.rootTsConfigPath }));
|
|
58
22
|
}
|
|
59
|
-
// Case B: flat workspaceRoot — a top-level project directory may itself be a
|
|
60
|
-
// nested monorepo (e.g. an Nx repo). Expand such a directory into its
|
|
61
|
-
// sub-projects as `children`, keeping the repo a single selectable unit.
|
|
62
23
|
return workspace.projects.map(p => this.expandIfNestedMonorepo(p));
|
|
63
24
|
}
|
|
64
|
-
/**
|
|
65
|
-
* If `project`'s directory is itself a monorepo (resolver detects it),
|
|
66
|
-
* return it with expanded `children` named `<repo>/<sub-project>`, each
|
|
67
|
-
* carrying the repo's workspace-wide tsconfig. Otherwise return it unchanged.
|
|
68
|
-
*/
|
|
69
25
|
expandIfNestedMonorepo(project) {
|
|
70
|
-
// Ordinary flat project — preserve the original contract (null root tsconfig).
|
|
71
26
|
const flat = { ...project, rootTsConfigPath: null };
|
|
72
27
|
const resolver = this.resolvers.find(r => r.isMonorepo(project.path));
|
|
73
28
|
if (!resolver)
|
|
@@ -89,10 +44,6 @@ class MonorepoAwareDiscoveryService {
|
|
|
89
44
|
});
|
|
90
45
|
return { ...project, children };
|
|
91
46
|
}
|
|
92
|
-
/**
|
|
93
|
-
* Analyze the workspace root and return full workspace information:
|
|
94
|
-
* monorepo detection flag, root tsconfig path, and project list.
|
|
95
|
-
*/
|
|
96
47
|
analyzeWorkspace(rootDir) {
|
|
97
48
|
for (const resolver of this.resolvers) {
|
|
98
49
|
if (resolver.isMonorepo(rootDir)) {
|
|
@@ -112,7 +63,6 @@ class MonorepoAwareDiscoveryService {
|
|
|
112
63
|
return { isMonorepo: true, rootTsConfigPath, projects };
|
|
113
64
|
}
|
|
114
65
|
}
|
|
115
|
-
// Fallback: flat workspace (original behavior) — delegated to the default discovery.
|
|
116
66
|
this.logger.debug('MonorepoAwareDiscovery: no monorepo detected, using flat discovery', { rootDir });
|
|
117
67
|
const projects = this.flatDiscovery.discover(rootDir);
|
|
118
68
|
return {
|
|
@@ -1,40 +1,11 @@
|
|
|
1
1
|
import type { IMonorepoResolver, MonorepoProject } from '../interfaces/IMonorepoResolver';
|
|
2
2
|
import type { ILogger } from '../interfaces';
|
|
3
|
-
/**
|
|
4
|
-
* Nx monorepo resolver.
|
|
5
|
-
*
|
|
6
|
-
* Detection: presence of `nx.json` at the workspace root.
|
|
7
|
-
*
|
|
8
|
-
* Project discovery strategies (results deduplicated by absolute path):
|
|
9
|
-
* 1. Read `workspace.json` or `angular.json` → projects map
|
|
10
|
-
* 2. Scan standard Nx directories (`apps/`, `libs/`, `packages/`) for
|
|
11
|
-
* `project.json`, then `package.json` (only when strategy 1 found nothing)
|
|
12
|
-
* 3. `tsconfig.base.json` `paths` — root-level libs referenced only by path
|
|
13
|
-
* alias (e.g. `contracts/`, `interfaces/`) that the directory scan misses
|
|
14
|
-
* 4. Root-level fallback: treat the workspace root itself as a project
|
|
15
|
-
* (standalone Nx setup) when nothing else matched
|
|
16
|
-
*
|
|
17
|
-
* tsconfig resolution:
|
|
18
|
-
* - Returns `tsconfig.base.json` at workspace root (Nx convention)
|
|
19
|
-
* - Falls back to `tsconfig.json` at workspace root
|
|
20
|
-
*
|
|
21
|
-
* Cross-project import resolution is handled by the AST parser via the
|
|
22
|
-
* workspace-wide tsconfig `paths` (tsconfig.base.json), so no scope map is built here.
|
|
23
|
-
*/
|
|
24
3
|
export declare class NxMonorepoResolver implements IMonorepoResolver {
|
|
25
4
|
private logger;
|
|
26
5
|
constructor(logger: ILogger);
|
|
27
6
|
isMonorepo(rootDir: string): boolean;
|
|
28
7
|
discoverProjects(rootDir: string): MonorepoProject[];
|
|
29
|
-
/**
|
|
30
|
-
* Discover projects from `tsconfig.base.json` `compilerOptions.paths`. Each
|
|
31
|
-
* alias (e.g. `@scope/interfaces` → `interfaces/src/index.ts`) resolves to a
|
|
32
|
-
* lib root (the path before `/src/`), which for real Nx libs contains a
|
|
33
|
-
* project.json. Aliases pointing at non-projects (no project.json/package.json,
|
|
34
|
-
* e.g. `@env` → `environments/environment.ts`) are skipped.
|
|
35
|
-
*/
|
|
36
8
|
private discoverFromTsconfigPaths;
|
|
37
|
-
/** Parse JSON that may contain comments / trailing commas (tsconfig style). */
|
|
38
9
|
private parseJsonc;
|
|
39
10
|
getRootTsConfigPath(rootDir: string): string | null;
|
|
40
11
|
private readWorkspaceJson;
|
|
@@ -37,27 +37,6 @@ exports.NxMonorepoResolver = void 0;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const file_utils_1 = require("../file-utils");
|
|
40
|
-
/**
|
|
41
|
-
* Nx monorepo resolver.
|
|
42
|
-
*
|
|
43
|
-
* Detection: presence of `nx.json` at the workspace root.
|
|
44
|
-
*
|
|
45
|
-
* Project discovery strategies (results deduplicated by absolute path):
|
|
46
|
-
* 1. Read `workspace.json` or `angular.json` → projects map
|
|
47
|
-
* 2. Scan standard Nx directories (`apps/`, `libs/`, `packages/`) for
|
|
48
|
-
* `project.json`, then `package.json` (only when strategy 1 found nothing)
|
|
49
|
-
* 3. `tsconfig.base.json` `paths` — root-level libs referenced only by path
|
|
50
|
-
* alias (e.g. `contracts/`, `interfaces/`) that the directory scan misses
|
|
51
|
-
* 4. Root-level fallback: treat the workspace root itself as a project
|
|
52
|
-
* (standalone Nx setup) when nothing else matched
|
|
53
|
-
*
|
|
54
|
-
* tsconfig resolution:
|
|
55
|
-
* - Returns `tsconfig.base.json` at workspace root (Nx convention)
|
|
56
|
-
* - Falls back to `tsconfig.json` at workspace root
|
|
57
|
-
*
|
|
58
|
-
* Cross-project import resolution is handled by the AST parser via the
|
|
59
|
-
* workspace-wide tsconfig `paths` (tsconfig.base.json), so no scope map is built here.
|
|
60
|
-
*/
|
|
61
40
|
class NxMonorepoResolver {
|
|
62
41
|
logger;
|
|
63
42
|
constructor(logger) {
|
|
@@ -67,15 +46,12 @@ class NxMonorepoResolver {
|
|
|
67
46
|
return fs.existsSync(path.join(rootDir, 'nx.json'));
|
|
68
47
|
}
|
|
69
48
|
discoverProjects(rootDir) {
|
|
70
|
-
// Deduplicate across strategies by absolute project path.
|
|
71
49
|
const byPath = new Map();
|
|
72
50
|
const add = (p) => { if (p && !byPath.has(p.path))
|
|
73
51
|
byPath.set(p.path, p); };
|
|
74
|
-
// Strategy 1: workspace.json / angular.json (authoritative when present)
|
|
75
52
|
const workspaceProjects = this.readWorkspaceJson(rootDir);
|
|
76
53
|
for (const p of workspaceProjects)
|
|
77
54
|
add(p);
|
|
78
|
-
// Strategy 2 & 3: scan standard directories (only when no workspace.json map)
|
|
79
55
|
if (byPath.size === 0) {
|
|
80
56
|
for (const dir of ['apps', 'libs', 'packages']) {
|
|
81
57
|
const fullDir = path.join(rootDir, dir);
|
|
@@ -86,13 +62,8 @@ class NxMonorepoResolver {
|
|
|
86
62
|
add(p);
|
|
87
63
|
}
|
|
88
64
|
}
|
|
89
|
-
// Strategy 4: tsconfig.base.json `paths` — captures libs that live at the
|
|
90
|
-
// repo root (e.g. `contracts/`, `interfaces/`) referenced by path aliases,
|
|
91
|
-
// which the apps/libs/packages scan misses. Only real Nx projects (with a
|
|
92
|
-
// project.json/package.json) are added; dedup handles overlap with the scan.
|
|
93
65
|
for (const p of this.discoverFromTsconfigPaths(rootDir))
|
|
94
66
|
add(p);
|
|
95
|
-
// Root-level fallback (standalone Nx setup)
|
|
96
67
|
if (byPath.size === 0) {
|
|
97
68
|
const rootProject = this.tryReadProject(rootDir, rootDir);
|
|
98
69
|
if (rootProject)
|
|
@@ -102,13 +73,6 @@ class NxMonorepoResolver {
|
|
|
102
73
|
this.logger.debug('NxMonorepoResolver: discovered projects', { count: projects.length });
|
|
103
74
|
return projects;
|
|
104
75
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Discover projects from `tsconfig.base.json` `compilerOptions.paths`. Each
|
|
107
|
-
* alias (e.g. `@scope/interfaces` → `interfaces/src/index.ts`) resolves to a
|
|
108
|
-
* lib root (the path before `/src/`), which for real Nx libs contains a
|
|
109
|
-
* project.json. Aliases pointing at non-projects (no project.json/package.json,
|
|
110
|
-
* e.g. `@env` → `environments/environment.ts`) are skipped.
|
|
111
|
-
*/
|
|
112
76
|
discoverFromTsconfigPaths(rootDir) {
|
|
113
77
|
const tsconfigPath = this.getRootTsConfigPath(rootDir);
|
|
114
78
|
if (!tsconfigPath)
|
|
@@ -118,7 +82,7 @@ class NxMonorepoResolver {
|
|
|
118
82
|
json = this.parseJsonc(fs.readFileSync(tsconfigPath, 'utf-8'));
|
|
119
83
|
}
|
|
120
84
|
catch (err) {
|
|
121
|
-
this.logger.warn('NxMonorepoResolver: failed to parse tsconfig paths', { file: tsconfigPath,
|
|
85
|
+
this.logger.warn('NxMonorepoResolver: failed to parse tsconfig paths', { file: tsconfigPath, err });
|
|
122
86
|
return [];
|
|
123
87
|
}
|
|
124
88
|
const co = json?.compilerOptions ?? {};
|
|
@@ -134,13 +98,12 @@ class NxMonorepoResolver {
|
|
|
134
98
|
const srcIdx = target.indexOf('/src/');
|
|
135
99
|
const relRoot = srcIdx >= 0 ? target.slice(0, srcIdx) : path.dirname(target);
|
|
136
100
|
const libRoot = path.resolve(rootDir, baseUrl, relRoot);
|
|
137
|
-
const project = this.tryReadProject(libRoot, rootDir);
|
|
101
|
+
const project = this.tryReadProject(libRoot, rootDir);
|
|
138
102
|
if (project)
|
|
139
103
|
projects.push(project);
|
|
140
104
|
}
|
|
141
105
|
return projects;
|
|
142
106
|
}
|
|
143
|
-
/** Parse JSON that may contain comments / trailing commas (tsconfig style). */
|
|
144
107
|
parseJsonc(text) {
|
|
145
108
|
try {
|
|
146
109
|
return JSON.parse(text);
|
|
@@ -154,17 +117,14 @@ class NxMonorepoResolver {
|
|
|
154
117
|
}
|
|
155
118
|
}
|
|
156
119
|
getRootTsConfigPath(rootDir) {
|
|
157
|
-
// Nx convention: tsconfig.base.json at workspace root
|
|
158
120
|
const basePath = path.join(rootDir, 'tsconfig.base.json');
|
|
159
121
|
if (fs.existsSync(basePath))
|
|
160
122
|
return basePath;
|
|
161
|
-
// Fallback: tsconfig.json at workspace root
|
|
162
123
|
const rootPath = path.join(rootDir, 'tsconfig.json');
|
|
163
124
|
if (fs.existsSync(rootPath))
|
|
164
125
|
return rootPath;
|
|
165
126
|
return null;
|
|
166
127
|
}
|
|
167
|
-
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
168
128
|
readWorkspaceJson(rootDir) {
|
|
169
129
|
const projects = [];
|
|
170
130
|
for (const filename of ['workspace.json', 'angular.json']) {
|
|
@@ -175,9 +135,6 @@ class NxMonorepoResolver {
|
|
|
175
135
|
const content = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
176
136
|
const projectsMap = content.projects ?? {};
|
|
177
137
|
for (const [name, value] of Object.entries(projectsMap)) {
|
|
178
|
-
// value can be a string (path) or an object with a `root` property.
|
|
179
|
-
// Guard per-entry: a malformed entry (object without `root`) must not
|
|
180
|
-
// abort discovery of the remaining projects in this file.
|
|
181
138
|
const rawRoot = typeof value === 'string'
|
|
182
139
|
? value
|
|
183
140
|
: value?.root;
|
|
@@ -196,7 +153,7 @@ class NxMonorepoResolver {
|
|
|
196
153
|
catch (err) {
|
|
197
154
|
this.logger.warn('NxMonorepoResolver: failed to parse workspace file', {
|
|
198
155
|
file: filePath,
|
|
199
|
-
|
|
156
|
+
err,
|
|
200
157
|
});
|
|
201
158
|
}
|
|
202
159
|
}
|
|
@@ -222,14 +179,12 @@ class NxMonorepoResolver {
|
|
|
222
179
|
projects.push(project);
|
|
223
180
|
continue;
|
|
224
181
|
}
|
|
225
|
-
// Check for nested grouping directories (e.g. libs/shared/utils)
|
|
226
182
|
const nested = this.scanDirectory(projectPath, defaultType, rootDir);
|
|
227
183
|
projects.push(...nested);
|
|
228
184
|
}
|
|
229
185
|
return projects;
|
|
230
186
|
}
|
|
231
187
|
tryReadProject(projectPath, rootDir, defaultType = 'lib') {
|
|
232
|
-
// Check for project.json (Nx project marker)
|
|
233
188
|
const projectJsonPath = path.join(projectPath, 'project.json');
|
|
234
189
|
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
235
190
|
const hasProjectJson = fs.existsSync(projectJsonPath);
|
|
@@ -239,7 +194,6 @@ class NxMonorepoResolver {
|
|
|
239
194
|
let name = path.relative(rootDir, projectPath).replace(/\\/g, '/');
|
|
240
195
|
let type = defaultType;
|
|
241
196
|
let packageName = null;
|
|
242
|
-
// Read project.json for name and type
|
|
243
197
|
if (hasProjectJson) {
|
|
244
198
|
try {
|
|
245
199
|
const projectJson = JSON.parse(fs.readFileSync(projectJsonPath, 'utf-8'));
|
|
@@ -253,14 +207,12 @@ class NxMonorepoResolver {
|
|
|
253
207
|
catch (err) {
|
|
254
208
|
this.logger.warn('NxMonorepoResolver: failed to parse project.json', {
|
|
255
209
|
file: projectJsonPath,
|
|
256
|
-
|
|
210
|
+
err,
|
|
257
211
|
});
|
|
258
212
|
}
|
|
259
213
|
}
|
|
260
|
-
// Read package.json for npm scope
|
|
261
214
|
if (hasPackageJson) {
|
|
262
215
|
packageName = this.readPackageName(projectPath);
|
|
263
|
-
// If no project.json name, use package name without scope
|
|
264
216
|
if (!hasProjectJson && packageName) {
|
|
265
217
|
const shortName = packageName.replace(/^@[^/]+\//, '');
|
|
266
218
|
name = shortName;
|
|
@@ -281,7 +233,6 @@ class NxMonorepoResolver {
|
|
|
281
233
|
}
|
|
282
234
|
}
|
|
283
235
|
inferProjectType(projectPath, name) {
|
|
284
|
-
// Check project.json
|
|
285
236
|
const projectJsonPath = path.join(projectPath, 'project.json');
|
|
286
237
|
if (fs.existsSync(projectJsonPath)) {
|
|
287
238
|
try {
|
|
@@ -291,15 +242,13 @@ class NxMonorepoResolver {
|
|
|
291
242
|
if (projectJson.projectType === 'library')
|
|
292
243
|
return 'lib';
|
|
293
244
|
}
|
|
294
|
-
catch {
|
|
245
|
+
catch { }
|
|
295
246
|
}
|
|
296
|
-
// Infer from path
|
|
297
247
|
const rel = projectPath.replace(/\\/g, '/');
|
|
298
248
|
if (rel.includes('/apps/') || rel.includes('/app/'))
|
|
299
249
|
return 'app';
|
|
300
250
|
if (rel.includes('/libs/') || rel.includes('/lib/') || rel.includes('/packages/'))
|
|
301
251
|
return 'lib';
|
|
302
|
-
// Infer from name
|
|
303
252
|
if (name.includes('lib') || name.includes('shared') || name.includes('util'))
|
|
304
253
|
return 'lib';
|
|
305
254
|
return 'app';
|
|
@@ -5,12 +5,6 @@ export interface EmbedderDeps {
|
|
|
5
5
|
fetchImpl?: typeof fetch;
|
|
6
6
|
baseDelayMs?: number;
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Embedder for any server exposing an OpenAI-style `/embeddings` endpoint:
|
|
10
|
-
* OpenAI cloud, Infinity, TEI, vLLM, LM Studio, LocalAI. One request carries all
|
|
11
|
-
* inputs (`{ input: string[], model, dimensions? }`) and returns
|
|
12
|
-
* `{ data: [{ embedding, index }] }`, re-ordered to input order.
|
|
13
|
-
*/
|
|
14
8
|
export declare class OpenAICompatibleEmbedder implements IEmbedder {
|
|
15
9
|
protected config: Config;
|
|
16
10
|
private logger;
|