@liendev/lien 0.24.0 → 0.25.0

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Give AI deep understanding of your codebase through semantic search. 100% local, 100% private.**
6
6
 
7
- Lien connects AI coding assistants like Cursor to your codebase through the Model Context Protocol (MCP). Ask questions in natural language, get precise answers from semantic search—all running locally on your machine.
7
+ Lien connects AI coding assistants like Cursor and Claude Code to your codebase through the Model Context Protocol (MCP). Ask questions in natural language, get precise answers from semantic search—all running locally on your machine.
8
8
 
9
9
  📚 **[Full Documentation](https://lien.dev)** | 🚀 **[Getting Started](https://lien.dev/guide/getting-started)** | 🔍 **[How It Works](https://lien.dev/how-it-works)**
10
10
 
@@ -15,7 +15,7 @@ Lien connects AI coding assistants like Cursor to your codebase through the Mode
15
15
  - 🔒 **100% Local & Private** - All code analysis happens on your machine
16
16
  - 🚀 **Semantic Search** - Natural language queries: "How does authentication work?"
17
17
  - 🌐 **Cross-Repo Search** - Search across all repositories in your organization (Qdrant backend)
18
- - 🎯 **MCP Integration** - Works seamlessly with Cursor and other MCP-compatible tools
18
+ - 🎯 **MCP Integration** - Works seamlessly with Cursor, Claude Code, and other MCP-compatible tools
19
19
  - ⚡ **Fast** - Sub-500ms queries, minutes to index large codebases
20
20
  - 🆓 **Free Forever** - No API costs, no subscriptions, no usage limits
21
21
  - 📦 **Framework-Aware** - Auto-detects Node.js, Laravel, Shopify; supports 15+ languages
@@ -39,7 +39,7 @@ npm install -g @liendev/lien
39
39
  }
40
40
  }
41
41
 
