@liendev/lien 0.28.0 → 0.29.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/dist/index.js +131 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8475,7 +8475,7 @@ var NEVER = INVALID;
|
|
|
8475
8475
|
// src/mcp/schemas/search.schema.ts
|
|
8476
8476
|
var SemanticSearchSchema = external_exports.object({
|
|
8477
8477
|
query: external_exports.string().min(3, "Query must be at least 3 characters").max(500, "Query too long (max 500 characters)").describe(
|
|
8478
|
-
"Natural language description of what you're looking for.\n\nUse full sentences describing functionality, not exact names.\n\nGood examples:\n - '
|
|
8478
|
+
"Natural language description of what you're looking for.\n\nUse full sentences describing functionality, not exact names.\n\nGood examples:\n - 'How does the code handle user authentication?'\n - 'Where are email addresses validated?'\n - 'How are payment transactions processed?'\n\nBad examples:\n - 'auth' (too vague)\n - 'validateEmail' (use grep for exact names)"
|
|
8479
8479
|
),
|
|
8480
8480
|
limit: external_exports.number().int().min(1, "Limit must be at least 1").max(50, "Limit cannot exceed 50").default(5).describe(
|
|
8481
8481
|
"Number of results to return.\n\nDefault: 5\nIncrease to 10-15 for broad exploration."
|
|
@@ -8570,8 +8570,10 @@ var tools = [
|
|
|
8570
8570
|
`Search codebase by MEANING, not text. Complements grep - use this for discovery and understanding, grep for exact matches.
|
|
8571
8571
|
|
|
8572
8572
|
Examples:
|
|
8573
|
-
- "Where is authentication handled?" \u2192 semantic_search({ query: "
|
|
8574
|
-
- "How does payment work?" \u2192 semantic_search({ query: "
|
|
8573
|
+
- "Where is authentication handled?" \u2192 semantic_search({ query: "How does the code handle user authentication?" })
|
|
8574
|
+
- "How does payment work?" \u2192 semantic_search({ query: "How are payment transactions processed and validated?" })
|
|
8575
|
+
|
|
8576
|
+
IMPORTANT: Phrase queries as full questions starting with "How", "Where", "What", etc. Full questions produce significantly better relevance than keyword phrases.
|
|
8575
8577
|
|
|
8576
8578
|
Use natural language describing what the code DOES, not function names. For exact string matching, use grep instead.
|
|
8577
8579
|
|
|
@@ -8743,6 +8745,91 @@ function wrapToolHandler(schema, handler) {
|
|
|
8743
8745
|
};
|
|
8744
8746
|
}
|
|
8745
8747
|
|
|
8748
|
+
// src/mcp/utils/metadata-shaper.ts
|
|
8749
|
+
var FIELD_ALLOWLISTS = {
|
|
8750
|
+
semantic_search: /* @__PURE__ */ new Set([
|
|
8751
|
+
"language",
|
|
8752
|
+
"type",
|
|
8753
|
+
"symbolName",
|
|
8754
|
+
"symbolType",
|
|
8755
|
+
"signature",
|
|
8756
|
+
"parentClass",
|
|
8757
|
+
"parameters",
|
|
8758
|
+
"exports",
|
|
8759
|
+
"repoId"
|
|
8760
|
+
]),
|
|
8761
|
+
find_similar: /* @__PURE__ */ new Set([
|
|
8762
|
+
"language",
|
|
8763
|
+
"type",
|
|
8764
|
+
"symbolName",
|
|
8765
|
+
"symbolType",
|
|
8766
|
+
"signature",
|
|
8767
|
+
"parentClass",
|
|
8768
|
+
"parameters",
|
|
8769
|
+
"exports"
|
|
8770
|
+
]),
|
|
8771
|
+
get_files_context: /* @__PURE__ */ new Set([
|
|
8772
|
+
"language",
|
|
8773
|
+
"type",
|
|
8774
|
+
"symbolName",
|
|
8775
|
+
"symbolType",
|
|
8776
|
+
"signature",
|
|
8777
|
+
"parentClass",
|
|
8778
|
+
"parameters",
|
|
8779
|
+
"exports",
|
|
8780
|
+
"imports",
|
|
8781
|
+
"importedSymbols",
|
|
8782
|
+
"callSites",
|
|
8783
|
+
"symbols"
|
|
8784
|
+
]),
|
|
8785
|
+
list_functions: /* @__PURE__ */ new Set([
|
|
8786
|
+
"language",
|
|
8787
|
+
"type",
|
|
8788
|
+
"symbolName",
|
|
8789
|
+
"symbolType",
|
|
8790
|
+
"signature",
|
|
8791
|
+
"parentClass",
|
|
8792
|
+
"parameters",
|
|
8793
|
+
"exports",
|
|
8794
|
+
"symbols"
|
|
8795
|
+
])
|
|
8796
|
+
};
|
|
8797
|
+
function deduplicateResults(results) {
|
|
8798
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8799
|
+
return results.filter((r) => {
|
|
8800
|
+
const key = JSON.stringify([r.metadata.repoId ?? "", r.metadata.file, r.metadata.startLine, r.metadata.endLine]);
|
|
8801
|
+
if (seen.has(key)) return false;
|
|
8802
|
+
seen.add(key);
|
|
8803
|
+
return true;
|
|
8804
|
+
});
|
|
8805
|
+
}
|
|
8806
|
+
function pickMetadata(metadata, allowlist) {
|
|
8807
|
+
const result = {
|
|
8808
|
+
file: metadata.file,
|
|
8809
|
+
startLine: metadata.startLine,
|
|
8810
|
+
endLine: metadata.endLine
|
|
8811
|
+
};
|
|
8812
|
+
const out = result;
|
|
8813
|
+
for (const key of allowlist) {
|
|
8814
|
+
if (key === "file" || key === "startLine" || key === "endLine") continue;
|
|
8815
|
+
if (metadata[key] !== void 0) {
|
|
8816
|
+
out[key] = metadata[key];
|
|
8817
|
+
}
|
|
8818
|
+
}
|
|
8819
|
+
return result;
|
|
8820
|
+
}
|
|
8821
|
+
function shapeResultMetadata(result, tool) {
|
|
8822
|
+
return {
|
|
8823
|
+
content: result.content,
|
|
8824
|
+
metadata: pickMetadata(result.metadata, FIELD_ALLOWLISTS[tool]),
|
|
8825
|
+
score: result.score,
|
|
8826
|
+
relevance: result.relevance
|
|
8827
|
+
};
|
|
8828
|
+
}
|
|
8829
|
+
function shapeResults(results, tool) {
|
|
8830
|
+
return results.map((r) => shapeResultMetadata(r, tool));
|
|
8831
|
+
}
|
|
8832
|
+
|
|
8746
8833
|
// src/mcp/handlers/semantic-search.ts
|
|
8747
8834
|
import { QdrantDB } from "@liendev/core";
|
|
8748
8835
|
function groupResultsByRepo(results) {
|
|
@@ -8778,15 +8865,31 @@ async function handleSemanticSearch(args, ctx) {
|
|
|
8778
8865
|
results = await vectorDB.search(queryEmbedding, limit, query);
|
|
8779
8866
|
log(`Found ${results.length} results`);
|
|
8780
8867
|
}
|
|
8868
|
+
results = deduplicateResults(results);
|
|
8869
|
+
const notes = [];
|
|
8870
|
+
if (crossRepoFallback) {
|
|
8871
|
+
notes.push("Cross-repo search requires Qdrant backend. Fell back to single-repo search.");
|
|
8872
|
+
}
|
|
8873
|
+
if (results.length > 0 && results.every((r) => r.relevance === "not_relevant")) {
|
|
8874
|
+
notes.push("No relevant matches found.");
|
|
8875
|
+
log("Returning 0 results (all not_relevant)");
|
|
8876
|
+
return {
|
|
8877
|
+
indexInfo: getIndexMetadata(),
|
|
8878
|
+
results: [],
|
|
8879
|
+
note: notes.join(" ")
|
|
8880
|
+
};
|
|
8881
|
+
}
|
|
8882
|
+
log(`Returning ${results.length} results`);
|
|
8883
|
+
const shaped = shapeResults(results, "semantic_search");
|
|
8781
8884
|
const response = {
|
|
8782
8885
|
indexInfo: getIndexMetadata(),
|
|
8783
|
-
results
|
|
8886
|
+
results: shaped
|
|
8784
8887
|
};
|
|
8785
8888
|
if (crossRepo && vectorDB instanceof QdrantDB) {
|
|
8786
|
-
response.groupedByRepo = groupResultsByRepo(
|
|
8889
|
+
response.groupedByRepo = groupResultsByRepo(shaped);
|
|
8787
8890
|
}
|
|
8788
|
-
if (
|
|
8789
|
-
response.note = "
|
|
8891
|
+
if (notes.length > 0) {
|
|
8892
|
+
response.note = notes.join(" ");
|
|
8790
8893
|
}
|
|
8791
8894
|
return response;
|
|
8792
8895
|
}
|
|
@@ -8818,6 +8921,12 @@ async function handleFindSimilar(args, ctx) {
|
|
|
8818
8921
|
const limit = validatedArgs.limit ?? 5;
|
|
8819
8922
|
const extraLimit = limit + 10;
|
|
8820
8923
|
let results = await vectorDB.search(codeEmbedding, extraLimit, validatedArgs.code);
|
|
8924
|
+
results = deduplicateResults(results);
|
|
8925
|
+
const inputCode = validatedArgs.code.trim();
|
|
8926
|
+
results = results.filter((r) => {
|
|
8927
|
+
if (r.score >= 0.1) return true;
|
|
8928
|
+
return r.content.trim() !== inputCode;
|
|
8929
|
+
});
|
|
8821
8930
|
const filtersApplied = { prunedLowRelevance: 0 };
|
|
8822
8931
|
if (validatedArgs.language) {
|
|
8823
8932
|
filtersApplied.language = validatedArgs.language;
|
|
@@ -8834,7 +8943,7 @@ async function handleFindSimilar(args, ctx) {
|
|
|
8834
8943
|
const hasFilters = filtersApplied.language || filtersApplied.pathHint || filtersApplied.prunedLowRelevance > 0;
|
|
8835
8944
|
return {
|
|
8836
8945
|
indexInfo: getIndexMetadata(),
|
|
8837
|
-
results: finalResults,
|
|
8946
|
+
results: shapeResults(finalResults, "find_similar"),
|
|
8838
8947
|
...hasFilters && { filtersApplied }
|
|
8839
8948
|
};
|
|
8840
8949
|
}
|
|
@@ -9042,18 +9151,26 @@ function buildScanLimitNote(hitScanLimit) {
|
|
|
9042
9151
|
return hitScanLimit ? "Scanned 10,000 chunks (limit reached). Test associations may be incomplete for large codebases." : void 0;
|
|
9043
9152
|
}
|
|
9044
9153
|
function buildSingleFileResponse(filepath, filesData, indexInfo, note) {
|
|
9154
|
+
const data = filesData[filepath];
|
|
9045
9155
|
return {
|
|
9046
9156
|
indexInfo,
|
|
9047
9157
|
file: filepath,
|
|
9048
|
-
chunks:
|
|
9049
|
-
testAssociations:
|
|
9158
|
+
chunks: shapeResults(data.chunks, "get_files_context"),
|
|
9159
|
+
testAssociations: data.testAssociations,
|
|
9050
9160
|
...note && { note }
|
|
9051
9161
|
};
|
|
9052
9162
|
}
|
|
9053
9163
|
function buildMultiFileResponse(filesData, indexInfo, note) {
|
|
9164
|
+
const shaped = {};
|
|
9165
|
+
for (const [filepath, data] of Object.entries(filesData)) {
|
|
9166
|
+
shaped[filepath] = {
|
|
9167
|
+
chunks: shapeResults(data.chunks, "get_files_context"),
|
|
9168
|
+
testAssociations: data.testAssociations
|
|
9169
|
+
};
|
|
9170
|
+
}
|
|
9054
9171
|
return {
|
|
9055
9172
|
indexInfo,
|
|
9056
|
-
files:
|
|
9173
|
+
files: shaped,
|
|
9057
9174
|
...note && { note }
|
|
9058
9175
|
};
|
|
9059
9176
|
}
|
|
@@ -9158,11 +9275,12 @@ async function handleListFunctions(args, ctx) {
|
|
|
9158
9275
|
log(`Symbol query failed: ${error}`);
|
|
9159
9276
|
queryResult = await performContentScan(vectorDB, validatedArgs, log);
|
|
9160
9277
|
}
|
|
9161
|
-
|
|
9278
|
+
const dedupedResults = deduplicateResults(queryResult.results);
|
|
9279
|
+
log(`Found ${dedupedResults.length} matches using ${queryResult.method} method`);
|
|
9162
9280
|
return {
|
|
9163
9281
|
indexInfo: getIndexMetadata(),
|
|
9164
9282
|
method: queryResult.method,
|
|
9165
|
-
results:
|
|
9283
|
+
results: shapeResults(dedupedResults, "list_functions"),
|
|
9166
9284
|
note: queryResult.method === "content" ? 'Using content search. Run "lien reindex" to enable faster symbol-based queries.' : void 0
|
|
9167
9285
|
};
|
|
9168
9286
|
}
|