bluera-knowledge 0.9.36 → 0.9.38
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/CHANGELOG.md +41 -0
- package/dist/{chunk-Z2KKVH45.js → chunk-36IFANFI.js} +2 -2
- package/dist/{chunk-WFNPNAAP.js → chunk-XJFV7AJW.js} +61 -30
- package/dist/chunk-XJFV7AJW.js.map +1 -0
- package/dist/{chunk-DC7CGSGT.js → chunk-ZAWIPEYX.js} +2 -2
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/workers/background-worker-cli.js +3 -2
- package/dist/workers/background-worker-cli.js.map +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/src/cli/commands/crawl.test.ts +1 -0
- package/src/cli/commands/crawl.ts +2 -0
- package/src/cli/commands/index-cmd.test.ts +1 -0
- package/src/db/lance.ts +15 -21
- package/src/services/index.service.test.ts +1 -0
- package/src/services/index.service.ts +2 -0
- package/src/services/search.service.test.ts +209 -0
- package/src/services/search.service.ts +77 -19
- package/src/workers/background-worker.test.ts +1 -0
- package/src/workers/background-worker.ts +2 -0
- package/tests/integration/search-quality.test.ts +5 -3
- package/dist/chunk-WFNPNAAP.js.map +0 -1
- /package/dist/{chunk-Z2KKVH45.js.map → chunk-36IFANFI.js.map} +0 -0
- /package/dist/{chunk-DC7CGSGT.js.map → chunk-ZAWIPEYX.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,47 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.9.38](https://github.com/blueraai/bluera-knowledge/compare/v0.9.32...v0.9.38) (2026-01-08)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **bridge:** kill Python process before nullifying to prevent zombie ([393dab3](https://github.com/blueraai/bluera-knowledge/commit/393dab3e45c75fd87c9ecfc1ca92e67b14526e79))
|
|
11
|
+
* **bridge:** mock kill() emits exit event & attach rejection handlers before stop ([d73c6ca](https://github.com/blueraai/bluera-knowledge/commit/d73c6ca6d640c3d15bd82756cabcda832f9ae245))
|
|
12
|
+
* **bridge:** stop() now waits for process to actually exit ([a92de41](https://github.com/blueraai/bluera-knowledge/commit/a92de41c89318fc106f996568ed88505352d5159))
|
|
13
|
+
* **cli:** ensure destroyServices runs before process.exit ([22e4267](https://github.com/blueraai/bluera-knowledge/commit/22e4267b7b9f698de3985a89b9c2b10759cfd49c))
|
|
14
|
+
* **code-unit:** brace counting now handles strings and comments ([1e857bb](https://github.com/blueraai/bluera-knowledge/commit/1e857bb297f357b97a6c067950e62495b3c8fc99))
|
|
15
|
+
* **code-unit:** support complex return types in signature extraction ([3bd2467](https://github.com/blueraai/bluera-knowledge/commit/3bd24675a67e73cc74a0c718f4b5a9e86cd826fb))
|
|
16
|
+
* **job:** validate PID before process.kill to prevent process group kill ([67c540f](https://github.com/blueraai/bluera-knowledge/commit/67c540fef6f2c55c5dca2c824104a91fe19aeff1))
|
|
17
|
+
* **search:** apply threshold filtering after score normalization ([1ebc78e](https://github.com/blueraai/bluera-knowledge/commit/1ebc78e0e688ffde0fdbaf049f17a35d129ef055))
|
|
18
|
+
* **search:** enable FTS-only search mode ([4a0f371](https://github.com/blueraai/bluera-knowledge/commit/4a0f371f0c42f80bf87e28ae0e609ac95986964d))
|
|
19
|
+
* **services:** fail fast on corrupted config/registry files ([030f63c](https://github.com/blueraai/bluera-knowledge/commit/030f63c10b0a30bddcd8e9b27b291ab0f53263f1))
|
|
20
|
+
* **tests:** increase timeout for exit code test in CI ([a362dcd](https://github.com/blueraai/bluera-knowledge/commit/a362dcdae32b0c19e757270e5009b0c1c5ead4e4))
|
|
21
|
+
* **tests:** increase timeout for flaky store delete test ([738fb49](https://github.com/blueraai/bluera-knowledge/commit/738fb4975653703d800dee802730dedfdf9e85ba))
|
|
22
|
+
* **watch:** clear pending timeouts on unwatch to prevent timer leak ([4dcafc1](https://github.com/blueraai/bluera-knowledge/commit/4dcafc14417442f6eeed0257cf185e04ae9de12b))
|
|
23
|
+
* **worker:** fail fast on PID file write error ([d92ce42](https://github.com/blueraai/bluera-knowledge/commit/d92ce42eff63cee3c97056ef019f5a52ef699edd))
|
|
24
|
+
* **worker:** prevent division by zero and improve cancellation handling ([b7b40ab](https://github.com/blueraai/bluera-knowledge/commit/b7b40ab950b7ad0fbbe84af243be3138b1072a72))
|
|
25
|
+
|
|
26
|
+
## [0.9.37](https://github.com/blueraai/bluera-knowledge/compare/v0.9.32...v0.9.37) (2026-01-08)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* **bridge:** kill Python process before nullifying to prevent zombie ([393dab3](https://github.com/blueraai/bluera-knowledge/commit/393dab3e45c75fd87c9ecfc1ca92e67b14526e79))
|
|
32
|
+
* **bridge:** mock kill() emits exit event & attach rejection handlers before stop ([d73c6ca](https://github.com/blueraai/bluera-knowledge/commit/d73c6ca6d640c3d15bd82756cabcda832f9ae245))
|
|
33
|
+
* **bridge:** stop() now waits for process to actually exit ([a92de41](https://github.com/blueraai/bluera-knowledge/commit/a92de41c89318fc106f996568ed88505352d5159))
|
|
34
|
+
* **cli:** ensure destroyServices runs before process.exit ([22e4267](https://github.com/blueraai/bluera-knowledge/commit/22e4267b7b9f698de3985a89b9c2b10759cfd49c))
|
|
35
|
+
* **code-unit:** brace counting now handles strings and comments ([1e857bb](https://github.com/blueraai/bluera-knowledge/commit/1e857bb297f357b97a6c067950e62495b3c8fc99))
|
|
36
|
+
* **code-unit:** support complex return types in signature extraction ([3bd2467](https://github.com/blueraai/bluera-knowledge/commit/3bd24675a67e73cc74a0c718f4b5a9e86cd826fb))
|
|
37
|
+
* **job:** validate PID before process.kill to prevent process group kill ([67c540f](https://github.com/blueraai/bluera-knowledge/commit/67c540fef6f2c55c5dca2c824104a91fe19aeff1))
|
|
38
|
+
* **search:** apply threshold filtering after score normalization ([1ebc78e](https://github.com/blueraai/bluera-knowledge/commit/1ebc78e0e688ffde0fdbaf049f17a35d129ef055))
|
|
39
|
+
* **services:** fail fast on corrupted config/registry files ([030f63c](https://github.com/blueraai/bluera-knowledge/commit/030f63c10b0a30bddcd8e9b27b291ab0f53263f1))
|
|
40
|
+
* **tests:** increase timeout for exit code test in CI ([a362dcd](https://github.com/blueraai/bluera-knowledge/commit/a362dcdae32b0c19e757270e5009b0c1c5ead4e4))
|
|
41
|
+
* **tests:** increase timeout for flaky store delete test ([738fb49](https://github.com/blueraai/bluera-knowledge/commit/738fb4975653703d800dee802730dedfdf9e85ba))
|
|
42
|
+
* **watch:** clear pending timeouts on unwatch to prevent timer leak ([4dcafc1](https://github.com/blueraai/bluera-knowledge/commit/4dcafc14417442f6eeed0257cf185e04ae9de12b))
|
|
43
|
+
* **worker:** fail fast on PID file write error ([d92ce42](https://github.com/blueraai/bluera-knowledge/commit/d92ce42eff63cee3c97056ef019f5a52ef699edd))
|
|
44
|
+
* **worker:** prevent division by zero and improve cancellation handling ([b7b40ab](https://github.com/blueraai/bluera-knowledge/commit/b7b40ab950b7ad0fbbe84af243be3138b1072a72))
|
|
45
|
+
|
|
5
46
|
## [0.9.36](https://github.com/blueraai/bluera-knowledge/compare/v0.9.32...v0.9.36) (2026-01-08)
|
|
6
47
|
|
|
7
48
|
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
createServices,
|
|
5
5
|
createStoreId,
|
|
6
6
|
summarizePayload
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XJFV7AJW.js";
|
|
8
8
|
|
|
9
9
|
// src/mcp/server.ts
|
|
10
10
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -1086,4 +1086,4 @@ export {
|
|
|
1086
1086
|
createMCPServer,
|
|
1087
1087
|
runMCPServer
|
|
1088
1088
|
};
|
|
1089
|
-
//# sourceMappingURL=chunk-
|
|
1089
|
+
//# sourceMappingURL=chunk-36IFANFI.js.map
|
|
@@ -2310,6 +2310,7 @@ var IndexService = class {
|
|
|
2310
2310
|
}
|
|
2311
2311
|
if (documents.length > 0) {
|
|
2312
2312
|
await this.lanceStore.addDocuments(store.id, documents);
|
|
2313
|
+
await this.lanceStore.createFtsIndex(store.id);
|
|
2313
2314
|
}
|
|
2314
2315
|
if (this.codeGraphService && sourceFiles.length > 0) {
|
|
2315
2316
|
const graph = await this.codeGraphService.buildGraph(sourceFiles);
|
|
@@ -2839,6 +2840,33 @@ var SearchService = class {
|
|
|
2839
2840
|
const lowerContent = content.toLowerCase();
|
|
2840
2841
|
return queryTerms.filter((term) => lowerContent.includes(term)).length;
|
|
2841
2842
|
}
|
|
2843
|
+
/**
|
|
2844
|
+
* Normalize scores to 0-1 range and optionally filter by threshold.
|
|
2845
|
+
* This ensures threshold values match displayed scores (UX consistency).
|
|
2846
|
+
*
|
|
2847
|
+
* Edge case handling:
|
|
2848
|
+
* - If there's only 1 result or all results have the same score, normalization
|
|
2849
|
+
* would make them all 1.0. In this case, we keep the raw scores to allow
|
|
2850
|
+
* threshold filtering to work meaningfully on absolute quality.
|
|
2851
|
+
*/
|
|
2852
|
+
normalizeAndFilterScores(results, threshold) {
|
|
2853
|
+
if (results.length === 0) return [];
|
|
2854
|
+
const sorted = [...results].sort((a, b) => b.score - a.score);
|
|
2855
|
+
const first = sorted[0];
|
|
2856
|
+
const last = sorted[sorted.length - 1];
|
|
2857
|
+
if (first === void 0 || last === void 0) return [];
|
|
2858
|
+
const maxScore = first.score;
|
|
2859
|
+
const minScore = last.score;
|
|
2860
|
+
const range = maxScore - minScore;
|
|
2861
|
+
const normalized = range > 0 ? sorted.map((r) => ({
|
|
2862
|
+
...r,
|
|
2863
|
+
score: Math.round((r.score - minScore) / range * 1e6) / 1e6
|
|
2864
|
+
})) : sorted;
|
|
2865
|
+
if (threshold !== void 0) {
|
|
2866
|
+
return normalized.filter((r) => r.score >= threshold);
|
|
2867
|
+
}
|
|
2868
|
+
return normalized;
|
|
2869
|
+
}
|
|
2842
2870
|
async vectorSearch(query, stores, limit, threshold) {
|
|
2843
2871
|
const queryVector = await this.embeddingEngine.embed(query);
|
|
2844
2872
|
const results = [];
|
|
@@ -2853,7 +2881,8 @@ var SearchService = class {
|
|
|
2853
2881
|
}))
|
|
2854
2882
|
);
|
|
2855
2883
|
}
|
|
2856
|
-
|
|
2884
|
+
const normalized = this.normalizeAndFilterScores(results, threshold);
|
|
2885
|
+
return normalized.slice(0, limit);
|
|
2857
2886
|
}
|
|
2858
2887
|
async ftsSearch(query, stores, limit) {
|
|
2859
2888
|
const results = [];
|
|
@@ -2873,7 +2902,7 @@ var SearchService = class {
|
|
|
2873
2902
|
async hybridSearch(query, stores, limit, threshold) {
|
|
2874
2903
|
const intents = classifyQueryIntents(query);
|
|
2875
2904
|
const [vectorResults, ftsResults] = await Promise.all([
|
|
2876
|
-
this.vectorSearch(query, stores, limit * 2
|
|
2905
|
+
this.vectorSearch(query, stores, limit * 2),
|
|
2877
2906
|
this.ftsSearch(query, stores, limit * 2)
|
|
2878
2907
|
]);
|
|
2879
2908
|
const vectorRanks = /* @__PURE__ */ new Map();
|
|
@@ -2927,32 +2956,41 @@ var SearchService = class {
|
|
|
2927
2956
|
});
|
|
2928
2957
|
}
|
|
2929
2958
|
const sorted = rrfScores.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
2959
|
+
let normalizedResults;
|
|
2930
2960
|
if (sorted.length > 0) {
|
|
2931
2961
|
const first = sorted[0];
|
|
2932
2962
|
const last = sorted[sorted.length - 1];
|
|
2933
2963
|
if (first === void 0 || last === void 0) {
|
|
2934
|
-
|
|
2964
|
+
normalizedResults = sorted.map((r) => ({
|
|
2935
2965
|
...r.result,
|
|
2936
2966
|
score: r.score,
|
|
2937
2967
|
rankingMetadata: r.metadata
|
|
2938
2968
|
}));
|
|
2969
|
+
} else {
|
|
2970
|
+
const maxScore = first.score;
|
|
2971
|
+
const minScore = last.score;
|
|
2972
|
+
const range = maxScore - minScore;
|
|
2973
|
+
if (range > 0) {
|
|
2974
|
+
normalizedResults = sorted.map((r) => ({
|
|
2975
|
+
...r.result,
|
|
2976
|
+
score: Math.round((r.score - minScore) / range * 1e6) / 1e6,
|
|
2977
|
+
rankingMetadata: r.metadata
|
|
2978
|
+
}));
|
|
2979
|
+
} else {
|
|
2980
|
+
normalizedResults = sorted.map((r) => ({
|
|
2981
|
+
...r.result,
|
|
2982
|
+
score: r.score,
|
|
2983
|
+
rankingMetadata: r.metadata
|
|
2984
|
+
}));
|
|
2985
|
+
}
|
|
2939
2986
|
}
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
const range = maxScore - minScore;
|
|
2943
|
-
if (range > 0) {
|
|
2944
|
-
return sorted.map((r) => ({
|
|
2945
|
-
...r.result,
|
|
2946
|
-
score: (r.score - minScore) / range,
|
|
2947
|
-
rankingMetadata: r.metadata
|
|
2948
|
-
}));
|
|
2949
|
-
}
|
|
2987
|
+
} else {
|
|
2988
|
+
normalizedResults = [];
|
|
2950
2989
|
}
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
}));
|
|
2990
|
+
if (threshold !== void 0) {
|
|
2991
|
+
return normalizedResults.filter((r) => r.score >= threshold);
|
|
2992
|
+
}
|
|
2993
|
+
return normalizedResults;
|
|
2956
2994
|
}
|
|
2957
2995
|
async searchAllStores(query, storeIds) {
|
|
2958
2996
|
return this.search({
|
|
@@ -4016,18 +4054,11 @@ var LanceStore = class {
|
|
|
4016
4054
|
const idList = documentIds.map((id) => `"${id}"`).join(", ");
|
|
4017
4055
|
await table.delete(`id IN (${idList})`);
|
|
4018
4056
|
}
|
|
4019
|
-
async search(storeId, vector, limit,
|
|
4057
|
+
async search(storeId, vector, limit, _threshold) {
|
|
4020
4058
|
const table = await this.getTable(storeId);
|
|
4021
|
-
|
|
4022
|
-
if (threshold !== void 0) {
|
|
4023
|
-
query = query.distanceType("cosine");
|
|
4024
|
-
}
|
|
4059
|
+
const query = table.vectorSearch(vector).limit(limit).distanceType("cosine");
|
|
4025
4060
|
const results = await query.toArray();
|
|
4026
|
-
return results.
|
|
4027
|
-
if (threshold === void 0) return true;
|
|
4028
|
-
const score = 1 - r._distance;
|
|
4029
|
-
return score >= threshold;
|
|
4030
|
-
}).map((r) => ({
|
|
4061
|
+
return results.map((r) => ({
|
|
4031
4062
|
id: createDocumentId(r.id),
|
|
4032
4063
|
content: r.content,
|
|
4033
4064
|
score: 1 - r._distance,
|
|
@@ -4048,7 +4079,7 @@ var LanceStore = class {
|
|
|
4048
4079
|
return results.map((r) => ({
|
|
4049
4080
|
id: createDocumentId(r.id),
|
|
4050
4081
|
content: r.content,
|
|
4051
|
-
score: r.
|
|
4082
|
+
score: r._score,
|
|
4052
4083
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
4053
4084
|
metadata: JSON.parse(r.metadata)
|
|
4054
4085
|
}));
|
|
@@ -4160,4 +4191,4 @@ export {
|
|
|
4160
4191
|
createServices,
|
|
4161
4192
|
destroyServices
|
|
4162
4193
|
};
|
|
4163
|
-
//# sourceMappingURL=chunk-
|
|
4194
|
+
//# sourceMappingURL=chunk-XJFV7AJW.js.map
|