@liendev/lien 0.23.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 +8 -11
- package/dist/index.js +87 -163
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
- package/CURSOR_RULES_TEMPLATE.md +0 -157
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
|
|
@@ -26,15 +26,10 @@ Lien connects AI coding assistants like Cursor to your codebase through the Mode
|
|
|
26
26
|
## Quick Start
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
# Install
|
|
29
|
+
# 1. Install
|
|
30
30
|
npm install -g @liendev/lien
|
|
31
31
|
|
|
32
|
-
#
|
|
33
|
-
cd /path/to/your/project
|
|
34
|
-
lien init
|
|
35
|
-
lien index
|
|
36
|
-
|
|
37
|
-
# Configure Cursor - create .cursor/mcp.json
|
|
32
|
+
# 2. Add to your project - create .cursor/mcp.json
|
|
38
33
|
{
|
|
39
34
|
"mcpServers": {
|
|
40
35
|
"lien": {
|
|
@@ -44,9 +39,11 @@ lien index
|
|
|
44
39
|
}
|
|
45
40
|
}
|
|
46
41
|
|
|
47
|
-
# Restart Cursor and start asking questions!
|
|
42
|
+
# 3. Restart your AI assistant (Cursor, Claude Code) and start asking questions!
|
|
48
43
|
```
|
|
49
44
|
|
|
45
|
+
That's it—zero configuration needed. Lien auto-detects your project and indexes on first use.
|
|
46
|
+
|
|
50
47
|
**👉 [Full installation guide](https://lien.dev/guide/installation)**
|
|
51
48
|
|
|
52
49
|
### Qdrant Backend (Cross-Repo Search)
|
|
@@ -102,7 +99,7 @@ Lien tracks code complexity with intuitive outputs:
|
|
|
102
99
|
## Documentation
|
|
103
100
|
|
|
104
101
|
- **[Installation](https://lien.dev/guide/installation)** - npm, npx, or local setup
|
|
105
|
-
- **[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
|
|
106
103
|
- **[Configuration](https://lien.dev/guide/configuration)** - Customize indexing, thresholds, performance
|
|
107
104
|
- **[CLI Commands](https://lien.dev/guide/cli-commands)** - Full command reference
|
|
108
105
|
- **[MCP Tools](https://lien.dev/guide/mcp-tools)** - Complete API reference for all 6 tools
|
package/dist/index.js
CHANGED
|
@@ -3591,15 +3591,13 @@ var require_dist = __commonJS({
|
|
|
3591
3591
|
// src/cli/index.ts
|
|
3592
3592
|
import { Command } from "commander";
|
|
3593
3593
|
import { createRequire as createRequire3 } from "module";
|
|
3594
|
-
import { fileURLToPath as
|
|
3594
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3595
3595
|
import { dirname as dirname3, join as join3 } from "path";
|
|
3596
3596
|
|
|
3597
3597
|
// src/cli/init.ts
|
|
3598
3598
|
import fs from "fs/promises";
|
|
3599
3599
|
import path from "path";
|
|
3600
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3601
3600
|
import chalk2 from "chalk";
|
|
3602
|
-
import inquirer from "inquirer";
|
|
3603
3601
|
|
|
3604
3602
|
// src/utils/banner.ts
|
|
3605
3603
|
import figlet from "figlet";
|
|
@@ -3661,8 +3659,6 @@ function showCompactBanner() {
|
|
|
3661
3659
|
}
|
|
3662
3660
|
|
|
3663
3661
|
// src/cli/init.ts
|
|
3664
|
-
var __filename2 = fileURLToPath2(import.meta.url);
|
|
3665
|
-
var __dirname2 = path.dirname(__filename2);
|
|
3666
3662
|
async function initCommand(options = {}) {
|
|
3667
3663
|
showCompactBanner();
|
|
3668
3664
|
console.log(chalk2.bold("\nLien Initialization\n"));
|
|
@@ -3695,129 +3691,6 @@ async function initCommand(options = {}) {
|
|
|
3695
3691
|
console.log(chalk2.dim(" You can safely delete it."));
|
|
3696
3692
|
} catch {
|
|
3697
3693
|
}
|
|
3698
|
-
await promptAndInstallCursorRules(rootDir, options);
|
|
3699
|
-
}
|
|
3700
|
-
async function getPathType(filepath) {
|
|
3701
|
-
try {
|
|
3702
|
-
const stats = await fs.stat(filepath);
|
|
3703
|
-
if (stats.isDirectory()) return "directory";
|
|
3704
|
-
if (stats.isFile()) return "file";
|
|
3705
|
-
return "other";
|
|
3706
|
-
} catch {
|
|
3707
|
-
return "none";
|
|
3708
|
-
}
|
|
3709
|
-
}
|
|
3710
|
-
async function convertRulesFileToDirectory(rulesPath, templatePath) {
|
|
3711
|
-
const existingRules = await fs.readFile(rulesPath, "utf-8");
|
|
3712
|
-
const parentDir = path.dirname(rulesPath);
|
|
3713
|
-
const baseName = path.basename(rulesPath);
|
|
3714
|
-
const tempDir = await fs.mkdtemp(path.join(parentDir, baseName + "_tmp_"));
|
|
3715
|
-
const backupPath = rulesPath + ".backup";
|
|
3716
|
-
try {
|
|
3717
|
-
await fs.writeFile(path.join(tempDir, "project.mdc"), existingRules);
|
|
3718
|
-
await fs.copyFile(templatePath, path.join(tempDir, "lien.mdc"));
|
|
3719
|
-
try {
|
|
3720
|
-
await fs.unlink(backupPath);
|
|
3721
|
-
} catch {
|
|
3722
|
-
}
|
|
3723
|
-
await fs.rename(rulesPath, backupPath);
|
|
3724
|
-
try {
|
|
3725
|
-
await fs.rename(tempDir, rulesPath);
|
|
3726
|
-
try {
|
|
3727
|
-
await fs.unlink(backupPath);
|
|
3728
|
-
} catch {
|
|
3729
|
-
console.log(chalk2.yellow("\u26A0\uFE0F Could not remove backup file, but conversion succeeded"));
|
|
3730
|
-
console.log(chalk2.dim(`Backup file: ${backupPath}`));
|
|
3731
|
-
}
|
|
3732
|
-
} catch (renameErr) {
|
|
3733
|
-
try {
|
|
3734
|
-
await fs.rename(backupPath, rulesPath);
|
|
3735
|
-
} catch (restoreErr) {
|
|
3736
|
-
console.log(chalk2.red("\u274C Failed to restore original .cursor/rules from backup after failed conversion."));
|
|
3737
|
-
console.log(chalk2.red(` - Original error: ${renameErr instanceof Error ? renameErr.message : renameErr}`));
|
|
3738
|
-
console.log(chalk2.red(` - Restore error: ${restoreErr instanceof Error ? restoreErr.message : restoreErr}`));
|
|
3739
|
-
console.log(chalk2.red(` - Backup file location: ${backupPath}`));
|
|
3740
|
-
throw new Error("Failed to convert .cursor/rules to directory and failed to restore from backup. Manual recovery needed.");
|
|
3741
|
-
}
|
|
3742
|
-
throw renameErr;
|
|
3743
|
-
}
|
|
3744
|
-
console.log(chalk2.green("\u2713 Converted .cursor/rules to directory"));
|
|
3745
|
-
console.log(chalk2.green(" - Your project rules: .cursor/rules/project.mdc"));
|
|
3746
|
-
console.log(chalk2.green(" - Lien rules: .cursor/rules/lien.mdc"));
|
|
3747
|
-
} catch (err) {
|
|
3748
|
-
try {
|
|
3749
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
3750
|
-
} catch {
|
|
3751
|
-
}
|
|
3752
|
-
throw err;
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
async function handleExistingRulesDirectory(rulesPath, templatePath) {
|
|
3756
|
-
const targetPath = path.join(rulesPath, "lien.mdc");
|
|
3757
|
-
try {
|
|
3758
|
-
await fs.access(targetPath);
|
|
3759
|
-
console.log(chalk2.dim("lien.mdc already exists in .cursor/rules/, skipping..."));
|
|
3760
|
-
return;
|
|
3761
|
-
} catch {
|
|
3762
|
-
}
|
|
3763
|
-
await fs.copyFile(templatePath, targetPath);
|
|
3764
|
-
console.log(chalk2.green("\u2713 Installed Cursor rules as .cursor/rules/lien.mdc"));
|
|
3765
|
-
}
|
|
3766
|
-
async function handleExistingRulesFile(rulesPath, templatePath, options) {
|
|
3767
|
-
if (options.yes) {
|
|
3768
|
-
console.log(chalk2.dim("Skipped Cursor rules installation (preserving existing .cursor/rules file)"));
|
|
3769
|
-
return;
|
|
3770
|
-
}
|
|
3771
|
-
const { convertToDir } = await inquirer.prompt([{
|
|
3772
|
-
type: "confirm",
|
|
3773
|
-
name: "convertToDir",
|
|
3774
|
-
message: "Existing .cursor/rules file found. Convert to directory and preserve your rules?",
|
|
3775
|
-
default: true
|
|
3776
|
-
}]);
|
|
3777
|
-
if (convertToDir) {
|
|
3778
|
-
await convertRulesFileToDirectory(rulesPath, templatePath);
|
|
3779
|
-
} else {
|
|
3780
|
-
console.log(chalk2.dim("Skipped Cursor rules installation (preserving existing file)"));
|
|
3781
|
-
}
|
|
3782
|
-
}
|
|
3783
|
-
async function handleInvalidRulesPath() {
|
|
3784
|
-
console.log(chalk2.yellow("\u26A0\uFE0F .cursor/rules exists but is not a regular file or directory"));
|
|
3785
|
-
console.log(chalk2.dim("Skipped Cursor rules installation"));
|
|
3786
|
-
}
|
|
3787
|
-
async function handleFreshRulesInstall(rulesPath, templatePath) {
|
|
3788
|
-
await fs.mkdir(rulesPath, { recursive: true });
|
|
3789
|
-
await fs.copyFile(templatePath, path.join(rulesPath, "lien.mdc"));
|
|
3790
|
-
console.log(chalk2.green("\u2713 Installed Cursor rules as .cursor/rules/lien.mdc"));
|
|
3791
|
-
}
|
|
3792
|
-
async function installCursorRulesFiles(rootDir, options) {
|
|
3793
|
-
const cursorRulesDir = path.join(rootDir, ".cursor");
|
|
3794
|
-
await fs.mkdir(cursorRulesDir, { recursive: true });
|
|
3795
|
-
const templatePath = path.join(__dirname2, "../CURSOR_RULES_TEMPLATE.md");
|
|
3796
|
-
const rulesPath = path.join(cursorRulesDir, "rules");
|
|
3797
|
-
const pathType = await getPathType(rulesPath);
|
|
3798
|
-
const handlers = {
|
|
3799
|
-
directory: () => handleExistingRulesDirectory(rulesPath, templatePath),
|
|
3800
|
-
file: () => handleExistingRulesFile(rulesPath, templatePath, options),
|
|
3801
|
-
other: () => handleInvalidRulesPath(),
|
|
3802
|
-
none: () => handleFreshRulesInstall(rulesPath, templatePath)
|
|
3803
|
-
};
|
|
3804
|
-
await handlers[pathType]();
|
|
3805
|
-
}
|
|
3806
|
-
async function promptAndInstallCursorRules(rootDir, options) {
|
|
3807
|
-
const shouldInstall = options.yes || (await inquirer.prompt([{
|
|
3808
|
-
type: "confirm",
|
|
3809
|
-
name: "installCursorRules",
|
|
3810
|
-
message: "Install recommended Cursor rules?",
|
|
3811
|
-
default: true
|
|
3812
|
-
}])).installCursorRules;
|
|
3813
|
-
if (!shouldInstall) return;
|
|
3814
|
-
try {
|
|
3815
|
-
await installCursorRulesFiles(rootDir, options);
|
|
3816
|
-
} catch (error) {
|
|
3817
|
-
console.log(chalk2.yellow("\u26A0\uFE0F Could not install Cursor rules"));
|
|
3818
|
-
console.log(chalk2.dim(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
3819
|
-
console.log(chalk2.dim("You can manually copy CURSOR_RULES_TEMPLATE.md to .cursor/rules/lien.mdc"));
|
|
3820
|
-
}
|
|
3821
3694
|
}
|
|
3822
3695
|
|
|
3823
3696
|
// src/cli/status.ts
|
|
@@ -4119,7 +3992,7 @@ import path4 from "path";
|
|
|
4119
3992
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4120
3993
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4121
3994
|
import { createRequire as createRequire2 } from "module";
|
|
4122
|
-
import { fileURLToPath as
|
|
3995
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4123
3996
|
import { dirname as dirname2, join as join2 } from "path";
|
|
4124
3997
|
import {
|
|
4125
3998
|
LocalEmbeddings,
|
|
@@ -8419,11 +8292,17 @@ var SemanticSearchSchema = external_exports.object({
|
|
|
8419
8292
|
|
|
8420
8293
|
// src/mcp/schemas/similarity.schema.ts
|
|
8421
8294
|
var FindSimilarSchema = external_exports.object({
|
|
8422
|
-
code: external_exports.string().min(
|
|
8295
|
+
code: external_exports.string().min(24, "Code snippet must be at least 24 characters").describe(
|
|
8423
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."
|
|
8424
8297
|
),
|
|
8425
8298
|
limit: external_exports.number().int().min(1, "Limit must be at least 1").max(20, "Limit cannot exceed 20").default(5).describe(
|
|
8426
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'"
|
|
8427
8306
|
)
|
|
8428
8307
|
});
|
|
8429
8308
|
|
|
@@ -8487,7 +8366,7 @@ var tools = [
|
|
|
8487
8366
|
toMCPToolSchema(
|
|
8488
8367
|
SemanticSearchSchema,
|
|
8489
8368
|
"semantic_search",
|
|
8490
|
-
`Search codebase by MEANING, not text.
|
|
8369
|
+
`Search codebase by MEANING, not text. Complements grep - use this for discovery and understanding, grep for exact matches.
|
|
8491
8370
|
|
|
8492
8371
|
Examples:
|
|
8493
8372
|
- "Where is authentication handled?" \u2192 semantic_search({ query: "handles user authentication" })
|
|
@@ -8505,7 +8384,13 @@ Results include a relevance category (highly_relevant, relevant, loosely_related
|
|
|
8505
8384
|
- Finding duplicate implementations
|
|
8506
8385
|
- Refactoring similar patterns together
|
|
8507
8386
|
|
|
8508
|
-
Provide at least
|
|
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.`
|
|
8509
8394
|
),
|
|
8510
8395
|
toMCPToolSchema(
|
|
8511
8396
|
GetFilesContextSchema,
|
|
@@ -8703,6 +8588,19 @@ async function handleSemanticSearch(args, ctx) {
|
|
|
8703
8588
|
}
|
|
8704
8589
|
|
|
8705
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
|
+
}
|
|
8706
8604
|
async function handleFindSimilar(args, ctx) {
|
|
8707
8605
|
const { vectorDB, embeddings, log, checkAndReconnect, getIndexMetadata } = ctx;
|
|
8708
8606
|
return await wrapToolHandler(
|
|
@@ -8711,11 +8609,27 @@ async function handleFindSimilar(args, ctx) {
|
|
|
8711
8609
|
log(`Finding similar code...`);
|
|
8712
8610
|
await checkAndReconnect();
|
|
8713
8611
|
const codeEmbedding = await embeddings.embed(validatedArgs.code);
|
|
8714
|
-
const
|
|
8715
|
-
|
|
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;
|
|
8716
8629
|
return {
|
|
8717
8630
|
indexInfo: getIndexMetadata(),
|
|
8718
|
-
results
|
|
8631
|
+
results: finalResults,
|
|
8632
|
+
...hasFilters && { filtersApplied }
|
|
8719
8633
|
};
|
|
8720
8634
|
}
|
|
8721
8635
|
)(args);
|
|
@@ -8938,6 +8852,25 @@ async function handleGetFilesContext(args, ctx) {
|
|
|
8938
8852
|
}
|
|
8939
8853
|
|
|
8940
8854
|
// src/mcp/handlers/list-functions.ts
|
|
8855
|
+
async function performContentScan(vectorDB, args, log) {
|
|
8856
|
+
log("Falling back to content scan...");
|
|
8857
|
+
let results = await vectorDB.scanWithFilter({
|
|
8858
|
+
language: args.language,
|
|
8859
|
+
limit: 200
|
|
8860
|
+
// Fetch more, we'll filter by symbolName
|
|
8861
|
+
});
|
|
8862
|
+
if (args.pattern) {
|
|
8863
|
+
const regex = new RegExp(args.pattern, "i");
|
|
8864
|
+
results = results.filter((r) => {
|
|
8865
|
+
const symbolName = r.metadata?.symbolName;
|
|
8866
|
+
return symbolName && regex.test(symbolName);
|
|
8867
|
+
});
|
|
8868
|
+
}
|
|
8869
|
+
return {
|
|
8870
|
+
results: results.slice(0, 50),
|
|
8871
|
+
method: "content"
|
|
8872
|
+
};
|
|
8873
|
+
}
|
|
8941
8874
|
async function handleListFunctions(args, ctx) {
|
|
8942
8875
|
const { vectorDB, log, checkAndReconnect, getIndexMetadata } = ctx;
|
|
8943
8876
|
return await wrapToolHandler(
|
|
@@ -8945,38 +8878,29 @@ async function handleListFunctions(args, ctx) {
|
|
|
8945
8878
|
async (validatedArgs) => {
|
|
8946
8879
|
log("Listing functions with symbol metadata...");
|
|
8947
8880
|
await checkAndReconnect();
|
|
8948
|
-
let
|
|
8949
|
-
let usedMethod = "symbols";
|
|
8881
|
+
let queryResult;
|
|
8950
8882
|
try {
|
|
8951
|
-
results = await vectorDB.querySymbols({
|
|
8883
|
+
const results = await vectorDB.querySymbols({
|
|
8952
8884
|
language: validatedArgs.language,
|
|
8953
8885
|
pattern: validatedArgs.pattern,
|
|
8954
8886
|
limit: 50
|
|
8955
8887
|
});
|
|
8956
8888
|
if (results.length === 0 && (validatedArgs.language || validatedArgs.pattern)) {
|
|
8957
8889
|
log("No symbol results, falling back to content scan...");
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
limit: 50
|
|
8962
|
-
});
|
|
8963
|
-
usedMethod = "content";
|
|
8890
|
+
queryResult = await performContentScan(vectorDB, validatedArgs, log);
|
|
8891
|
+
} else {
|
|
8892
|
+
queryResult = { results, method: "symbols" };
|
|
8964
8893
|
}
|
|
8965
8894
|
} catch (error) {
|
|
8966
|
-
log(`Symbol query failed
|
|
8967
|
-
|
|
8968
|
-
language: validatedArgs.language,
|
|
8969
|
-
pattern: validatedArgs.pattern,
|
|
8970
|
-
limit: 50
|
|
8971
|
-
});
|
|
8972
|
-
usedMethod = "content";
|
|
8895
|
+
log(`Symbol query failed: ${error}`);
|
|
8896
|
+
queryResult = await performContentScan(vectorDB, validatedArgs, log);
|
|
8973
8897
|
}
|
|
8974
|
-
log(`Found ${results.length} matches using ${
|
|
8898
|
+
log(`Found ${queryResult.results.length} matches using ${queryResult.method} method`);
|
|
8975
8899
|
return {
|
|
8976
8900
|
indexInfo: getIndexMetadata(),
|
|
8977
|
-
method:
|
|
8978
|
-
results,
|
|
8979
|
-
note:
|
|
8901
|
+
method: queryResult.method,
|
|
8902
|
+
results: queryResult.results,
|
|
8903
|
+
note: queryResult.method === "content" ? 'Using content search. Run "lien reindex" to enable faster symbol-based queries.' : void 0
|
|
8980
8904
|
};
|
|
8981
8905
|
}
|
|
8982
8906
|
)(args);
|
|
@@ -9377,14 +9301,14 @@ function registerMCPHandlers(server, toolContext, log) {
|
|
|
9377
9301
|
}
|
|
9378
9302
|
|
|
9379
9303
|
// src/mcp/server.ts
|
|
9380
|
-
var
|
|
9381
|
-
var
|
|
9304
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
9305
|
+
var __dirname2 = dirname2(__filename2);
|
|
9382
9306
|
var require3 = createRequire2(import.meta.url);
|
|
9383
9307
|
var packageJson2;
|
|
9384
9308
|
try {
|
|
9385
|
-
packageJson2 = require3(join2(
|
|
9309
|
+
packageJson2 = require3(join2(__dirname2, "../package.json"));
|
|
9386
9310
|
} catch {
|
|
9387
|
-
packageJson2 = require3(join2(
|
|
9311
|
+
packageJson2 = require3(join2(__dirname2, "../../package.json"));
|
|
9388
9312
|
}
|
|
9389
9313
|
async function initializeDatabase(rootDir, log) {
|
|
9390
9314
|
const embeddings = new LocalEmbeddings();
|
|
@@ -9719,14 +9643,14 @@ async function complexityCommand(options) {
|
|
|
9719
9643
|
}
|
|
9720
9644
|
|
|
9721
9645
|
// src/cli/index.ts
|
|
9722
|
-
var
|
|
9723
|
-
var
|
|
9646
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
9647
|
+
var __dirname3 = dirname3(__filename3);
|
|
9724
9648
|
var require4 = createRequire3(import.meta.url);
|
|
9725
9649
|
var packageJson3;
|
|
9726
9650
|
try {
|
|
9727
|
-
packageJson3 = require4(join3(
|
|
9651
|
+
packageJson3 = require4(join3(__dirname3, "../package.json"));
|
|
9728
9652
|
} catch {
|
|
9729
|
-
packageJson3 = require4(join3(
|
|
9653
|
+
packageJson3 = require4(join3(__dirname3, "../../package.json"));
|
|
9730
9654
|
}
|
|
9731
9655
|
var program = new Command();
|
|
9732
9656
|
program.name("lien").description("Local semantic code search for AI assistants via MCP").version(packageJson3.version);
|