42
- # 3. Restart Cursor and start asking questions!
42
+ # 3. Restart your AI assistant (Cursor, Claude Code) and start asking questions!
43
43
  ```
44
44
 
45
45
  That's it—zero configuration needed. Lien auto-detects your project and indexes on first use.
@@ -99,7 +99,7 @@ Lien tracks code complexity with intuitive outputs:
99
99
  ## Documentation
100
100
 
101
101
  - **[Installation](https://lien.dev/guide/installation)** - npm, npx, or local setup
102
- - **[Getting Started](https://lien.dev/guide/getting-started)** - Step-by-step configuration for Cursor
102
+ - **[Getting Started](https://lien.dev/guide/getting-started)** - Step-by-step configuration for Cursor or Claude Code
103
103
  - **[Configuration](https://lien.dev/guide/configuration)** - Customize indexing, thresholds, performance
104
104
  - **[CLI Commands](https://lien.dev/guide/cli-commands)** - Full command reference
105
105
  - **[MCP Tools](https://lien.dev/guide/mcp-tools)** - Complete API reference for all 6 tools
package/dist/index.js CHANGED
@@ -8292,11 +8292,17 @@ var SemanticSearchSchema = external_exports.object({
8292
8292
 
8293
8293
  // src/mcp/schemas/similarity.schema.ts
8294
8294
  var FindSimilarSchema = external_exports.object({
8295
- code: external_exports.string().min(10, "Code snippet must be at least 10 characters").describe(
8295
+ code: external_exports.string().min(24, "Code snippet must be at least 24 characters").describe(
8296
8296
  "Code snippet to find similar implementations for.\n\nProvide a representative code sample that demonstrates the pattern you want to find similar examples of in the codebase."
8297
8297
  ),
8298
8298
  limit: external_exports.number().int().min(1, "Limit must be at least 1").max(20, "Limit cannot exceed 20").default(5).describe(
8299
8299
  "Number of similar code blocks to return.\n\nDefault: 5"
8300
+ ),
8301
+ language: external_exports.string().min(1, "Language filter cannot be empty").optional().describe(
8302
+ "Filter by programming language.\n\nExamples: 'typescript', 'python', 'javascript', 'php'\n\nIf omitted, searches all languages."
8303
+ ),
8304
+ pathHint: external_exports.string().min(1, "Path hint cannot be empty").optional().describe(
8305
+ "Filter by file path substring.\n\nOnly returns results where the file path contains this string (case-insensitive).\n\nExamples: 'src/api', 'components', 'utils'"
8300
8306
  )
8301
8307
  });
8302
8308
 
@@ -8378,7 +8384,13 @@ Results include a relevance category (highly_relevant, relevant, loosely_related
8378
8384
  - Finding duplicate implementations
8379
8385
  - Refactoring similar patterns together
8380
8386
 
8381
- Provide at least 10 characters of code to match against. Results include a relevance category for each match.`
8387
+ Provide at least 24 characters of code to match against. Results include a relevance category for each match.
8388
+
8389
+ Optional filters:
8390
+ - language: Filter by programming language (e.g., "typescript", "python")
8391
+ - pathHint: Filter by file path substring (e.g., "src/api", "components")
8392
+
8393
+ Low-relevance results (not_relevant) are automatically pruned.`
8382
8394
  ),
8383
8395
  toMCPToolSchema(
8384
8396
  GetFilesContextSchema,
@@ -8576,6 +8588,19 @@ async function handleSemanticSearch(args, ctx) {
8576
8588
  }
8577
8589
 
8578
8590
  // src/mcp/handlers/find-similar.ts
8591
+ function applyLanguageFilter(results, language) {
8592
+ const lang = language.toLowerCase();
8593
+ return results.filter((r) => r.metadata.language?.toLowerCase() === lang);
8594
+ }
8595
+ function applyPathHintFilter(results, pathHint) {
8596
+ const hint = pathHint.toLowerCase();
8597
+ return results.filter((r) => (r.metadata.file?.toLowerCase() ?? "").includes(hint));
8598
+ }
8599
+ function pruneIrrelevantResults(results) {
8600
+ const beforePrune = results.length;
8601
+ const filtered = results.filter((r) => r.relevance !== "not_relevant");
8602
+ return { filtered, prunedCount: beforePrune - filtered.length };
8603
+ }
8579
8604
  async function handleFindSimilar(args, ctx) {
8580
8605
  const { vectorDB, embeddings, log, checkAndReconnect, getIndexMetadata } = ctx;
8581
8606
  return await wrapToolHandler(
@@ -8584,11 +8609,27 @@ async function handleFindSimilar(args, ctx) {
8584
8609
  log(`Finding similar code...`);
8585
8610
  await checkAndReconnect();
8586
8611
  const codeEmbedding = await embeddings.embed(validatedArgs.code);
8587
- const results = await vectorDB.search(codeEmbedding, validatedArgs.limit, validatedArgs.code);
8588
- log(`Found ${results.length} similar chunks`);
8612
+ const limit = validatedArgs.limit ?? 5;
8613
+ const extraLimit = limit + 10;
8614
+ let results = await vectorDB.search(codeEmbedding, extraLimit, validatedArgs.code);
8615
+ const filtersApplied = { prunedLowRelevance: 0 };
8616
+ if (validatedArgs.language) {
8617
+ filtersApplied.language = validatedArgs.language;
8618
+ results = applyLanguageFilter(results, validatedArgs.language);
8619
+ }
8620
+ if (validatedArgs.pathHint) {
8621
+ filtersApplied.pathHint = validatedArgs.pathHint;
8622
+ results = applyPathHintFilter(results, validatedArgs.pathHint);
8623
+ }
8624
+ const { filtered, prunedCount } = pruneIrrelevantResults(results);
8625
+ filtersApplied.prunedLowRelevance = prunedCount;
8626
+ const finalResults = filtered.slice(0, limit);
8627
+ log(`Found ${finalResults.length} similar chunks`);
8628
+ const hasFilters = filtersApplied.language || filtersApplied.pathHint || filtersApplied.prunedLowRelevance > 0;
8589
8629
  return {
8590
8630
  indexInfo: getIndexMetadata(),
8591
- results
8631
+ results: finalResults,
8632
+ ...hasFilters && { filtersApplied }
8592
8633
  };
8593
8634
  }
8594
8635
  )(args);