@code-rag/mcp-server 0.1.0 → 0.1.1

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.
@@ -1,357 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { ok, err } from 'neverthrow';
3
- import { handleDocs, docsInputSchema } from './docs.js';
4
- import { EmbedError } from '@coderag/core';
5
- // --- Helpers ---
6
- function makeDocResult(overrides = {}) {
7
- return {
8
- chunkId: 'doc-chunk-1',
9
- content: '## Getting Started\n\nInstall with `pnpm install`.',
10
- nlSummary: 'Instructions for getting started with the project',
11
- score: 0.9,
12
- method: 'hybrid',
13
- metadata: {
14
- chunkType: 'doc',
15
- name: 'Getting Started',
16
- declarations: [],
17
- imports: [],
18
- exports: [],
19
- docTitle: 'Getting Started',
20
- },
21
- chunk: {
22
- id: 'doc-chunk-1',
23
- content: '## Getting Started\n\nInstall with `pnpm install`.',
24
- nlSummary: 'Instructions for getting started with the project',
25
- filePath: 'docs/README.md',
26
- startLine: 1,
27
- endLine: 5,
28
- language: 'markdown',
29
- metadata: {
30
- chunkType: 'doc',
31
- name: 'Getting Started',
32
- declarations: [],
33
- imports: [],
34
- exports: [],
35
- docTitle: 'Getting Started',
36
- },
37
- },
38
- ...overrides,
39
- };
40
- }
41
- function makeConfluenceResult(overrides = {}) {
42
- return {
43
- chunkId: 'confluence-chunk-1',
44
- content: '# API Reference\n\nEndpoint documentation.',
45
- nlSummary: 'API reference documentation from Confluence',
46
- score: 0.85,
47
- method: 'hybrid',
48
- metadata: {
49
- chunkType: 'doc',
50
- name: 'API Reference',
51
- declarations: [],
52
- imports: [],
53
- exports: [],
54
- docTitle: 'API Reference',
55
- },
56
- chunk: {
57
- id: 'confluence-chunk-1',
58
- content: '# API Reference\n\nEndpoint documentation.',
59
- nlSummary: 'API reference documentation from Confluence',
60
- filePath: 'confluence://spaces/DEV/pages/12345',
61
- startLine: 1,
62
- endLine: 3,
63
- language: 'markdown',
64
- metadata: {
65
- chunkType: 'doc',
66
- name: 'API Reference',
67
- declarations: [],
68
- imports: [],
69
- exports: [],
70
- docTitle: 'API Reference',
71
- },
72
- },
73
- ...overrides,
74
- };
75
- }
76
- function makeCodeResult() {
77
- return {
78
- chunkId: 'code-chunk-1',
79
- content: 'function hello() {}',
80
- nlSummary: 'A greeting function',
81
- score: 0.8,
82
- method: 'hybrid',
83
- metadata: {
84
- chunkType: 'function',
85
- name: 'hello',
86
- declarations: [],
87
- imports: [],
88
- exports: [],
89
- },
90
- chunk: {
91
- id: 'code-chunk-1',
92
- content: 'function hello() {}',
93
- nlSummary: 'A greeting function',
94
- filePath: 'src/hello.ts',
95
- startLine: 1,
96
- endLine: 1,
97
- language: 'typescript',
98
- metadata: {
99
- chunkType: 'function',
100
- name: 'hello',
101
- declarations: [],
102
- imports: [],
103
- exports: [],
104
- },
105
- },
106
- };
107
- }
108
- function parseResponse(response) {
109
- return JSON.parse(response.content[0].text);
110
- }
111
- // --- Input Schema Validation ---
112
- describe('docsInputSchema', () => {
113
- it('should accept valid input with just query', () => {
114
- const result = docsInputSchema.safeParse({ query: 'getting started' });
115
- expect(result.success).toBe(true);
116
- });
117
- it('should reject empty query', () => {
118
- const result = docsInputSchema.safeParse({ query: '' });
119
- expect(result.success).toBe(false);
120
- });
121
- it('should reject missing query', () => {
122
- const result = docsInputSchema.safeParse({});
123
- expect(result.success).toBe(false);
124
- });
125
- it('should apply default source of all', () => {
126
- const result = docsInputSchema.parse({ query: 'test' });
127
- expect(result.source).toBe('all');
128
- });
129
- it('should accept markdown source', () => {
130
- const result = docsInputSchema.parse({ query: 'test', source: 'markdown' });
131
- expect(result.source).toBe('markdown');
132
- });
133
- it('should accept confluence source', () => {
134
- const result = docsInputSchema.parse({ query: 'test', source: 'confluence' });
135
- expect(result.source).toBe('confluence');
136
- });
137
- it('should reject invalid source', () => {
138
- const result = docsInputSchema.safeParse({ query: 'test', source: 'wiki' });
139
- expect(result.success).toBe(false);
140
- });
141
- it('should reject file_path with path traversal', () => {
142
- const result = docsInputSchema.safeParse({ query: 'test', file_path: '../../etc/passwd' });
143
- expect(result.success).toBe(false);
144
- });
145
- it('should accept valid file_path', () => {
146
- const result = docsInputSchema.safeParse({ query: 'test', file_path: 'docs/guide.md' });
147
- expect(result.success).toBe(true);
148
- });
149
- it('should apply default top_k of 10', () => {
150
- const result = docsInputSchema.parse({ query: 'test' });
151
- expect(result.top_k).toBe(10);
152
- });
153
- it('should reject top_k greater than 100', () => {
154
- const result = docsInputSchema.safeParse({ query: 'test', top_k: 101 });
155
- expect(result.success).toBe(false);
156
- });
157
- it('should reject non-positive top_k', () => {
158
- const result = docsInputSchema.safeParse({ query: 'test', top_k: 0 });
159
- expect(result.success).toBe(false);
160
- });
161
- });
162
- // --- Handler Tests ---
163
- describe('handleDocs', () => {
164
- let mockHybridSearch;
165
- let mockReranker;
166
- beforeEach(() => {
167
- mockHybridSearch = {
168
- search: vi.fn(),
169
- };
170
- mockReranker = {
171
- rerank: vi.fn(),
172
- };
173
- });
174
- it('should return validation error for invalid input', async () => {
175
- const response = await handleDocs({}, mockHybridSearch, mockReranker);
176
- const parsed = parseResponse(response);
177
- expect(parsed.error).toBe('Invalid input');
178
- });
179
- it('should return graceful message when search engine is null', async () => {
180
- const response = await handleDocs({ query: 'test' }, null, null);
181
- const parsed = parseResponse(response);
182
- expect(parsed.results).toEqual([]);
183
- expect(parsed.message).toContain('not initialized');
184
- });
185
- it('should search and return only doc type chunks', async () => {
186
- const docResult = makeDocResult();
187
- const codeResult = makeCodeResult();
188
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([docResult, codeResult]));
189
- const response = await handleDocs({ query: 'getting started' }, mockHybridSearch, null);
190
- const parsed = parseResponse(response);
191
- expect(mockHybridSearch.search).toHaveBeenCalledWith('getting started', { topK: 10 });
192
- expect(parsed.results).toHaveLength(1);
193
- expect(parsed.results[0].file_path).toBe('docs/README.md');
194
- });
195
- it('should filter by markdown source', async () => {
196
- const mdResult = makeDocResult();
197
- const confluenceResult = makeConfluenceResult();
198
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([mdResult, confluenceResult]));
199
- const response = await handleDocs({ query: 'docs', source: 'markdown' }, mockHybridSearch, null);
200
- const parsed = parseResponse(response);
201
- expect(parsed.results).toHaveLength(1);
202
- expect(parsed.results[0].source).toBe('markdown');
203
- });
204
- it('should filter by confluence source', async () => {
205
- const mdResult = makeDocResult();
206
- const confluenceResult = makeConfluenceResult();
207
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([mdResult, confluenceResult]));
208
- const response = await handleDocs({ query: 'api', source: 'confluence' }, mockHybridSearch, null);
209
- const parsed = parseResponse(response);
210
- expect(parsed.results).toHaveLength(1);
211
- expect(parsed.results[0].source).toBe('confluence');
212
- });
213
- it('should return all sources when source is all', async () => {
214
- const mdResult = makeDocResult();
215
- const confluenceResult = makeConfluenceResult();
216
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([mdResult, confluenceResult]));
217
- const response = await handleDocs({ query: 'docs', source: 'all' }, mockHybridSearch, null);
218
- const parsed = parseResponse(response);
219
- expect(parsed.results).toHaveLength(2);
220
- });
221
- it('should filter by file_path', async () => {
222
- const guideResult = makeDocResult({
223
- chunk: {
224
- id: 'doc-guide',
225
- content: 'Guide content',
226
- nlSummary: 'A guide',
227
- filePath: 'docs/guide.md',
228
- startLine: 1,
229
- endLine: 3,
230
- language: 'markdown',
231
- metadata: {
232
- chunkType: 'doc',
233
- name: 'Guide',
234
- declarations: [],
235
- imports: [],
236
- exports: [],
237
- },
238
- },
239
- });
240
- const readmeResult = makeDocResult();
241
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([guideResult, readmeResult]));
242
- const response = await handleDocs({ query: 'docs', file_path: 'guide.md' }, mockHybridSearch, null);
243
- const parsed = parseResponse(response);
244
- expect(parsed.results).toHaveLength(1);
245
- expect(parsed.results[0].file_path).toBe('docs/guide.md');
246
- });
247
- it('should return empty results when no docs match', async () => {
248
- const codeResult = makeCodeResult();
249
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([codeResult]));
250
- const response = await handleDocs({ query: 'test' }, mockHybridSearch, null);
251
- const parsed = parseResponse(response);
252
- expect(parsed.results).toHaveLength(0);
253
- });
254
- it('should handle search API errors gracefully', async () => {
255
- vi.mocked(mockHybridSearch.search).mockResolvedValue(err(new EmbedError('Connection refused')));
256
- const response = await handleDocs({ query: 'test' }, mockHybridSearch, null);
257
- const parsed = parseResponse(response);
258
- expect(parsed.error).toBe('Search failed');
259
- expect(parsed.message).toContain('Connection refused');
260
- });
261
- it('should handle thrown exceptions', async () => {
262
- vi.mocked(mockHybridSearch.search).mockRejectedValue(new Error('Unexpected'));
263
- const response = await handleDocs({ query: 'test' }, mockHybridSearch, null);
264
- const parsed = parseResponse(response);
265
- expect(parsed.error).toBe('Docs search failed');
266
- expect(parsed.message).toBe('Unexpected');
267
- });
268
- it('should format doc results with heading and source', async () => {
269
- const docResult = makeDocResult();
270
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([docResult]));
271
- const response = await handleDocs({ query: 'getting started' }, mockHybridSearch, null);
272
- const parsed = parseResponse(response);
273
- expect(parsed.results[0].file_path).toBe('docs/README.md');
274
- expect(parsed.results[0].heading).toBe('Getting Started');
275
- expect(parsed.results[0].content).toContain('pnpm install');
276
- expect(parsed.results[0].nl_summary).toContain('getting started');
277
- expect(parsed.results[0].score).toBe(0.9);
278
- expect(parsed.results[0].source).toBe('markdown');
279
- });
280
- it('should apply custom top_k', async () => {
281
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([]));
282
- await handleDocs({ query: 'test', top_k: 5 }, mockHybridSearch, null);
283
- expect(mockHybridSearch.search).toHaveBeenCalledWith('test', { topK: 5 });
284
- });
285
- it('should re-rank results when reranker is available', async () => {
286
- const docResult1 = makeDocResult({ score: 0.7 });
287
- const docResult2 = makeDocResult({
288
- chunkId: 'doc-chunk-2',
289
- score: 0.9,
290
- content: '## Advanced\n\nAdvanced usage.',
291
- metadata: {
292
- chunkType: 'doc',
293
- name: 'Advanced',
294
- declarations: [],
295
- imports: [],
296
- exports: [],
297
- docTitle: 'Advanced',
298
- },
299
- chunk: {
300
- id: 'doc-chunk-2',
301
- content: '## Advanced\n\nAdvanced usage.',
302
- nlSummary: 'Advanced usage guide',
303
- filePath: 'docs/advanced.md',
304
- startLine: 1,
305
- endLine: 3,
306
- language: 'markdown',
307
- metadata: {
308
- chunkType: 'doc',
309
- name: 'Advanced',
310
- declarations: [],
311
- imports: [],
312
- exports: [],
313
- docTitle: 'Advanced',
314
- },
315
- },
316
- });
317
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([docResult1, docResult2]));
318
- // Reranker reverses order
319
- vi.mocked(mockReranker.rerank).mockResolvedValue(ok([docResult2, docResult1]));
320
- const response = await handleDocs({ query: 'advanced' }, mockHybridSearch, mockReranker);
321
- const parsed = parseResponse(response);
322
- expect(mockReranker.rerank).toHaveBeenCalled();
323
- expect(parsed.results[0].heading).toBe('Advanced');
324
- });
325
- it('should fall back to original results when reranking fails', async () => {
326
- const docResult = makeDocResult();
327
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([docResult]));
328
- vi.mocked(mockReranker.rerank).mockResolvedValue(err(new EmbedError('Rerank failed')));
329
- const response = await handleDocs({ query: 'test' }, mockHybridSearch, mockReranker);
330
- const parsed = parseResponse(response);
331
- expect(parsed.results).toHaveLength(1);
332
- expect(parsed.results[0].file_path).toBe('docs/README.md');
333
- });
334
- it('should not invoke reranker when no doc results remain after filtering', async () => {
335
- const codeResult = makeCodeResult();
336
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([codeResult]));
337
- await handleDocs({ query: 'test' }, mockHybridSearch, mockReranker);
338
- expect(mockReranker.rerank).not.toHaveBeenCalled();
339
- });
340
- it('should use name as heading fallback when docTitle is missing', async () => {
341
- const docResult = makeDocResult({
342
- metadata: {
343
- chunkType: 'doc',
344
- name: 'Section Name',
345
- declarations: [],
346
- imports: [],
347
- exports: [],
348
- // No docTitle
349
- },
350
- });
351
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok([docResult]));
352
- const response = await handleDocs({ query: 'test' }, mockHybridSearch, null);
353
- const parsed = parseResponse(response);
354
- expect(parsed.results[0].heading).toBe('Section Name');
355
- });
356
- });
357
- //# sourceMappingURL=docs.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"docs.test.js","sourceRoot":"","sources":["../../src/tools/docs.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,244 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { ok, err } from 'neverthrow';
3
- import { handleExplain, explainInputSchema } from './explain.js';
4
- import { EmbedError } from '@coderag/core';
5
- // --- Helpers ---
6
- function makeSearchResult(overrides = {}) {
7
- return {
8
- chunkId: 'chunk-1',
9
- content: 'function hello() {}',
10
- nlSummary: 'A greeting function',
11
- score: 0.95,
12
- method: 'hybrid',
13
- metadata: {
14
- chunkType: 'function',
15
- name: 'hello',
16
- declarations: [],
17
- imports: [],
18
- exports: [],
19
- },
20
- chunk: {
21
- id: 'chunk-1',
22
- content: 'function hello() {}',
23
- nlSummary: 'A greeting function',
24
- filePath: 'src/utils/hello.ts',
25
- startLine: 1,
26
- endLine: 3,
27
- language: 'typescript',
28
- metadata: {
29
- chunkType: 'function',
30
- name: 'hello',
31
- declarations: [],
32
- imports: [],
33
- exports: [],
34
- },
35
- },
36
- ...overrides,
37
- };
38
- }
39
- function parseResponse(response) {
40
- return JSON.parse(response.content[0].text);
41
- }
42
- // --- Input Validation Tests ---
43
- describe('explainInputSchema', () => {
44
- it('should accept valid input with name', () => {
45
- const result = explainInputSchema.safeParse({ name: 'hello' });
46
- expect(result.success).toBe(true);
47
- });
48
- it('should accept valid input with file_path', () => {
49
- const result = explainInputSchema.safeParse({ file_path: 'src/utils/hello.ts' });
50
- expect(result.success).toBe(true);
51
- });
52
- it('should reject input with neither file_path nor name', () => {
53
- const result = explainInputSchema.safeParse({});
54
- expect(result.success).toBe(false);
55
- });
56
- it('should reject file_path with path traversal', () => {
57
- const result = explainInputSchema.safeParse({ file_path: '../../etc/passwd' });
58
- expect(result.success).toBe(false);
59
- });
60
- it('should apply default detail_level of detailed', () => {
61
- const result = explainInputSchema.parse({ name: 'hello' });
62
- expect(result.detail_level).toBe('detailed');
63
- });
64
- it('should accept brief detail_level', () => {
65
- const result = explainInputSchema.parse({ name: 'hello', detail_level: 'brief' });
66
- expect(result.detail_level).toBe('brief');
67
- });
68
- it('should reject invalid detail_level', () => {
69
- const result = explainInputSchema.safeParse({ name: 'hello', detail_level: 'verbose' });
70
- expect(result.success).toBe(false);
71
- });
72
- it('should accept both file_path and name together', () => {
73
- const result = explainInputSchema.safeParse({ file_path: 'src/hello.ts', name: 'hello' });
74
- expect(result.success).toBe(true);
75
- });
76
- });
77
- // --- Handler Tests ---
78
- describe('handleExplain', () => {
79
- let mockHybridSearch;
80
- let mockContextExpander;
81
- beforeEach(() => {
82
- mockHybridSearch = {
83
- search: vi.fn(),
84
- };
85
- mockContextExpander = {
86
- expand: vi.fn(),
87
- };
88
- });
89
- it('should return validation error when both file_path and name are missing', async () => {
90
- const response = await handleExplain({}, mockHybridSearch, mockContextExpander);
91
- const parsed = parseResponse(response);
92
- expect(parsed.error).toBe('Invalid input');
93
- });
94
- it('should return validation error for file_path with path traversal', async () => {
95
- const response = await handleExplain({ file_path: '../../../etc/passwd' }, mockHybridSearch, mockContextExpander);
96
- const parsed = parseResponse(response);
97
- expect(parsed.error).toBe('Invalid input');
98
- });
99
- it('should return graceful message when services are null', async () => {
100
- const response = await handleExplain({ name: 'hello' }, null, null);
101
- const parsed = parseResponse(response);
102
- expect(parsed.chunks_found).toBe(0);
103
- expect(parsed.explanation.chunks).toEqual([]);
104
- expect(parsed.message).toContain('not initialized');
105
- });
106
- it('should search by name and return matching chunks', async () => {
107
- const results = [makeSearchResult()];
108
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
109
- const expandedContext = {
110
- primaryResults: results,
111
- relatedChunks: [],
112
- graphExcerpt: { nodes: [], edges: [] },
113
- };
114
- vi.mocked(mockContextExpander.expand).mockReturnValue(expandedContext);
115
- const response = await handleExplain({ name: 'hello' }, mockHybridSearch, mockContextExpander);
116
- const parsed = parseResponse(response);
117
- expect(mockHybridSearch.search).toHaveBeenCalledWith('hello', { topK: 5 });
118
- expect(parsed.chunks_found).toBe(1);
119
- expect(parsed.explanation.chunks[0].name).toBe('hello');
120
- expect(parsed.explanation.chunks[0].nl_summary).toBe('A greeting function');
121
- expect(parsed.explanation.chunks[0].code).toBe('function hello() {}');
122
- });
123
- it('should search by file_path and return matching chunks', async () => {
124
- const results = [makeSearchResult()];
125
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
126
- const expandedContext = {
127
- primaryResults: results,
128
- relatedChunks: [],
129
- graphExcerpt: { nodes: [], edges: [] },
130
- };
131
- vi.mocked(mockContextExpander.expand).mockReturnValue(expandedContext);
132
- const response = await handleExplain({ file_path: 'src/utils/hello.ts' }, mockHybridSearch, mockContextExpander);
133
- const parsed = parseResponse(response);
134
- expect(mockHybridSearch.search).toHaveBeenCalledWith('src/utils/hello.ts', { topK: 20 });
135
- expect(parsed.chunks_found).toBe(1);
136
- expect(parsed.explanation.chunks[0].file_path).toBe('src/utils/hello.ts');
137
- });
138
- it('should return brief output without code or related_symbols', async () => {
139
- const results = [makeSearchResult()];
140
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
141
- const response = await handleExplain({ name: 'hello', detail_level: 'brief' }, mockHybridSearch, mockContextExpander);
142
- const parsed = parseResponse(response);
143
- expect(parsed.explanation.detail_level).toBe('brief');
144
- expect(parsed.explanation.chunks[0].nl_summary).toBe('A greeting function');
145
- expect(parsed.explanation.chunks[0].code).toBeUndefined();
146
- expect(parsed.explanation.related_symbols).toBeUndefined();
147
- });
148
- it('should return detailed output with code and related_symbols', async () => {
149
- const results = [makeSearchResult()];
150
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
151
- const depResult = makeSearchResult({
152
- chunkId: 'dep-1',
153
- metadata: {
154
- chunkType: 'function',
155
- name: 'greet',
156
- declarations: [],
157
- imports: [],
158
- exports: [],
159
- },
160
- chunk: {
161
- id: 'dep-1',
162
- content: 'function greet() {}',
163
- nlSummary: 'A greet helper',
164
- filePath: 'src/utils/greet.ts',
165
- startLine: 1,
166
- endLine: 2,
167
- language: 'typescript',
168
- metadata: {
169
- chunkType: 'function',
170
- name: 'greet',
171
- declarations: [],
172
- imports: [],
173
- exports: [],
174
- },
175
- },
176
- });
177
- const expandedContext = {
178
- primaryResults: results,
179
- relatedChunks: [
180
- {
181
- chunk: depResult,
182
- relationship: 'imports',
183
- distance: 1,
184
- },
185
- ],
186
- graphExcerpt: { nodes: [], edges: [] },
187
- };
188
- vi.mocked(mockContextExpander.expand).mockReturnValue(expandedContext);
189
- const response = await handleExplain({ name: 'hello', detail_level: 'detailed' }, mockHybridSearch, mockContextExpander);
190
- const parsed = parseResponse(response);
191
- expect(parsed.explanation.detail_level).toBe('detailed');
192
- expect(parsed.explanation.chunks[0].code).toBe('function hello() {}');
193
- expect(parsed.explanation.related_symbols).toContain('greet');
194
- });
195
- it('should handle search API errors gracefully', async () => {
196
- vi.mocked(mockHybridSearch.search).mockResolvedValue(err(new EmbedError('Connection refused')));
197
- const response = await handleExplain({ name: 'hello' }, mockHybridSearch, mockContextExpander);
198
- const parsed = parseResponse(response);
199
- expect(parsed.error).toBe('Search failed');
200
- expect(parsed.message).toContain('Connection refused');
201
- });
202
- it('should handle thrown exceptions', async () => {
203
- vi.mocked(mockHybridSearch.search).mockRejectedValue(new Error('Unexpected'));
204
- const response = await handleExplain({ name: 'hello' }, mockHybridSearch, mockContextExpander);
205
- const parsed = parseResponse(response);
206
- expect(parsed.error).toBe('Explain failed');
207
- expect(parsed.message).toBe('Unexpected');
208
- });
209
- it('should return empty explanation when no chunks match name', async () => {
210
- const results = [makeSearchResult({
211
- metadata: {
212
- chunkType: 'function',
213
- name: 'other',
214
- declarations: [],
215
- imports: [],
216
- exports: [],
217
- },
218
- })];
219
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
220
- const response = await handleExplain({ name: 'hello' }, mockHybridSearch, mockContextExpander);
221
- const parsed = parseResponse(response);
222
- expect(parsed.chunks_found).toBe(0);
223
- expect(parsed.message).toContain('No chunks found matching name: hello');
224
- });
225
- it('should return empty explanation when no chunks match file_path', async () => {
226
- const results = [makeSearchResult()]; // filePath is 'src/utils/hello.ts'
227
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
228
- const response = await handleExplain({ file_path: 'src/other.ts' }, mockHybridSearch, mockContextExpander);
229
- const parsed = parseResponse(response);
230
- expect(parsed.chunks_found).toBe(0);
231
- expect(parsed.message).toContain('No chunks found for file: src/other.ts');
232
- });
233
- it('should work without context expander in detailed mode', async () => {
234
- const results = [makeSearchResult()];
235
- vi.mocked(mockHybridSearch.search).mockResolvedValue(ok(results));
236
- const response = await handleExplain({ name: 'hello', detail_level: 'detailed' }, mockHybridSearch, null);
237
- const parsed = parseResponse(response);
238
- expect(parsed.chunks_found).toBe(1);
239
- expect(parsed.explanation.chunks[0].code).toBe('function hello() {}');
240
- // No related_symbols since context expander is null
241
- expect(parsed.explanation.related_symbols).toBeUndefined();
242
- });
243
- });
244
- //# sourceMappingURL=explain.test.js.map