codebasesearch 0.1.19 → 0.1.21

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/mcp.js CHANGED
@@ -134,17 +134,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
134
134
  };
135
135
  }
136
136
 
137
+ const repoPath = typeof repositoryPath === 'string' ? repositoryPath : null;
137
138
  const text =
138
139
  result.resultsCount === 0
139
140
  ? `No results found for query: "${query}"`
140
141
  : `Found ${result.resultsCount} result${result.resultsCount !== 1 ? 's' : ''} for query: "${query}"\n\n${result.results
141
- .map(
142
- (r) =>
143
- `${r.rank}. ${r.absolutePath}:${r.lines} (score: ${r.score}%)\n${r.snippet
144
- .split('\n')
145
- .map((line) => ` ${line}`)
146
- .join('\n')}`
147
- )
142
+ .map((r) => {
143
+ const pathPart = r.relativePath || r.absolutePath;
144
+ const lineCount = r.totalLines ? ` [${r.totalLines}L]` : '';
145
+ const ctx = r.enclosingContext ? ` (in: ${r.enclosingContext})` : '';
146
+ const header = `${r.rank}. ${pathPart}${lineCount}:${r.lines}${ctx} (score: ${r.score}%)`;
147
+ const body = r.snippet.split('\n').map((line) => ` ${line}`).join('\n');
148
+ return `${header}\n${body}`;
149
+ })
148
150
  .join('\n\n')}`;
149
151
 
150
152
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebasesearch",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "Ultra-simple code search tool with Jina embeddings, LanceDB, and MCP protocol support",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,10 +1,34 @@
1
1
  import { parentPort } from 'worker_threads';
2
2
  import { resolve, relative } from 'path';
3
- import { existsSync } from 'fs';
3
+ import { existsSync, readFileSync } from 'fs';
4
4
  import { loadIgnorePatterns } from './ignore-parser.js';
5
5
  import { scanRepository } from './scanner.js';
6
6
  import { buildTextIndex, searchText } from './text-search.js';
7
7
 
8
+ function findEnclosingContext(content, lineStart) {
9
+ const lines = content.split('\n');
10
+ const targetLine = Math.min(lineStart - 1, lines.length - 1);
11
+ const skip = new Set(['if', 'for', 'while', 'switch', 'catch', 'else']);
12
+ for (let i = targetLine; i >= 0; i--) {
13
+ const line = lines[i];
14
+ const m = line.match(/(?:^|\s)(?:async\s+)?(?:function\s+(\w+)|class\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(|(?:static\s+)?(?:async\s+)?(\w+)\s*\([^)]*\)\s*\{)/);
15
+ if (m) {
16
+ const name = m[1] || m[2] || m[3] || m[4];
17
+ if (name && !skip.has(name)) return name;
18
+ }
19
+ }
20
+ return null;
21
+ }
22
+
23
+ function getFileTotalLines(absoluteFilePath) {
24
+ try {
25
+ const content = readFileSync(absoluteFilePath, 'utf8');
26
+ return content.split('\n').length;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+
8
32
  let indexCache = new Map();
9
33
 
10
34
  async function initializeIndex(repositoryPath) {
@@ -55,12 +79,18 @@ async function performSearch(repositoryPath, query) {
55
79
  resultsCount: results.length,
56
80
  results: results.slice(0, 10).map((result, idx) => {
57
81
  const absoluteFilePath = resolve(absolutePath, result.file_path);
82
+ const totalLines = getFileTotalLines(absoluteFilePath);
83
+ const enclosingContext = findEnclosingContext(result.content, result.line_start);
84
+ const relPath = relative(absolutePath, absoluteFilePath);
58
85
  return {
59
86
  rank: idx + 1,
60
87
  absolutePath: absoluteFilePath,
88
+ relativePath: relPath,
61
89
  lines: `${result.line_start}-${result.line_end}`,
90
+ totalLines,
91
+ enclosingContext,
62
92
  score: (result.score * 100).toFixed(1),
63
- snippet: result.content.split('\n').slice(0, 3).join('\n'),
93
+ snippet: result.content.split('\n').slice(0, 30).join('\n'),
64
94
  };
65
95
  }),
66
96
  };